diff --git a/Makefile b/Makefile index b705129a7bd06c45bc54b9774390ba6bc2e6d71d..87a014586eb8927f9ca8c93472e80c001cd6ab44 100644 --- a/Makefile +++ b/Makefile @@ -145,7 +145,7 @@ CC_tsan = clang CXX_tsan = clang++ LD_tsan = clang LDXX_tsan = clang++ -CPPFLAGS_tsan = -O0 -fsanitize=thread -fno-omit-frame-pointer -Wno-error=unused-command-line-argument +CPPFLAGS_tsan = -O0 -fsanitize=thread -fno-omit-frame-pointer -Wno-unused-command-line-argument LDFLAGS_tsan = -fsanitize=thread DEFINES_tsan = NDEBUG GRPC_TEST_SLOWDOWN_BUILD_FACTOR=10 @@ -155,7 +155,7 @@ CC_asan = clang CXX_asan = clang++ LD_asan = clang LDXX_asan = clang++ -CPPFLAGS_asan = -O0 -fsanitize=address -fno-omit-frame-pointer -Wno-error=unused-command-line-argument +CPPFLAGS_asan = -O0 -fsanitize=address -fno-omit-frame-pointer -Wno-unused-command-line-argument LDFLAGS_asan = -fsanitize=address DEFINES_asan = GRPC_TEST_SLOWDOWN_BUILD_FACTOR=3 @@ -165,7 +165,7 @@ CC_msan = clang CXX_msan = clang++-libc++ LD_msan = clang LDXX_msan = clang++-libc++ -CPPFLAGS_msan = -O0 -fsanitize=memory -fsanitize-memory-track-origins -fno-omit-frame-pointer -DGTEST_HAS_TR1_TUPLE=0 -DGTEST_USE_OWN_TR1_TUPLE=1 -Wno-error=unused-command-line-argument +CPPFLAGS_msan = -O0 -fsanitize=memory -fsanitize-memory-track-origins -fno-omit-frame-pointer -DGTEST_HAS_TR1_TUPLE=0 -DGTEST_USE_OWN_TR1_TUPLE=1 -Wno-unused-command-line-argument OPENSSL_CFLAGS_msan = -DPURIFY LDFLAGS_msan = -fsanitize=memory -DGTEST_HAS_TR1_TUPLE=0 -DGTEST_USE_OWN_TR1_TUPLE=1 DEFINES_msan = NDEBUG GRPC_TEST_SLOWDOWN_BUILD_FACTOR=4 @@ -176,7 +176,7 @@ CC_ubsan = clang CXX_ubsan = clang++ LD_ubsan = clang LDXX_ubsan = clang++ -CPPFLAGS_ubsan = -O1 -fsanitize=undefined -fno-omit-frame-pointer -Wno-error=unused-command-line-argument +CPPFLAGS_ubsan = -O1 -fsanitize=undefined -fno-omit-frame-pointer -Wno-unused-command-line-argument OPENSSL_CFLAGS_ubsan = -DPURIFY LDFLAGS_ubsan = -fsanitize=undefined DEFINES_ubsan = NDEBUG GRPC_TEST_SLOWDOWN_BUILD_FACTOR=3 diff --git a/examples/python/helloworld/README.md b/examples/python/helloworld/README.md index 8fde0d2315cfbe32e566e4835cf4e791aee48a26..070b9e8837690ec9354c8cbe1c027347551606b1 100644 --- a/examples/python/helloworld/README.md +++ b/examples/python/helloworld/README.md @@ -91,9 +91,6 @@ Which internally invokes the proto-compiler as: $ protoc -I ../../protos --python_out=. --grpc_out=. --plugin=protoc-gen-grpc=`which grpc_python_plugin` ../../protos/helloworld.proto ``` -Optionally, you can just skip the code generation step as the generated python module has already -been generated for you (helloworld_pb2.py). - ### The client Client-side code can be found in [greeter_client.py](greeter_client.py). diff --git a/examples/python/helloworld/greeter_client.py b/examples/python/helloworld/greeter_client.py old mode 100755 new mode 100644 index 370ce46770302ea7aa222e28a20d512768db0b8f..561b25bcb2e2651965dfa744cc0431bbde8bf891 --- a/examples/python/helloworld/greeter_client.py +++ b/examples/python/helloworld/greeter_client.py @@ -29,15 +29,18 @@ """The Python implementation of the GRPC helloworld.Greeter client.""" +from grpc.beta import implementations + import helloworld_pb2 _TIMEOUT_SECONDS = 10 def run(): - with helloworld_pb2.early_adopter_create_Greeter_stub('localhost', 50051) as stub: - response = stub.SayHello(helloworld_pb2.HelloRequest(name='you'), _TIMEOUT_SECONDS) - print "Greeter client received: " + response.message + channel = implementations.insecure_channel('localhost', 50051) + stub = helloworld_pb2.beta_create_Greeter_stub(channel) + response = stub.SayHello(helloworld_pb2.HelloRequest(name='you'), _TIMEOUT_SECONDS) + print "Greeter client received: " + response.message if __name__ == '__main__': diff --git a/examples/python/helloworld/greeter_server.py b/examples/python/helloworld/greeter_server.py index 81353666b10ffe022d86eb755b147dbb2064cdb8..1514d8f270bef2eca2e1aac16a367172b73daf35 100644 --- a/examples/python/helloworld/greeter_server.py +++ b/examples/python/helloworld/greeter_server.py @@ -36,15 +36,15 @@ import helloworld_pb2 _ONE_DAY_IN_SECONDS = 60 * 60 * 24 -class Greeter(helloworld_pb2.EarlyAdopterGreeterServicer): +class Greeter(helloworld_pb2.BetaGreeterServicer): def SayHello(self, request, context): return helloworld_pb2.HelloReply(message='Hello, %s!' % request.name) def serve(): - server = helloworld_pb2.early_adopter_create_Greeter_server( - Greeter(), 50051, None, None) + server = helloworld_pb2.beta_create_Greeter_server(Greeter()) + server.add_insecure_port('[::]:50051') server.start() try: while True: diff --git a/examples/python/route_guide/README.md b/examples/python/route_guide/README.md index 636e134964d69ec8837d7dd7ebaec6775c6b1ca4..cb1aa7d78ae34cda62b57f04a6f39e424dbaf4ed 100644 --- a/examples/python/route_guide/README.md +++ b/examples/python/route_guide/README.md @@ -29,7 +29,7 @@ Then change your current directory to `examples/python/route_guide`: $ cd examples/python/route_guide ``` -You also should have the relevant tools installed to generate the server and client interface code - if you don't already, follow the setup instructions in [the Python quick start guide](../python). +You also should have the relevant tools installed to generate the server and client interface code - if you don't already, follow the setup instructions in [the Python quick start guide](../helloworld). ## Defining the service @@ -99,12 +99,11 @@ $ protoc -I ../../protos --python_out=. --grpc_out=. --plugin=protoc-gen-grpc=`w Note that as we've already provided a version of the generated code in the example repository, running this command regenerates the appropriate file rather than creates a new one. The generated code file is called `route_guide_pb2.py` and contains: - classes for the messages defined in route_guide.proto - abstract classes for the service defined in route_guide.proto - - `EarlyAdopterRouteGuideServicer`, which defines the interface for implementations of the RouteGuide service - - `EarlyAdopterRouteGuideServer`, which may be started and stopped - - `EarlyAdopterRouteGuideStub`, which can be used by clients to invoke RouteGuide RPCs + - `BetaRouteGuideServicer`, which defines the interface for implementations of the RouteGuide service + - `BetaRouteGuideStub`, which can be used by clients to invoke RouteGuide RPCs - functions for application use - - `early_adopter_create_RouteGuide_server`, which creates a gRPC server given an `EarlyAdopterRouteGuideServicer` object - - `early_adopter_create_RouteGuide_stub`, which can be used by clients to create a stub object + - `beta_create_RouteGuide_server`, which creates a gRPC server given a `BetaRouteGuideServicer` object + - `beta_create_RouteGuide_stub`, which can be used by clients to create a stub object <a name="server"></a> ## Creating the server @@ -119,11 +118,11 @@ You can find the example `RouteGuide` server in [route_guide_server.py](route_gu ### Implementing RouteGuide -`route_guide_server.py` has a `RouteGuideServicer` class that implements the generated interface `route_guide_pb2.EarlyAdopterRouteGuideServicer`: +`route_guide_server.py` has a `RouteGuideServicer` class that implements the generated interface `route_guide_pb2.BetaRouteGuideServicer`: ```python # RouteGuideServicer provides an implementation of the methods of the RouteGuide service. -class RouteGuideServicer(route_guide_pb2.EarlyAdopterRouteGuideServicer): +class RouteGuideServicer(route_guide_pb2.BetaRouteGuideServicer): ``` `RouteGuideServicer` implements all the `RouteGuide` service methods. @@ -141,7 +140,7 @@ Let's look at the simplest type first, `GetFeature`, which just gets a `Point` f return feature ``` -The method is passed a `route_guide_pb2.Point` request for the RPC, and an `RpcContext` object that provides RPC-specific information such as timeout limits. It returns a `route_guide_pb2.Feature` response. +The method is passed a `route_guide_pb2.Point` request for the RPC, and a `ServicerContext` object that provides RPC-specific information such as timeout limits. It returns a `route_guide_pb2.Feature` response. #### Response-streaming RPC @@ -212,8 +211,8 @@ Once you have implemented all the `RouteGuide` methods, the next step is to star ```python def serve(): - server = route_guide_pb2.early_adopter_create_RouteGuide_server( - RouteGuideServicer(), 50051, None, None) + server = route_guide_pb2.beta_create_RouteGuide_server(RouteGuideServicer()) + server.add_insecure_port('[::]:50051') server.start() ``` @@ -228,17 +227,14 @@ You can see the complete example client code in [route_guide_client.py](route_gu To call service methods, we first need to create a *stub*. -We use the `early_adopter_create_RouteGuide_stub` function of the `route_guide_pb2` module, generated from our .proto. +We use the `beta_create_RouteGuide_stub` function of the `route_guide_pb2` module, generated from our .proto. ```python -stub = RouteGuide::Stub.new('localhost', 50051) +channel = implementations.insecure_channel('localhost', 50051) +stub = beta_create_RouteGuide_stub(channel) ``` -The returned object implements all the methods defined by the `EarlyAdopterRouteGuideStub` interface, and is also a [context manager](https://docs.python.org/2/library/stdtypes.html#typecontextmanager). All RPCs invoked on the stub must be invoked within the stub's context, so it is common for stubs to be created and used with a [with statement](https://docs.python.org/2/reference/compound_stmts.html#the-with-statement): - -```python -with route_guide_pb2.early_adopter_create_RouteGuide_stub('localhost', 50051) as stub: -``` +The returned object implements all the methods defined by the `BetaRouteGuideStub` interface. ### Calling service methods @@ -255,7 +251,7 @@ feature = stub.GetFeature(point, timeout_in_seconds) An asynchronous call to `GetFeature` is similar, but like calling a local method asynchronously in a thread pool: ```python -feature_future = stub.GetFeature.async(point, timeout_in_seconds) +feature_future = stub.GetFeature.future(point, timeout_in_seconds) feature = feature_future.result() ``` @@ -276,7 +272,7 @@ route_summary = stub.RecordRoute(point_sequence, timeout_in_seconds) ``` ```python -route_summary_future = stub.RecordRoute.async(point_sequence, timeout_in_seconds) +route_summary_future = stub.RecordRoute.future(point_sequence, timeout_in_seconds) route_summary = route_summary_future.result() ``` diff --git a/examples/python/route_guide/route_guide_client.py b/examples/python/route_guide/route_guide_client.py old mode 100755 new mode 100644 index 078231543e1b852f2e5f6c8a09ade564e743570a..b1dfad551dc78fb05d875e741e34458d6ddf4d95 --- a/examples/python/route_guide/route_guide_client.py +++ b/examples/python/route_guide/route_guide_client.py @@ -32,6 +32,8 @@ import random import time +from grpc.beta import implementations + import route_guide_pb2 import route_guide_resources @@ -115,15 +117,16 @@ def guide_route_chat(stub): def run(): - with route_guide_pb2.early_adopter_create_RouteGuide_stub('localhost', 50051) as stub: - print "-------------- GetFeature --------------" - guide_get_feature(stub) - print "-------------- ListFeatures --------------" - guide_list_features(stub) - print "-------------- RecordRoute --------------" - guide_record_route(stub) - print "-------------- RouteChat --------------" - guide_route_chat(stub) + channel = implementations.insecure_channel('localhost', 50051) + stub = route_guide_pb2.beta_create_RouteGuide_stub(channel) + print "-------------- GetFeature --------------" + guide_get_feature(stub) + print "-------------- ListFeatures --------------" + guide_list_features(stub) + print "-------------- RecordRoute --------------" + guide_record_route(stub) + print "-------------- RouteChat --------------" + guide_route_chat(stub) if __name__ == '__main__': diff --git a/examples/python/route_guide/route_guide_pb2.py b/examples/python/route_guide/route_guide_pb2.py index 2a4532bb75017f6c0f539bcd6eced792f4cee66e..d4d9f8dcd5dcbb01780b5962dc25c853d652d275 100644 --- a/examples/python/route_guide/route_guide_pb2.py +++ b/examples/python/route_guide/route_guide_pb2.py @@ -1,8 +1,6 @@ # Generated by the protocol buffer compiler. DO NOT EDIT! # source: route_guide.proto -import sys -_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1')) from google.protobuf import descriptor as _descriptor from google.protobuf import message as _message from google.protobuf import reflection as _reflection @@ -17,8 +15,9 @@ _sym_db = _symbol_database.Default() DESCRIPTOR = _descriptor.FileDescriptor( name='route_guide.proto', - package='', - serialized_pb=_b('\n\x11route_guide.proto\",\n\x05Point\x12\x10\n\x08latitude\x18\x01 \x01(\x05\x12\x11\n\tlongitude\x18\x02 \x01(\x05\"3\n\tRectangle\x12\x12\n\x02lo\x18\x01 \x01(\x0b\x32\x06.Point\x12\x12\n\x02hi\x18\x02 \x01(\x0b\x32\x06.Point\"1\n\x07\x46\x65\x61ture\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x18\n\x08location\x18\x02 \x01(\x0b\x32\x06.Point\"6\n\tRouteNote\x12\x18\n\x08location\x18\x01 \x01(\x0b\x32\x06.Point\x12\x0f\n\x07message\x18\x02 \x01(\t\"b\n\x0cRouteSummary\x12\x13\n\x0bpoint_count\x18\x01 \x01(\x05\x12\x15\n\rfeature_count\x18\x02 \x01(\x05\x12\x10\n\x08\x64istance\x18\x03 \x01(\x05\x12\x14\n\x0c\x65lapsed_time\x18\x04 \x01(\x05\x32\xad\x01\n\nRouteGuide\x12 \n\nGetFeature\x12\x06.Point\x1a\x08.Feature\"\x00\x12(\n\x0cListFeatures\x12\n.Rectangle\x1a\x08.Feature\"\x00\x30\x01\x12(\n\x0bRecordRoute\x12\x06.Point\x1a\r.RouteSummary\"\x00(\x01\x12)\n\tRouteChat\x12\n.RouteNote\x1a\n.RouteNote\"\x00(\x01\x30\x01') + package='routeguide', + syntax='proto3', + serialized_pb=b'\n\x11route_guide.proto\x12\nrouteguide\",\n\x05Point\x12\x10\n\x08latitude\x18\x01 \x01(\x05\x12\x11\n\tlongitude\x18\x02 \x01(\x05\"I\n\tRectangle\x12\x1d\n\x02lo\x18\x01 \x01(\x0b\x32\x11.routeguide.Point\x12\x1d\n\x02hi\x18\x02 \x01(\x0b\x32\x11.routeguide.Point\"<\n\x07\x46\x65\x61ture\x12\x0c\n\x04name\x18\x01 \x01(\t\x12#\n\x08location\x18\x02 \x01(\x0b\x32\x11.routeguide.Point\"A\n\tRouteNote\x12#\n\x08location\x18\x01 \x01(\x0b\x32\x11.routeguide.Point\x12\x0f\n\x07message\x18\x02 \x01(\t\"b\n\x0cRouteSummary\x12\x13\n\x0bpoint_count\x18\x01 \x01(\x05\x12\x15\n\rfeature_count\x18\x02 \x01(\x05\x12\x10\n\x08\x64istance\x18\x03 \x01(\x05\x12\x14\n\x0c\x65lapsed_time\x18\x04 \x01(\x05\x32\x85\x02\n\nRouteGuide\x12\x36\n\nGetFeature\x12\x11.routeguide.Point\x1a\x13.routeguide.Feature\"\x00\x12>\n\x0cListFeatures\x12\x15.routeguide.Rectangle\x1a\x13.routeguide.Feature\"\x00\x30\x01\x12>\n\x0bRecordRoute\x12\x11.routeguide.Point\x1a\x18.routeguide.RouteSummary\"\x00(\x01\x12?\n\tRouteChat\x12\x15.routeguide.RouteNote\x1a\x15.routeguide.RouteNote\"\x00(\x01\x30\x01\x42\x0f\n\x07\x65x.grpc\xa2\x02\x03RTGb\x06proto3' ) _sym_db.RegisterFileDescriptor(DESCRIPTOR) @@ -27,20 +26,20 @@ _sym_db.RegisterFileDescriptor(DESCRIPTOR) _POINT = _descriptor.Descriptor( name='Point', - full_name='Point', + full_name='routeguide.Point', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ _descriptor.FieldDescriptor( - name='latitude', full_name='Point.latitude', index=0, + name='latitude', full_name='routeguide.Point.latitude', index=0, number=1, type=5, cpp_type=1, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( - name='longitude', full_name='Point.longitude', index=1, + name='longitude', full_name='routeguide.Point.longitude', index=1, number=2, type=5, cpp_type=1, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, @@ -54,30 +53,31 @@ _POINT = _descriptor.Descriptor( ], options=None, is_extendable=False, + syntax='proto3', extension_ranges=[], oneofs=[ ], - serialized_start=21, - serialized_end=65, + serialized_start=33, + serialized_end=77, ) _RECTANGLE = _descriptor.Descriptor( name='Rectangle', - full_name='Rectangle', + full_name='routeguide.Rectangle', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ _descriptor.FieldDescriptor( - name='lo', full_name='Rectangle.lo', index=0, + name='lo', full_name='routeguide.Rectangle.lo', index=0, number=1, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( - name='hi', full_name='Rectangle.hi', index=1, + name='hi', full_name='routeguide.Rectangle.hi', index=1, number=2, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, @@ -91,30 +91,31 @@ _RECTANGLE = _descriptor.Descriptor( ], options=None, is_extendable=False, + syntax='proto3', extension_ranges=[], oneofs=[ ], - serialized_start=67, - serialized_end=118, + serialized_start=79, + serialized_end=152, ) _FEATURE = _descriptor.Descriptor( name='Feature', - full_name='Feature', + full_name='routeguide.Feature', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ _descriptor.FieldDescriptor( - name='name', full_name='Feature.name', index=0, + name='name', full_name='routeguide.Feature.name', index=0, number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( - name='location', full_name='Feature.location', index=1, + name='location', full_name='routeguide.Feature.location', index=1, number=2, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, @@ -128,32 +129,33 @@ _FEATURE = _descriptor.Descriptor( ], options=None, is_extendable=False, + syntax='proto3', extension_ranges=[], oneofs=[ ], - serialized_start=120, - serialized_end=169, + serialized_start=154, + serialized_end=214, ) _ROUTENOTE = _descriptor.Descriptor( name='RouteNote', - full_name='RouteNote', + full_name='routeguide.RouteNote', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ _descriptor.FieldDescriptor( - name='location', full_name='RouteNote.location', index=0, + name='location', full_name='routeguide.RouteNote.location', index=0, number=1, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( - name='message', full_name='RouteNote.message', index=1, + name='message', full_name='routeguide.RouteNote.message', index=1, number=2, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), @@ -165,44 +167,45 @@ _ROUTENOTE = _descriptor.Descriptor( ], options=None, is_extendable=False, + syntax='proto3', extension_ranges=[], oneofs=[ ], - serialized_start=171, - serialized_end=225, + serialized_start=216, + serialized_end=281, ) _ROUTESUMMARY = _descriptor.Descriptor( name='RouteSummary', - full_name='RouteSummary', + full_name='routeguide.RouteSummary', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ _descriptor.FieldDescriptor( - name='point_count', full_name='RouteSummary.point_count', index=0, + name='point_count', full_name='routeguide.RouteSummary.point_count', index=0, number=1, type=5, cpp_type=1, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( - name='feature_count', full_name='RouteSummary.feature_count', index=1, + name='feature_count', full_name='routeguide.RouteSummary.feature_count', index=1, number=2, type=5, cpp_type=1, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( - name='distance', full_name='RouteSummary.distance', index=2, + name='distance', full_name='routeguide.RouteSummary.distance', index=2, number=3, type=5, cpp_type=1, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None), _descriptor.FieldDescriptor( - name='elapsed_time', full_name='RouteSummary.elapsed_time', index=3, + name='elapsed_time', full_name='routeguide.RouteSummary.elapsed_time', index=3, number=4, type=5, cpp_type=1, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, @@ -216,11 +219,12 @@ _ROUTESUMMARY = _descriptor.Descriptor( ], options=None, is_extendable=False, + syntax='proto3', extension_ranges=[], oneofs=[ ], - serialized_start=227, - serialized_end=325, + serialized_start=283, + serialized_end=381, ) _RECTANGLE.fields_by_name['lo'].message_type = _POINT @@ -236,58 +240,61 @@ DESCRIPTOR.message_types_by_name['RouteSummary'] = _ROUTESUMMARY Point = _reflection.GeneratedProtocolMessageType('Point', (_message.Message,), dict( DESCRIPTOR = _POINT, __module__ = 'route_guide_pb2' - # @@protoc_insertion_point(class_scope:Point) + # @@protoc_insertion_point(class_scope:routeguide.Point) )) _sym_db.RegisterMessage(Point) Rectangle = _reflection.GeneratedProtocolMessageType('Rectangle', (_message.Message,), dict( DESCRIPTOR = _RECTANGLE, __module__ = 'route_guide_pb2' - # @@protoc_insertion_point(class_scope:Rectangle) + # @@protoc_insertion_point(class_scope:routeguide.Rectangle) )) _sym_db.RegisterMessage(Rectangle) Feature = _reflection.GeneratedProtocolMessageType('Feature', (_message.Message,), dict( DESCRIPTOR = _FEATURE, __module__ = 'route_guide_pb2' - # @@protoc_insertion_point(class_scope:Feature) + # @@protoc_insertion_point(class_scope:routeguide.Feature) )) _sym_db.RegisterMessage(Feature) RouteNote = _reflection.GeneratedProtocolMessageType('RouteNote', (_message.Message,), dict( DESCRIPTOR = _ROUTENOTE, __module__ = 'route_guide_pb2' - # @@protoc_insertion_point(class_scope:RouteNote) + # @@protoc_insertion_point(class_scope:routeguide.RouteNote) )) _sym_db.RegisterMessage(RouteNote) RouteSummary = _reflection.GeneratedProtocolMessageType('RouteSummary', (_message.Message,), dict( DESCRIPTOR = _ROUTESUMMARY, __module__ = 'route_guide_pb2' - # @@protoc_insertion_point(class_scope:RouteSummary) + # @@protoc_insertion_point(class_scope:routeguide.RouteSummary) )) _sym_db.RegisterMessage(RouteSummary) +DESCRIPTOR.has_options = True +DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), b'\n\007ex.grpc\242\002\003RTG') import abc -from grpc._adapter import fore -from grpc._adapter import rear -from grpc.framework.assembly import implementations -from grpc.framework.assembly import utilities +from grpc.beta import implementations as beta_implementations +from grpc.early_adopter import implementations as early_adopter_implementations +from grpc.framework.alpha import utilities as alpha_utilities +from grpc.framework.common import cardinality +from grpc.framework.interfaces.face import utilities as face_utilities class EarlyAdopterRouteGuideServicer(object): """<fill me in later!>""" __metaclass__ = abc.ABCMeta @abc.abstractmethod - def GetFeature(self, request): + def GetFeature(self, request, context): raise NotImplementedError() @abc.abstractmethod - def ListFeatures(self, request): + def ListFeatures(self, request, context): raise NotImplementedError() @abc.abstractmethod - def RecordRoute(self, request_iterator): + def RecordRoute(self, request_iterator, context): raise NotImplementedError() @abc.abstractmethod - def RouteChat(self, request_iterator): + def RouteChat(self, request_iterator, context): raise NotImplementedError() class EarlyAdopterRouteGuideServer(object): """<fill me in later!>""" @@ -317,54 +324,158 @@ class EarlyAdopterRouteGuideStub(object): def RouteChat(self, request_iterator): raise NotImplementedError() RouteChat.async = None -def early_adopter_create_RouteGuide_server(servicer, port, root_certificates, key_chain_pairs): - method_implementations = { - "GetFeature": utilities.unary_unary_inline(servicer.GetFeature), - "ListFeatures": utilities.unary_stream_inline(servicer.ListFeatures), - "RecordRoute": utilities.stream_unary_inline(servicer.RecordRoute), - "RouteChat": utilities.stream_stream_inline(servicer.RouteChat), +def early_adopter_create_RouteGuide_server(servicer, port, private_key=None, certificate_chain=None): + import route_guide_pb2 + import route_guide_pb2 + import route_guide_pb2 + import route_guide_pb2 + import route_guide_pb2 + import route_guide_pb2 + import route_guide_pb2 + import route_guide_pb2 + method_service_descriptions = { + "GetFeature": alpha_utilities.unary_unary_service_description( + servicer.GetFeature, + route_guide_pb2.Point.FromString, + route_guide_pb2.Feature.SerializeToString, + ), + "ListFeatures": alpha_utilities.unary_stream_service_description( + servicer.ListFeatures, + route_guide_pb2.Rectangle.FromString, + route_guide_pb2.Feature.SerializeToString, + ), + "RecordRoute": alpha_utilities.stream_unary_service_description( + servicer.RecordRoute, + route_guide_pb2.Point.FromString, + route_guide_pb2.RouteSummary.SerializeToString, + ), + "RouteChat": alpha_utilities.stream_stream_service_description( + servicer.RouteChat, + route_guide_pb2.RouteNote.FromString, + route_guide_pb2.RouteNote.SerializeToString, + ), + } + return early_adopter_implementations.server("routeguide.RouteGuide", method_service_descriptions, port, private_key=private_key, certificate_chain=certificate_chain) +def early_adopter_create_RouteGuide_stub(host, port, metadata_transformer=None, secure=False, root_certificates=None, private_key=None, certificate_chain=None, server_host_override=None): + import route_guide_pb2 + import route_guide_pb2 + import route_guide_pb2 + import route_guide_pb2 + import route_guide_pb2 + import route_guide_pb2 + import route_guide_pb2 + import route_guide_pb2 + method_invocation_descriptions = { + "GetFeature": alpha_utilities.unary_unary_invocation_description( + route_guide_pb2.Point.SerializeToString, + route_guide_pb2.Feature.FromString, + ), + "ListFeatures": alpha_utilities.unary_stream_invocation_description( + route_guide_pb2.Rectangle.SerializeToString, + route_guide_pb2.Feature.FromString, + ), + "RecordRoute": alpha_utilities.stream_unary_invocation_description( + route_guide_pb2.Point.SerializeToString, + route_guide_pb2.RouteSummary.FromString, + ), + "RouteChat": alpha_utilities.stream_stream_invocation_description( + route_guide_pb2.RouteNote.SerializeToString, + route_guide_pb2.RouteNote.FromString, + ), } + return early_adopter_implementations.stub("routeguide.RouteGuide", method_invocation_descriptions, host, port, metadata_transformer=metadata_transformer, secure=secure, root_certificates=root_certificates, private_key=private_key, certificate_chain=certificate_chain, server_host_override=server_host_override) + +class BetaRouteGuideServicer(object): + """<fill me in later!>""" + __metaclass__ = abc.ABCMeta + @abc.abstractmethod + def GetFeature(self, request, context): + raise NotImplementedError() + @abc.abstractmethod + def ListFeatures(self, request, context): + raise NotImplementedError() + @abc.abstractmethod + def RecordRoute(self, request_iterator, context): + raise NotImplementedError() + @abc.abstractmethod + def RouteChat(self, request_iterator, context): + raise NotImplementedError() + +class BetaRouteGuideStub(object): + """The interface to which stubs will conform.""" + __metaclass__ = abc.ABCMeta + @abc.abstractmethod + def GetFeature(self, request, timeout): + raise NotImplementedError() + GetFeature.future = None + @abc.abstractmethod + def ListFeatures(self, request, timeout): + raise NotImplementedError() + @abc.abstractmethod + def RecordRoute(self, request_iterator, timeout): + raise NotImplementedError() + RecordRoute.future = None + @abc.abstractmethod + def RouteChat(self, request_iterator, timeout): + raise NotImplementedError() + +def beta_create_RouteGuide_server(servicer, pool=None, pool_size=None, default_timeout=None, maximum_timeout=None): + import route_guide_pb2 + import route_guide_pb2 + import route_guide_pb2 + import route_guide_pb2 import route_guide_pb2 import route_guide_pb2 import route_guide_pb2 import route_guide_pb2 request_deserializers = { - "GetFeature": route_guide_pb2.Point.FromString, - "ListFeatures": route_guide_pb2.Rectangle.FromString, - "RecordRoute": route_guide_pb2.Point.FromString, - "RouteChat": route_guide_pb2.RouteNote.FromString, + ('routeguide.RouteGuide', 'GetFeature'): route_guide_pb2.Point.FromString, + ('routeguide.RouteGuide', 'ListFeatures'): route_guide_pb2.Rectangle.FromString, + ('routeguide.RouteGuide', 'RecordRoute'): route_guide_pb2.Point.FromString, + ('routeguide.RouteGuide', 'RouteChat'): route_guide_pb2.RouteNote.FromString, } response_serializers = { - "GetFeature": lambda x: x.SerializeToString(), - "ListFeatures": lambda x: x.SerializeToString(), - "RecordRoute": lambda x: x.SerializeToString(), - "RouteChat": lambda x: x.SerializeToString(), + ('routeguide.RouteGuide', 'GetFeature'): route_guide_pb2.Feature.SerializeToString, + ('routeguide.RouteGuide', 'ListFeatures'): route_guide_pb2.Feature.SerializeToString, + ('routeguide.RouteGuide', 'RecordRoute'): route_guide_pb2.RouteSummary.SerializeToString, + ('routeguide.RouteGuide', 'RouteChat'): route_guide_pb2.RouteNote.SerializeToString, } - link = fore.activated_fore_link(port, request_deserializers, response_serializers, root_certificates, key_chain_pairs) - return implementations.assemble_service(method_implementations, link) -def early_adopter_create_RouteGuide_stub(host, port): method_implementations = { - "GetFeature": utilities.unary_unary_inline(None), - "ListFeatures": utilities.unary_stream_inline(None), - "RecordRoute": utilities.stream_unary_inline(None), - "RouteChat": utilities.stream_stream_inline(None), + ('routeguide.RouteGuide', 'GetFeature'): face_utilities.unary_unary_inline(servicer.GetFeature), + ('routeguide.RouteGuide', 'ListFeatures'): face_utilities.unary_stream_inline(servicer.ListFeatures), + ('routeguide.RouteGuide', 'RecordRoute'): face_utilities.stream_unary_inline(servicer.RecordRoute), + ('routeguide.RouteGuide', 'RouteChat'): face_utilities.stream_stream_inline(servicer.RouteChat), } + server_options = beta_implementations.server_options(request_deserializers=request_deserializers, response_serializers=response_serializers, thread_pool=pool, thread_pool_size=pool_size, default_timeout=default_timeout, maximum_timeout=maximum_timeout) + return beta_implementations.server(method_implementations, options=server_options) + +def beta_create_RouteGuide_stub(channel, host=None, metadata_transformer=None, pool=None, pool_size=None): import route_guide_pb2 import route_guide_pb2 import route_guide_pb2 import route_guide_pb2 + import route_guide_pb2 + import route_guide_pb2 + import route_guide_pb2 + import route_guide_pb2 + request_serializers = { + ('routeguide.RouteGuide', 'GetFeature'): route_guide_pb2.Point.SerializeToString, + ('routeguide.RouteGuide', 'ListFeatures'): route_guide_pb2.Rectangle.SerializeToString, + ('routeguide.RouteGuide', 'RecordRoute'): route_guide_pb2.Point.SerializeToString, + ('routeguide.RouteGuide', 'RouteChat'): route_guide_pb2.RouteNote.SerializeToString, + } response_deserializers = { - "GetFeature": route_guide_pb2.Feature.FromString, - "ListFeatures": route_guide_pb2.Feature.FromString, - "RecordRoute": route_guide_pb2.RouteSummary.FromString, - "RouteChat": route_guide_pb2.RouteNote.FromString, + ('routeguide.RouteGuide', 'GetFeature'): route_guide_pb2.Feature.FromString, + ('routeguide.RouteGuide', 'ListFeatures'): route_guide_pb2.Feature.FromString, + ('routeguide.RouteGuide', 'RecordRoute'): route_guide_pb2.RouteSummary.FromString, + ('routeguide.RouteGuide', 'RouteChat'): route_guide_pb2.RouteNote.FromString, } - request_serializers = { - "GetFeature": lambda x: x.SerializeToString(), - "ListFeatures": lambda x: x.SerializeToString(), - "RecordRoute": lambda x: x.SerializeToString(), - "RouteChat": lambda x: x.SerializeToString(), + cardinalities = { + 'GetFeature': cardinality.Cardinality.UNARY_UNARY, + 'ListFeatures': cardinality.Cardinality.UNARY_STREAM, + 'RecordRoute': cardinality.Cardinality.STREAM_UNARY, + 'RouteChat': cardinality.Cardinality.STREAM_STREAM, } - link = rear.activated_rear_link(host, port, request_serializers, response_deserializers) - return implementations.assemble_dynamic_inline_stub(method_implementations, link) + stub_options = beta_implementations.stub_options(host=host, metadata_transformer=metadata_transformer, request_serializers=request_serializers, response_deserializers=response_deserializers, thread_pool=pool, thread_pool_size=pool_size) + return beta_implementations.dynamic_stub(channel, 'routeguide.RouteGuide', cardinalities, options=stub_options) # @@protoc_insertion_point(module_scope) diff --git a/examples/python/route_guide/route_guide_server.py b/examples/python/route_guide/route_guide_server.py index 44bbacf5f321db19a3bad1fd00423954f01cc6b8..f23b98bf3673c191f2641f05e9adcaf7f127e228 100644 --- a/examples/python/route_guide/route_guide_server.py +++ b/examples/python/route_guide/route_guide_server.py @@ -65,7 +65,7 @@ def get_distance(start, end): R = 6371000; # metres return R * c; -class RouteGuideServicer(route_guide_pb2.EarlyAdopterRouteGuideServicer): +class RouteGuideServicer(route_guide_pb2.BetaRouteGuideServicer): """Provides methods that implement functionality of route guide server.""" def __init__(self): @@ -121,8 +121,8 @@ class RouteGuideServicer(route_guide_pb2.EarlyAdopterRouteGuideServicer): def serve(): - server = route_guide_pb2.early_adopter_create_RouteGuide_server( - RouteGuideServicer(), 50051, None, None) + server = route_guide_pb2.beta_create_RouteGuide_server(RouteGuideServicer()) + server.add_insecure_port('[::]:50051') server.start() try: while True: diff --git a/examples/python/route_guide/run_codegen.sh b/examples/python/route_guide/run_codegen.sh index 689e0978de661355a11a57047044c0fd014ae805..a5759025b8d288ae376f5f3f70009c268d3b4133 100755 --- a/examples/python/route_guide/run_codegen.sh +++ b/examples/python/route_guide/run_codegen.sh @@ -1,4 +1,4 @@ #!/bin/bash # Runs the protoc with gRPC plugin to generate protocol messages and gRPC stubs. -protoc -I . --python_out=. --grpc_out=. --plugin=protoc-gen-grpc=`which grpc_python_plugin` route_guide.proto +protoc -I ../../protos --python_out=. --grpc_out=. --plugin=protoc-gen-grpc=`which grpc_python_plugin` ../../protos/route_guide.proto diff --git a/include/grpc++/server.h b/include/grpc++/server.h index 18a8017880c0948bd0f83d213614c109c4da9b1f..210fe020ad10b5bdc2e2a35e558cc398a8cbecd1 100644 --- a/include/grpc++/server.h +++ b/include/grpc++/server.h @@ -37,6 +37,7 @@ #include <list> #include <memory> +#include <grpc/compression.h> #include <grpc++/completion_queue.h> #include <grpc++/impl/call.h> #include <grpc++/impl/grpc_library.h> @@ -99,7 +100,7 @@ class Server GRPC_FINAL : public GrpcLibrary, private CallHook { /// \param max_message_size Maximum message length that the channel can /// receive. Server(ThreadPoolInterface* thread_pool, bool thread_pool_owned, - int max_message_size); + int max_message_size, grpc_compression_options compression_options); /// Register a service. This call does not take ownership of the service. /// The service must exist for the lifetime of the Server instance. diff --git a/include/grpc++/server_builder.h b/include/grpc++/server_builder.h index 496e7862c5386afe5a142a1521df86e257e764d6..05937f150bde97e92891bccbf2631eb26560615e 100644 --- a/include/grpc++/server_builder.h +++ b/include/grpc++/server_builder.h @@ -37,6 +37,7 @@ #include <memory> #include <vector> +#include <grpc/compression.h> #include <grpc++/support/config.h> namespace grpc { @@ -92,6 +93,11 @@ class ServerBuilder { max_message_size_ = max_message_size; } + /// Set the compression options to be used by the server. + void SetCompressionOptions(const grpc_compression_options& options) { + compression_options_ = options; + } + /// Tries to bind \a server to the given \a addr. /// /// It can be invoked multiple times. @@ -133,6 +139,7 @@ class ServerBuilder { }; int max_message_size_; + grpc_compression_options compression_options_; std::vector<std::unique_ptr<NamedService<RpcService>>> services_; std::vector<std::unique_ptr<NamedService<AsynchronousService>>> async_services_; diff --git a/src/core/channel/compress_filter.c b/src/core/channel/compress_filter.c index 17b48f31c18917b17c76e7d1cefff77bf0f87d93..7959603102c35b29c321dc02816180c94fc27629 100644 --- a/src/core/channel/compress_filter.c +++ b/src/core/channel/compress_filter.c @@ -71,6 +71,8 @@ typedef struct channel_data { grpc_mdelem *mdelem_accept_encoding; /** The default, channel-level, compression algorithm */ grpc_compression_algorithm default_compression_algorithm; + /** Compression options for the channel */ + grpc_compression_options compression_options; } channel_data; /** Compress \a slices in place using \a algorithm. Returns 1 if compression did @@ -103,7 +105,17 @@ static grpc_mdelem *compression_md_filter(void *user_data, grpc_mdelem *md) { const char *md_c_str = grpc_mdstr_as_c_string(md->value); if (!grpc_compression_algorithm_parse(md_c_str, strlen(md_c_str), &calld->compression_algorithm)) { - gpr_log(GPR_ERROR, "Invalid compression algorithm: '%s'. Ignoring.", + gpr_log(GPR_ERROR, + "Invalid compression algorithm: '%s' (unknown). Ignoring.", + md_c_str); + calld->compression_algorithm = GRPC_COMPRESS_NONE; + } + if (grpc_compression_options_is_algorithm_enabled( + &channeld->compression_options, calld->compression_algorithm) == + 0) { + gpr_log(GPR_ERROR, + "Invalid compression algorithm: '%s' (previously disabled). " + "Ignoring.", md_c_str); calld->compression_algorithm = GRPC_COMPRESS_NONE; } @@ -299,11 +311,21 @@ static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master, channel_data *channeld = elem->channel_data; grpc_compression_algorithm algo_idx; const char *supported_algorithms_names[GRPC_COMPRESS_ALGORITHMS_COUNT - 1]; + size_t supported_algorithms_idx = 0; char *accept_encoding_str; size_t accept_encoding_str_len; + grpc_compression_options_init(&channeld->compression_options); + channeld->compression_options.enabled_algorithms_bitset = + (gpr_uint32)grpc_channel_args_compression_algorithm_get_states(args); + channeld->default_compression_algorithm = grpc_channel_args_get_compression_algorithm(args); + /* Make sure the default isn't disabled. */ + GPR_ASSERT(grpc_compression_options_is_algorithm_enabled( + &channeld->compression_options, channeld->default_compression_algorithm)); + channeld->compression_options.default_compression_algorithm = + channeld->default_compression_algorithm; channeld->mdstr_request_compression_algorithm_key = grpc_mdstr_from_string(mdctx, GRPC_COMPRESS_REQUEST_ALGORITHM_KEY, 0); @@ -316,6 +338,11 @@ static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master, for (algo_idx = 0; algo_idx < GRPC_COMPRESS_ALGORITHMS_COUNT; ++algo_idx) { char *algorithm_name; + /* skip disabled algorithms */ + if (grpc_compression_options_is_algorithm_enabled( + &channeld->compression_options, algo_idx) == 0) { + continue; + } GPR_ASSERT(grpc_compression_algorithm_name(algo_idx, &algorithm_name) != 0); channeld->mdelem_compression_algorithms[algo_idx] = grpc_mdelem_from_metadata_strings( @@ -323,15 +350,15 @@ static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master, GRPC_MDSTR_REF(channeld->mdstr_outgoing_compression_algorithm_key), grpc_mdstr_from_string(mdctx, algorithm_name, 0)); if (algo_idx > 0) { - supported_algorithms_names[algo_idx - 1] = algorithm_name; + supported_algorithms_names[supported_algorithms_idx++] = algorithm_name; } } /* TODO(dgq): gpr_strjoin_sep could be made to work with statically allocated * arrays, as to avoid the heap allocs */ - accept_encoding_str = gpr_strjoin_sep( - supported_algorithms_names, GPR_ARRAY_SIZE(supported_algorithms_names), - ", ", &accept_encoding_str_len); + accept_encoding_str = + gpr_strjoin_sep(supported_algorithms_names, supported_algorithms_idx, ",", + &accept_encoding_str_len); channeld->mdelem_accept_encoding = grpc_mdelem_from_metadata_strings( mdctx, GRPC_MDSTR_REF(channeld->mdstr_compression_capabilities_key), diff --git a/src/core/client_config/uri_parser.c b/src/core/client_config/uri_parser.c index 5c2aa46e538718f7feaec1034461578f03b32f4a..2738e2df5763d45d1e545418410159c16405ca34 100644 --- a/src/core/client_config/uri_parser.c +++ b/src/core/client_config/uri_parser.c @@ -39,6 +39,9 @@ #include <grpc/support/log.h> #include <grpc/support/string_util.h> +/** a size_t default value... maps to all 1's */ +#define NOT_SET (~(size_t)0) + static grpc_uri *bad_uri(const char *uri_text, size_t pos, const char *section, int suppress_errors) { char *line_prefix; @@ -60,24 +63,89 @@ static grpc_uri *bad_uri(const char *uri_text, size_t pos, const char *section, return NULL; } -static char *copy_fragment(const char *src, size_t begin, size_t end) { - char *out; - GPR_ASSERT(end >= begin); - out = gpr_malloc(end - begin + 1); +/** Returns a copy of \a src[begin, end) */ +static char *copy_component(const char *src, size_t begin, size_t end) { + char *out = gpr_malloc(end - begin + 1); memcpy(out, src + begin, end - begin); out[end - begin] = 0; return out; } +/** Returns how many chars to advance if \a uri_text[i] begins a valid \a pchar + * production. If \a uri_text[i] introduces an invalid \a pchar (such as percent + * sign not followed by two hex digits), NOT_SET is returned. */ +static size_t parse_pchar(const char *uri_text, size_t i) { + /* pchar = unreserved / pct-encoded / sub-delims / ":" / "@" + * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" + * pct-encoded = "%" HEXDIG HEXDIG + * sub-delims = "!" / "$" / "&" / "'" / "(" / ")" + / "*" / "+" / "," / ";" / "=" */ + char c = uri_text[i]; + if (((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z')) || + ((c >= '0') && (c <= '9')) || + (c == '-' || c == '.' || c == '_' || c == '~') || /* unreserved */ + + (c == '!' || c == '$' || c == '&' || c == '\'' || c == '$' || c == '&' || + c == '(' || c == ')' || c == '*' || c == '+' || c == ',' || c == ';' || + c == '=') /* sub-delims */) { + return 1; + } + if (c == '%') { /* pct-encoded */ + size_t j; + if (uri_text[i + 1] == 0 || uri_text[i + 2] == 0) { + return NOT_SET; + } + for (j = i + 1; j < 2; j++) { + c = uri_text[j]; + if (!(((c >= '0') && (c <= '9')) || ((c >= 'a') && (c <= 'f')) || + ((c >= 'A') && (c <= 'F')))) { + return NOT_SET; + } + } + return 2; + } + return 0; +} + +/* *( pchar / "?" / "/" ) */ +static int parse_fragment_or_query(const char *uri_text, size_t *i) { + char c; + while ((c = uri_text[*i]) != 0) { + const size_t advance = parse_pchar(uri_text, *i); /* pchar */ + switch (advance) { + case 0: /* uri_text[i] isn't in pchar */ + /* maybe it's ? or / */ + if (uri_text[*i] == '?' || uri_text[*i] == '/') { + (*i)++; + break; + } else { + return 1; + } + gpr_log(GPR_ERROR, "should never reach here"); + abort(); + default: + (*i) += advance; + break; + case NOT_SET: /* uri_text[i] introduces an invalid URI */ + return 0; + } + } + /* *i is the first uri_text position past the \a query production, maybe \0 */ + return 1; +} + grpc_uri *grpc_uri_parse(const char *uri_text, int suppress_errors) { grpc_uri *uri; size_t scheme_begin = 0; -#define NOT_SET (~(size_t)0) size_t scheme_end = NOT_SET; size_t authority_begin = NOT_SET; size_t authority_end = NOT_SET; size_t path_begin = NOT_SET; size_t path_end = NOT_SET; + size_t query_begin = NOT_SET; + size_t query_end = NOT_SET; + size_t fragment_begin = NOT_SET; + size_t fragment_end = NOT_SET; size_t i; for (i = scheme_begin; uri_text[i] != 0; i++) { @@ -103,15 +171,9 @@ grpc_uri *grpc_uri_parse(const char *uri_text, int suppress_errors) { authority_begin = scheme_end + 3; for (i = authority_begin; uri_text[i] != 0 && authority_end == NOT_SET; i++) { - if (uri_text[i] == '/') { + if (uri_text[i] == '/' || uri_text[i] == '?' || uri_text[i] == '#') { authority_end = i; } - if (uri_text[i] == '?') { - return bad_uri(uri_text, i, "query_not_supported", suppress_errors); - } - if (uri_text[i] == '#') { - return bad_uri(uri_text, i, "fragment_not_supported", suppress_errors); - } } if (authority_end == NOT_SET && uri_text[i] == 0) { authority_end = i; @@ -126,20 +188,46 @@ grpc_uri *grpc_uri_parse(const char *uri_text, int suppress_errors) { } for (i = path_begin; uri_text[i] != 0; i++) { - if (uri_text[i] == '?') { - return bad_uri(uri_text, i, "query_not_supported", suppress_errors); + if (uri_text[i] == '?' || uri_text[i] == '#') { + path_end = i; + break; } - if (uri_text[i] == '#') { - return bad_uri(uri_text, i, "fragment_not_supported", suppress_errors); + } + if (path_end == NOT_SET && uri_text[i] == 0) { + path_end = i; + } + if (path_end == NOT_SET) { + return bad_uri(uri_text, i, "path", suppress_errors); + } + + if (uri_text[i] == '?') { + query_begin = ++i; + if (!parse_fragment_or_query(uri_text, &i)) { + return bad_uri(uri_text, i, "query", suppress_errors); + } else if (uri_text[i] != 0 && uri_text[i] != '#') { + /* We must be at the end or at the beginning of a fragment */ + return bad_uri(uri_text, i, "query", suppress_errors); + } + query_end = i; + } + if (uri_text[i] == '#') { + fragment_begin = ++i; + if (!parse_fragment_or_query(uri_text, &i)) { + return bad_uri(uri_text, i - fragment_end, "fragment", suppress_errors); + } else if (uri_text[i] != 0) { + /* We must be at the end */ + return bad_uri(uri_text, i, "fragment", suppress_errors); } + fragment_end = i; } - path_end = i; uri = gpr_malloc(sizeof(*uri)); memset(uri, 0, sizeof(*uri)); - uri->scheme = copy_fragment(uri_text, scheme_begin, scheme_end); - uri->authority = copy_fragment(uri_text, authority_begin, authority_end); - uri->path = copy_fragment(uri_text, path_begin, path_end); + uri->scheme = copy_component(uri_text, scheme_begin, scheme_end); + uri->authority = copy_component(uri_text, authority_begin, authority_end); + uri->path = copy_component(uri_text, path_begin, path_end); + uri->query = copy_component(uri_text, query_begin, query_end); + uri->fragment = copy_component(uri_text, fragment_begin, fragment_end); return uri; } @@ -149,5 +237,7 @@ void grpc_uri_destroy(grpc_uri *uri) { gpr_free(uri->scheme); gpr_free(uri->authority); gpr_free(uri->path); + gpr_free(uri->query); + gpr_free(uri->fragment); gpr_free(uri); } diff --git a/src/core/client_config/uri_parser.h b/src/core/client_config/uri_parser.h index ce4e6aecb09c83480a8217f444e913161727cdf3..b8daa13bd4f66a0f39ccc210fab025851e3f026c 100644 --- a/src/core/client_config/uri_parser.h +++ b/src/core/client_config/uri_parser.h @@ -38,6 +38,8 @@ typedef struct { char *scheme; char *authority; char *path; + char *query; + char *fragment; } grpc_uri; /** parse a uri, return NULL on failure */ diff --git a/src/core/compression/algorithm.c b/src/core/compression/algorithm.c index 6ed6dbe93f26dbbf1b41561f154b8ea493f7b638..76d42fde0f7868a3405cbdc3a74ed685deb605c6 100644 --- a/src/core/compression/algorithm.c +++ b/src/core/compression/algorithm.c @@ -33,7 +33,9 @@ #include <stdlib.h> #include <string.h> + #include <grpc/compression.h> +#include <grpc/support/useful.h> int grpc_compression_algorithm_parse(const char *name, size_t name_length, grpc_compression_algorithm *algorithm) { @@ -102,3 +104,24 @@ grpc_compression_level grpc_compression_level_for_algorithm( } abort(); } + +void grpc_compression_options_init(grpc_compression_options *opts) { + opts->enabled_algorithms_bitset = (1u << GRPC_COMPRESS_ALGORITHMS_COUNT)-1; + opts->default_compression_algorithm = GRPC_COMPRESS_NONE; +} + +void grpc_compression_options_enable_algorithm( + grpc_compression_options *opts, grpc_compression_algorithm algorithm) { + GPR_BITSET(&opts->enabled_algorithms_bitset, algorithm); +} + +void grpc_compression_options_disable_algorithm( + grpc_compression_options *opts, grpc_compression_algorithm algorithm) { + GPR_BITCLEAR(&opts->enabled_algorithms_bitset, algorithm); +} + +int grpc_compression_options_is_algorithm_enabled( + const grpc_compression_options *opts, + grpc_compression_algorithm algorithm) { + return GPR_BITGET(opts->enabled_algorithms_bitset, algorithm); +} diff --git a/src/core/surface/call.c b/src/core/surface/call.c index 16a7d2ec3587cefa3e9bc3a1ffa9fa27923555b0..4168c2ef0ccf16fc4a2cfa8ebe2fb6bb80d23c75 100644 --- a/src/core/surface/call.c +++ b/src/core/surface/call.c @@ -534,7 +534,7 @@ static void set_encodings_accepted_by_peer( gpr_slice_buffer accept_encoding_parts; gpr_slice_buffer_init(&accept_encoding_parts); - gpr_slice_split(accept_encoding_slice, ", ", &accept_encoding_parts); + gpr_slice_split(accept_encoding_slice, ",", &accept_encoding_parts); /* No need to zero call->encodings_accepted_by_peer: grpc_call_create already * zeroes the whole grpc_call */ diff --git a/src/cpp/server/server.cc b/src/cpp/server/server.cc index d67205e822f58ceac9c3ca3a6f7c6ef58ba516f3..a3020c342b416790f541599cde1f6a598a110249 100644 --- a/src/cpp/server/server.cc +++ b/src/cpp/server/server.cc @@ -252,28 +252,36 @@ class Server::SyncRequest GRPC_FINAL : public CompletionQueueTag { grpc_completion_queue* cq_; }; -static grpc_server* CreateServer(int max_message_size) { +static grpc_server* CreateServer( + int max_message_size, const grpc_compression_options& compression_options) { + grpc_arg args[2]; + size_t args_idx = 0; if (max_message_size > 0) { - grpc_arg arg; - arg.type = GRPC_ARG_INTEGER; - arg.key = const_cast<char*>(GRPC_ARG_MAX_MESSAGE_LENGTH); - arg.value.integer = max_message_size; - grpc_channel_args args = {1, &arg}; - return grpc_server_create(&args, nullptr); - } else { - return grpc_server_create(nullptr, nullptr); + args[args_idx].type = GRPC_ARG_INTEGER; + args[args_idx].key = const_cast<char*>(GRPC_ARG_MAX_MESSAGE_LENGTH); + args[args_idx].value.integer = max_message_size; + args_idx++; } + + args[args_idx].type = GRPC_ARG_INTEGER; + args[args_idx].key = const_cast<char*>(GRPC_COMPRESSION_ALGORITHM_STATE_ARG); + args[args_idx].value.integer = compression_options.enabled_algorithms_bitset; + args_idx++; + + grpc_channel_args channel_args = {args_idx, args}; + return grpc_server_create(&channel_args, nullptr); } Server::Server(ThreadPoolInterface* thread_pool, bool thread_pool_owned, - int max_message_size) + int max_message_size, + grpc_compression_options compression_options) : max_message_size_(max_message_size), started_(false), shutdown_(false), num_running_cb_(0), sync_methods_(new std::list<SyncRequest>), has_generic_service_(false), - server_(CreateServer(max_message_size)), + server_(CreateServer(max_message_size, compression_options)), thread_pool_(thread_pool), thread_pool_owned_(thread_pool_owned) { grpc_server_register_completion_queue(server_, cq_.cq(), nullptr); diff --git a/src/cpp/server/server_builder.cc b/src/cpp/server/server_builder.cc index 99bc8147a0d86a458cd0e2b140ef1ce5915e4eec..1c7e4e4eb663b9baad39e52e1c28e26714e95e1d 100644 --- a/src/cpp/server/server_builder.cc +++ b/src/cpp/server/server_builder.cc @@ -43,7 +43,9 @@ namespace grpc { ServerBuilder::ServerBuilder() - : max_message_size_(-1), generic_service_(nullptr), thread_pool_(nullptr) {} + : max_message_size_(-1), generic_service_(nullptr), thread_pool_(nullptr) { + grpc_compression_options_init(&compression_options_); +} std::unique_ptr<ServerCompletionQueue> ServerBuilder::AddCompletionQueue() { ServerCompletionQueue* cq = new ServerCompletionQueue(); @@ -99,8 +101,9 @@ std::unique_ptr<Server> ServerBuilder::BuildAndStart() { thread_pool_ = CreateDefaultThreadPool(); thread_pool_owned = true; } - std::unique_ptr<Server> server( - new Server(thread_pool_, thread_pool_owned, max_message_size_)); + std::unique_ptr<Server> server(new Server(thread_pool_, thread_pool_owned, + max_message_size_, + compression_options_)); for (auto cq = cqs_.begin(); cq != cqs_.end(); ++cq) { grpc_server_register_completion_queue(server->server_, (*cq)->cq(), nullptr); diff --git a/src/python/grpcio/commands.py b/src/python/grpcio/commands.py index 89c0fbf0f3f1abb0facb26d7eadf6bada3909d40..8a2f2d6283edcb13806aec5f0d94ff5c2c9a1f4c 100644 --- a/src/python/grpcio/commands.py +++ b/src/python/grpcio/commands.py @@ -64,7 +64,7 @@ class SphinxDocumentation(setuptools.Command): import sphinx.apidoc metadata = self.distribution.metadata src_dir = os.path.join( - os.getcwd(), self.distribution.package_dir['grpc']) + os.getcwd(), self.distribution.package_dir[''], 'grpc') sys.path.append(src_dir) sphinx.apidoc.main([ '', '--force', '--full', '-H', metadata.name, '-A', metadata.author, diff --git a/src/python/grpcio/grpc/beta/_server.py b/src/python/grpcio/grpc/beta/_server.py index daa42c475ad991c7292a8c941ac5252ba01143fa..05b954d1860030557ccffe3f0c5a562c76f87534 100644 --- a/src/python/grpcio/grpc/beta/_server.py +++ b/src/python/grpcio/grpc/beta/_server.py @@ -86,13 +86,13 @@ class Server(interfaces.Server): return self._grpc_link.add_port( address, server_credentials._intermediary_low_credentials) # pylint: disable=protected-access - def start(self): + def _start(self): self._grpc_link.join_link(self._end_link) self._end_link.join_link(self._grpc_link) self._grpc_link.start() self._end_link.start() - def stop(self, grace): + def _stop(self, grace): stop_event = threading.Event() if 0 < grace: disassembly_thread = threading.Thread( @@ -105,6 +105,20 @@ class Server(interfaces.Server): _disassemble(self._grpc_link, self._end_link, self._pool, stop_event, 0) return stop_event + def start(self): + self._start() + + def stop(self, grace): + return self._stop(grace) + + def __enter__(self): + self._start() + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + self._stop(0).wait() + return False + def server( implementations, multi_implementation, request_deserializers, diff --git a/src/python/grpcio/grpc/beta/_stub.py b/src/python/grpcio/grpc/beta/_stub.py index cfbecb852b292a77371775862a54a47dacfc4bd1..11dab889cd0f34e8196a885374c4aa1d94f0130f 100644 --- a/src/python/grpcio/grpc/beta/_stub.py +++ b/src/python/grpcio/grpc/beta/_stub.py @@ -49,6 +49,12 @@ class _AutoIntermediary(object): def __getattr__(self, attr): return getattr(self._delegate, attr) + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + return False + def __del__(self): self._on_deletion() diff --git a/src/python/grpcio/requirements.txt b/src/python/grpcio/requirements.txt index 43395df03b997c30098e62caba748bdc927048b7..608ba402e094aa65db61e990c34e58119408db6c 100644 --- a/src/python/grpcio/requirements.txt +++ b/src/python/grpcio/requirements.txt @@ -1,3 +1,2 @@ enum34==1.0.4 futures==2.2.0 -protobuf==3.0.0a3 diff --git a/src/python/grpcio/setup.py b/src/python/grpcio/setup.py index 4735ce080b094a7c8d6af64da509dcd0f4201bb0..151b2bfcb4d55fd64f092cb8d6c25f2de016e23e 100644 --- a/src/python/grpcio/setup.py +++ b/src/python/grpcio/setup.py @@ -104,7 +104,7 @@ _COMMAND_CLASS = { setuptools.setup( name='grpcio', - version='0.11.0', + version='0.11.0b0', ext_modules=_EXTENSION_MODULES, packages=list(_PACKAGES), package_dir=_PACKAGE_DIRECTORIES, diff --git a/src/python/grpcio_health_checking/setup.py b/src/python/grpcio_health_checking/setup.py index fcde0dab8c9607a145c5e01d8b76ef41c9507ac8..35253ba31235343a1fe8c51d1d1194f4cafbe94b 100644 --- a/src/python/grpcio_health_checking/setup.py +++ b/src/python/grpcio_health_checking/setup.py @@ -51,7 +51,7 @@ _PACKAGE_DIRECTORIES = { } _INSTALL_REQUIRES = ( - 'grpcio>=0.10.0a0', + 'grpcio>=0.11.0b0', ) _SETUP_REQUIRES = _INSTALL_REQUIRES @@ -63,7 +63,7 @@ _COMMAND_CLASS = { setuptools.setup( name='grpcio_health_checking', - version='0.10.0a0', + version='0.11.0b0', packages=list(_PACKAGES), package_dir=_PACKAGE_DIRECTORIES, install_requires=_INSTALL_REQUIRES, diff --git a/src/python/grpcio_test/requirements.txt b/src/python/grpcio_test/requirements.txt index 856198def57bf26e457c7d9abd63355546ac30af..fea80ca07f1ad687686af5859cea20cf18106341 100644 --- a/src/python/grpcio_test/requirements.txt +++ b/src/python/grpcio_test/requirements.txt @@ -1,5 +1,6 @@ +grpcio>=0.11.0b0 +oauth2client>=1.4.7 +protobuf>=3.0.0a3 pytest>=2.6 pytest-cov>=2.0 pytest-xdist>=1.11 -oauth2client>=1.4.7 -grpcio>=0.10.0a0 diff --git a/src/python/grpcio_test/setup.py b/src/python/grpcio_test/setup.py index 802dd1e53afa3a6c4bf2b9ce49291bea9b3f80d9..216119f0e7bb1ba44bc14667946f2ea5ac5a05e7 100644 --- a/src/python/grpcio_test/setup.py +++ b/src/python/grpcio_test/setup.py @@ -71,7 +71,7 @@ _SETUP_REQUIRES = ( _INSTALL_REQUIRES = ( 'oauth2client>=1.4.7', - 'grpcio>=0.10.0a0', + 'grpcio>=0.11.0b0', ) _COMMAND_CLASS = { @@ -80,7 +80,7 @@ _COMMAND_CLASS = { setuptools.setup( name='grpcio_test', - version='0.10.0a0', + version='0.11.0b0', packages=_PACKAGES, package_dir=_PACKAGE_DIRECTORIES, package_data=_PACKAGE_DATA, diff --git a/templates/Makefile.template b/templates/Makefile.template index 346b4f438ce9ccdec89b50ad014021fdbcc7c309..d8370ce26892f96c3559dede4c185d9a4242ea80 100644 --- a/templates/Makefile.template +++ b/templates/Makefile.template @@ -161,7 +161,7 @@ CXX_tsan = clang++ LD_tsan = clang LDXX_tsan = clang++ - CPPFLAGS_tsan = -O0 -fsanitize=thread -fno-omit-frame-pointer -Wno-error=unused-command-line-argument + CPPFLAGS_tsan = -O0 -fsanitize=thread -fno-omit-frame-pointer -Wno-unused-command-line-argument LDFLAGS_tsan = -fsanitize=thread DEFINES_tsan = NDEBUG GRPC_TEST_SLOWDOWN_BUILD_FACTOR=10 @@ -171,7 +171,7 @@ CXX_asan = clang++ LD_asan = clang LDXX_asan = clang++ - CPPFLAGS_asan = -O0 -fsanitize=address -fno-omit-frame-pointer -Wno-error=unused-command-line-argument + CPPFLAGS_asan = -O0 -fsanitize=address -fno-omit-frame-pointer -Wno-unused-command-line-argument LDFLAGS_asan = -fsanitize=address DEFINES_asan = GRPC_TEST_SLOWDOWN_BUILD_FACTOR=3 @@ -181,7 +181,7 @@ CXX_msan = clang++-libc++ LD_msan = clang LDXX_msan = clang++-libc++ - CPPFLAGS_msan = -O0 -fsanitize=memory -fsanitize-memory-track-origins -fno-omit-frame-pointer -DGTEST_HAS_TR1_TUPLE=0 -DGTEST_USE_OWN_TR1_TUPLE=1 -Wno-error=unused-command-line-argument + CPPFLAGS_msan = -O0 -fsanitize=memory -fsanitize-memory-track-origins -fno-omit-frame-pointer -DGTEST_HAS_TR1_TUPLE=0 -DGTEST_USE_OWN_TR1_TUPLE=1 -Wno-unused-command-line-argument OPENSSL_CFLAGS_msan = -DPURIFY LDFLAGS_msan = -fsanitize=memory -DGTEST_HAS_TR1_TUPLE=0 -DGTEST_USE_OWN_TR1_TUPLE=1 DEFINES_msan = NDEBUG GRPC_TEST_SLOWDOWN_BUILD_FACTOR=4 @@ -192,7 +192,7 @@ CXX_ubsan = clang++ LD_ubsan = clang LDXX_ubsan = clang++ - CPPFLAGS_ubsan = -O1 -fsanitize=undefined -fno-omit-frame-pointer -Wno-error=unused-command-line-argument + CPPFLAGS_ubsan = -O1 -fsanitize=undefined -fno-omit-frame-pointer -Wno-unused-command-line-argument OPENSSL_CFLAGS_ubsan = -DPURIFY LDFLAGS_ubsan = -fsanitize=undefined DEFINES_ubsan = NDEBUG GRPC_TEST_SLOWDOWN_BUILD_FACTOR=3 diff --git a/test/core/client_config/uri_parser_test.c b/test/core/client_config/uri_parser_test.c index d324029c7efc0382a98be0f9f2ee52e9e18ba5e7..580c18b699ddeaa96be30740d6e71e92efa1b98f 100644 --- a/test/core/client_config/uri_parser_test.c +++ b/test/core/client_config/uri_parser_test.c @@ -40,12 +40,15 @@ #include "test/core/util/test_config.h" static void test_succeeds(const char *uri_text, const char *scheme, - const char *authority, const char *path) { + const char *authority, const char *path, + const char *query, const char* fragment) { grpc_uri *uri = grpc_uri_parse(uri_text, 0); GPR_ASSERT(uri); GPR_ASSERT(0 == strcmp(scheme, uri->scheme)); GPR_ASSERT(0 == strcmp(authority, uri->authority)); GPR_ASSERT(0 == strcmp(path, uri->path)); + GPR_ASSERT(0 == strcmp(query, uri->query)); + GPR_ASSERT(0 == strcmp(fragment, uri->fragment)); grpc_uri_destroy(uri); } @@ -55,17 +58,29 @@ static void test_fails(const char *uri_text) { int main(int argc, char **argv) { grpc_test_init(argc, argv); - test_succeeds("http://www.google.com", "http", "www.google.com", ""); - test_succeeds("dns:///foo", "dns", "", "/foo"); - test_succeeds("http://www.google.com:90", "http", "www.google.com:90", ""); - test_succeeds("a192.4-df:foo.coom", "a192.4-df", "", "foo.coom"); - test_succeeds("a+b:foo.coom", "a+b", "", "foo.coom"); + test_succeeds("http://www.google.com", "http", "www.google.com", "", "", ""); + test_succeeds("dns:///foo", "dns", "", "/foo", "", ""); + test_succeeds("http://www.google.com:90", "http", "www.google.com:90", "", "", + ""); + test_succeeds("a192.4-df:foo.coom", "a192.4-df", "", "foo.coom", "", ""); + test_succeeds("a+b:foo.coom", "a+b", "", "foo.coom", "", ""); test_succeeds("zookeeper://127.0.0.1:2181/foo/bar", "zookeeper", - "127.0.0.1:2181", "/foo/bar"); + "127.0.0.1:2181", "/foo/bar", "", ""); + test_succeeds("http://www.google.com?yay-i'm-using-queries", "http", + "www.google.com", "", "yay-i'm-using-queries", ""); + test_succeeds("dns:foo.com#fragment-all-the-things", "dns", "", "foo.com", "", + "fragment-all-the-things"); + test_succeeds("http:?legit", "http", "", "", "legit", ""); + test_succeeds("unix:#this-is-ok-too", "unix", "", "", "", "this-is-ok-too"); + test_succeeds("http:?legit#twice", "http", "", "", "legit", "twice"); + test_succeeds("http://foo?bar#lol?", "http", "foo", "", "bar", "lol?"); + test_succeeds("http://foo?bar#lol?/", "http", "foo", "", "bar", "lol?/"); + test_fails("xyz"); - test_fails("http://www.google.com?why-are-you-using-queries"); - test_fails("dns:foo.com#fragments-arent-supported-here"); - test_fails("http:?huh"); - test_fails("unix:#yeah-right"); + test_fails("http:?dangling-pct-%0"); + test_fails("http://foo?[bar]"); + test_fails("http://foo?x[bar]"); + test_fails("http://foo?bar#lol#"); + return 0; } diff --git a/test/core/end2end/dualstack_socket_test.c b/test/core/end2end/dualstack_socket_test.c index 2aee333d27730a7b1d44ea6beac8868ff232f5be..ec3fb651051b9f14e18e926803da982f33456022 100644 --- a/test/core/end2end/dualstack_socket_test.c +++ b/test/core/end2end/dualstack_socket_test.c @@ -40,6 +40,7 @@ #include <grpc/support/string_util.h> #include "src/core/support/string.h" +#include "src/core/iomgr/resolve_address.h" #include "src/core/iomgr/socket_utils_posix.h" #include "test/core/end2end/cq_verifier.h" @@ -263,6 +264,15 @@ void test_connect(const char *server_host, const char *client_host, int port, gpr_free(details); } +int external_dns_works(const char *host) { + grpc_resolved_addresses *res = grpc_blocking_resolve_address(host, "80"); + if (res != NULL) { + gpr_free(res); + return 1; + } + return 0; +} + int main(int argc, char **argv) { int do_ipv6 = 1; @@ -308,6 +318,25 @@ int main(int argc, char **argv) { test_connect("::1", "ipv4:127.0.0.1", 0, 0); test_connect("127.0.0.1", "ipv6:[::1]", 0, 0); } + + if (!external_dns_works("loopback46.unittest.grpc.io")) { + gpr_log(GPR_INFO, "Skipping tests that depend on *.unittest.grpc.io."); + } else { + test_connect("loopback46.unittest.grpc.io", + "loopback4.unittest.grpc.io", 0, 1); + test_connect("loopback4.unittest.grpc.io", + "loopback46.unittest.grpc.io", 0, 1); + if (do_ipv6) { + test_connect("loopback46.unittest.grpc.io", + "loopback6.unittest.grpc.io", 0, 1); + test_connect("loopback6.unittest.grpc.io", + "loopback46.unittest.grpc.io", 0, 1); + test_connect("loopback4.unittest.grpc.io", + "loopback6.unittest.grpc.io", 0, 0); + test_connect("loopback6.unittest.grpc.io", + "loopback4.unittest.grpc.io", 0, 0); + } + } } grpc_shutdown(); diff --git a/test/cpp/qps/server_async.cc b/test/cpp/qps/server_async.cc index 0ed2048d4a79c7e7a8f6c01c5b84523e95d8c80e..516598a0e221367e099a20b774bb0582db69439b 100644 --- a/test/cpp/qps/server_async.cc +++ b/test/cpp/qps/server_async.cc @@ -98,7 +98,9 @@ class AsyncQpsServerTest : public Server { } } ~AsyncQpsServerTest() { - server_->Shutdown(); + auto deadline = std::chrono::system_clock::now() + + std::chrono::seconds(10); + server_->Shutdown(deadline); for (auto ss = shutdown_state_.begin(); ss != shutdown_state_.end(); ++ss) { (*ss)->set_shutdown(); } diff --git a/tools/distrib/python/docgen.py b/tools/distrib/python/docgen.py index d76792c56f418733099ddee90273e70e7cf1a8a2..2acd3cc12f27e76749afd8bc2c02b7957805bc98 100755 --- a/tools/distrib/python/docgen.py +++ b/tools/distrib/python/docgen.py @@ -81,7 +81,7 @@ if args.submit: assert args.doc_branch github_user = args.gh_user github_repository_owner = ( - args.gh_repo_owner if args.gh_repo_owner else gh_user) + args.gh_repo_owner if args.gh_repo_owner else args.gh_user) # Create a temporary directory out of tree, checkout gh-pages from the # specified repository, edit it, and push it. It's up to the user to then go # onto GitHub and make a PR against grpc/grpc:gh-pages.