aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/compiler/config.h90
-rw-r--r--src/compiler/cpp_generator.cc217
-rw-r--r--src/compiler/cpp_generator.h25
-rw-r--r--src/compiler/cpp_generator_helpers.h18
-rw-r--r--src/compiler/cpp_plugin.cc60
-rw-r--r--src/compiler/generator_helpers.h35
-rw-r--r--src/compiler/python_generator.cc199
-rw-r--r--src/compiler/python_generator.h30
-rw-r--r--src/compiler/python_plugin.cc60
-rw-r--r--src/compiler/ruby_generator.cc48
-rw-r--r--src/compiler/ruby_generator.h10
-rw-r--r--src/compiler/ruby_generator_helpers-inl.h12
-rw-r--r--src/compiler/ruby_generator_map-inl.h13
-rw-r--r--src/compiler/ruby_generator_string-inl.h43
-rw-r--r--src/compiler/ruby_plugin.cc30
-rw-r--r--src/core/channel/http_server_filter.c19
-rw-r--r--src/core/channel/metadata_buffer.c51
-rw-r--r--src/core/iomgr/fd_posix.c8
-rw-r--r--src/core/iomgr/iocp_windows.c34
-rw-r--r--src/core/iomgr/iocp_windows.h1
-rw-r--r--src/core/iomgr/iomgr.c11
-rw-r--r--src/core/iomgr/sockaddr_win32.h5
-rw-r--r--src/core/iomgr/socket_windows.c7
-rw-r--r--src/core/iomgr/socket_windows.h6
-rw-r--r--src/core/iomgr/tcp_server_windows.c3
-rw-r--r--src/core/iomgr/tcp_windows.c4
-rw-r--r--src/core/security/credentials.c79
-rw-r--r--src/core/security/credentials.h16
-rw-r--r--src/core/security/google_default_credentials.c19
-rw-r--r--src/core/security/json_token.c79
-rw-r--r--src/core/security/json_token.h23
-rw-r--r--src/core/security/roots.pem2183
-rw-r--r--[-rwxr-xr-x]src/core/support/cpu_iphone.c (renamed from src/php/ext/grpc/completion_queue.h)49
-rw-r--r--src/core/support/cpu_posix.c2
-rw-r--r--src/core/support/env_win32.c15
-rw-r--r--src/core/support/file_win32.c2
-rw-r--r--src/core/support/log_win32.c8
-rw-r--r--src/core/support/slice_buffer.c7
-rw-r--r--src/core/support/string_win32.c6
-rw-r--r--src/core/support/sync_win32.c1
-rw-r--r--src/core/support/time_win32.c4
-rw-r--r--src/core/transport/chttp2_transport.c10
-rw-r--r--src/core/tsi/ssl_transport_security.c4
-rw-r--r--src/cpp/client/channel.h10
-rw-r--r--src/cpp/client/channel_arguments.cc18
-rw-r--r--src/cpp/client/client_context.cc8
-rw-r--r--src/cpp/client/client_unary_call.cc8
-rw-r--r--src/cpp/client/create_channel.cc9
-rw-r--r--src/cpp/client/insecure_credentials.cc4
-rw-r--r--src/cpp/client/secure_credentials.cc37
-rw-r--r--src/cpp/common/call.cc97
-rw-r--r--src/cpp/common/completion_queue.cc20
-rw-r--r--src/cpp/proto/proto_utils.cc146
-rw-r--r--src/cpp/proto/proto_utils.h6
-rw-r--r--[-rwxr-xr-x]src/cpp/server/async_generic_service.cc (renamed from src/php/tests/unit_tests/CompletionQueueTest.php)28
-rw-r--r--src/cpp/server/async_server_context.cc16
-rw-r--r--src/cpp/server/insecure_server_credentials.cc3
-rw-r--r--src/cpp/server/secure_server_credentials.cc19
-rw-r--r--src/cpp/server/server.cc77
-rw-r--r--src/cpp/server/server_builder.cc41
-rw-r--r--src/cpp/server/thread_pool.cc47
-rw-r--r--src/cpp/server/thread_pool.h4
-rw-r--r--src/cpp/util/byte_buffer.cc76
-rw-r--r--[-rwxr-xr-x]src/cpp/util/slice.cc (renamed from src/php/ext/grpc/event.h)23
-rw-r--r--src/cpp/util/status.cc4
-rw-r--r--src/cpp/util/time.cc10
-rw-r--r--src/cpp/util/time.h4
-rw-r--r--src/csharp/Grpc.Core.Tests/ClientServerTest.cs28
-rw-r--r--src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj4
-rw-r--r--src/csharp/Grpc.Core.Tests/GrpcEnvironmentTest.cs2
-rw-r--r--src/csharp/Grpc.Core.Tests/Internal/MetadataArraySafeHandleTest.cs62
-rw-r--r--src/csharp/Grpc.Core.Tests/PInvokeTest.cs35
-rw-r--r--src/csharp/Grpc.Core.Tests/Properties/AssemblyInfo.cs10
-rw-r--r--src/csharp/Grpc.Core.Tests/ServerTest.cs3
-rw-r--r--src/csharp/Grpc.Core.Tests/TimespecTest.cs1
-rw-r--r--src/csharp/Grpc.Core/Call.cs57
-rw-r--r--src/csharp/Grpc.Core/Calls.cs36
-rw-r--r--src/csharp/Grpc.Core/Channel.cs5
-rw-r--r--src/csharp/Grpc.Core/ChannelArgs.cs47
-rw-r--r--src/csharp/Grpc.Core/ClientStreamingAsyncResult.cs1
-rw-r--r--src/csharp/Grpc.Core/Credentials.cs4
-rw-r--r--src/csharp/Grpc.Core/Grpc.Core.csproj17
-rw-r--r--src/csharp/Grpc.Core/GrpcEnvironment.cs8
-rw-r--r--src/csharp/Grpc.Core/Internal/AsyncCall.cs49
-rw-r--r--src/csharp/Grpc.Core/Internal/AsyncCallBase.cs18
-rw-r--r--src/csharp/Grpc.Core/Internal/AsyncCompletion.cs1
-rw-r--r--src/csharp/Grpc.Core/Internal/BatchContextSafeHandleNotOwned.cs8
-rw-r--r--src/csharp/Grpc.Core/Internal/CallSafeHandle.cs40
-rw-r--r--src/csharp/Grpc.Core/Internal/ChannelArgsSafeHandle.cs1
-rw-r--r--src/csharp/Grpc.Core/Internal/CompletionQueueSafeHandle.cs1
-rw-r--r--src/csharp/Grpc.Core/Internal/Enums.cs1
-rw-r--r--src/csharp/Grpc.Core/Internal/GrpcLog.cs4
-rw-r--r--src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs17
-rw-r--r--src/csharp/Grpc.Core/Internal/MetadataArraySafeHandle.cs72
-rw-r--r--src/csharp/Grpc.Core/Internal/SafeHandleZeroIsInvalid.cs1
-rw-r--r--src/csharp/Grpc.Core/Internal/ServerCallHandler.cs (renamed from src/csharp/Grpc.Core/ServerCallHandler.cs)9
-rw-r--r--src/csharp/Grpc.Core/Internal/ServerCredentialsSafeHandle.cs68
-rw-r--r--src/csharp/Grpc.Core/Internal/ServerSafeHandle.cs13
-rw-r--r--src/csharp/Grpc.Core/Internal/ServerStreamingOutputObserver.cs1
-rw-r--r--src/csharp/Grpc.Core/Internal/Timespec.cs11
-rw-r--r--src/csharp/Grpc.Core/Marshaller.cs20
-rw-r--r--src/csharp/Grpc.Core/Metadata.cs126
-rw-r--r--src/csharp/Grpc.Core/Method.cs1
-rw-r--r--src/csharp/Grpc.Core/OperationFailedException.cs1
-rw-r--r--src/csharp/Grpc.Core/Properties/AssemblyInfo.cs28
-rw-r--r--src/csharp/Grpc.Core/RpcException.cs4
-rw-r--r--src/csharp/Grpc.Core/Server.cs49
-rw-r--r--src/csharp/Grpc.Core/ServerCalls.cs11
-rw-r--r--src/csharp/Grpc.Core/ServerCredentials.cs109
-rw-r--r--src/csharp/Grpc.Core/ServerServiceDefinition.cs33
-rw-r--r--src/csharp/Grpc.Core/StatusCode.cs5
-rw-r--r--src/csharp/Grpc.Core/Stub/AbstractStub.cs73
-rw-r--r--src/csharp/Grpc.Core/Stub/StubConfiguration.cs64
-rw-r--r--src/csharp/Grpc.Core/Utils/BenchmarkUtil.cs7
-rw-r--r--src/csharp/Grpc.Core/Utils/ExceptionHelper.cs4
-rw-r--r--src/csharp/Grpc.Core/Utils/Preconditions.cs9
-rw-r--r--src/csharp/Grpc.Core/Utils/RecordingObserver.cs4
-rw-r--r--src/csharp/Grpc.Core/Utils/RecordingQueue.cs5
-rw-r--r--src/csharp/Grpc.Core/packages.config4
-rw-r--r--src/csharp/Grpc.Examples.MathClient/Properties/AssemblyInfo.cs28
-rw-r--r--src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs24
-rw-r--r--src/csharp/Grpc.Examples.Tests/Properties/AssemblyInfo.cs10
-rw-r--r--src/csharp/Grpc.Examples/MathExamples.cs21
-rw-r--r--src/csharp/Grpc.Examples/MathGrpc.cs83
-rw-r--r--src/csharp/Grpc.Examples/MathServiceImpl.cs13
-rw-r--r--src/csharp/Grpc.Examples/Properties/AssemblyInfo.cs28
-rw-r--r--src/csharp/Grpc.Examples/Settings.StyleCop10
-rw-r--r--src/csharp/Grpc.IntegrationTesting.Client/Properties/AssemblyInfo.cs10
-rw-r--r--src/csharp/Grpc.IntegrationTesting.Server/Properties/AssemblyInfo.cs10
-rw-r--r--src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj11
-rw-r--r--src/csharp/Grpc.IntegrationTesting/InteropClient.cs31
-rw-r--r--src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs12
-rw-r--r--src/csharp/Grpc.IntegrationTesting/InteropServer.cs16
-rw-r--r--src/csharp/Grpc.IntegrationTesting/Properties/AssemblyInfo.cs10
-rw-r--r--src/csharp/Grpc.IntegrationTesting/Settings.StyleCop11
-rw-r--r--src/csharp/Grpc.IntegrationTesting/TestCredentials.cs84
-rw-r--r--src/csharp/Grpc.IntegrationTesting/TestServiceGrpc.cs120
-rw-r--r--src/csharp/Grpc.IntegrationTesting/TestServiceImpl.cs33
-rw-r--r--src/csharp/Grpc.IntegrationTesting/packages.config1
-rw-r--r--src/csharp/Settings.StyleCop509
-rw-r--r--src/csharp/ext/grpc_csharp_ext.c197
-rw-r--r--src/node/README.md6
-rw-r--r--src/node/examples/qps_test.js136
-rw-r--r--src/node/ext/byte_buffer.cc2
-rw-r--r--src/node/ext/call.cc34
-rw-r--r--src/node/ext/completion_queue_async_worker.cc1
-rw-r--r--src/node/index.js8
-rw-r--r--src/node/interop/interop_client.js12
-rw-r--r--src/node/package.json4
-rw-r--r--src/node/src/client.js53
-rw-r--r--src/node/src/common.js23
-rw-r--r--src/node/src/server.js99
-rw-r--r--src/node/test/call_test.js4
-rw-r--r--src/node/test/end_to_end_test.js87
-rw-r--r--src/node/test/server_test.js94
-rw-r--r--src/node/test/surface_test.js53
-rw-r--r--src/php/ext/grpc/byte_buffer.c5
-rw-r--r--src/php/ext/grpc/call.c536
-rw-r--r--src/php/ext/grpc/call.h19
-rw-r--r--src/php/ext/grpc/channel.c25
-rwxr-xr-xsrc/php/ext/grpc/channel.h2
-rw-r--r--src/php/ext/grpc/completion_queue.c168
-rwxr-xr-xsrc/php/ext/grpc/config.m42
-rw-r--r--src/php/ext/grpc/credentials.c2
-rwxr-xr-xsrc/php/ext/grpc/credentials.h2
-rw-r--r--src/php/ext/grpc/event.c150
-rw-r--r--src/php/ext/grpc/php_grpc.c36
-rw-r--r--src/php/ext/grpc/server.c78
-rwxr-xr-xsrc/php/ext/grpc/server.h3
-rw-r--r--src/php/ext/grpc/server_credentials.c2
-rwxr-xr-xsrc/php/ext/grpc/server_credentials.h2
-rw-r--r--src/php/ext/grpc/timeval.c2
-rwxr-xr-xsrc/php/ext/grpc/timeval.h2
-rwxr-xr-xsrc/php/lib/Grpc/ActiveCall.php37
-rwxr-xr-xsrc/php/tests/interop/interop_client.php7
-rwxr-xr-xsrc/php/tests/unit_tests/CallTest.php62
-rwxr-xr-xsrc/php/tests/unit_tests/EndToEndTest.php186
-rwxr-xr-xsrc/php/tests/unit_tests/SecureEndToEndTest.php197
-rw-r--r--src/python/README.md2
-rw-r--r--src/python/interop/interop/_insecure_interop_test.py5
-rw-r--r--src/python/interop/interop/_secure_interop_test.py6
-rw-r--r--src/python/interop/interop/client.py7
-rw-r--r--src/python/interop/interop/methods.py40
-rw-r--r--src/python/interop/interop/server.py5
-rw-r--r--src/python/src/grpc/_adapter/_call.c2
-rw-r--r--src/python/src/grpc/_adapter/_face_test_case.py36
-rw-r--r--src/python/src/grpc/_adapter/_links_test.py81
-rw-r--r--src/python/src/grpc/_adapter/_lonely_rear_link_test.py20
-rw-r--r--src/python/src/grpc/_adapter/_test_links.py2
-rw-r--r--src/python/src/grpc/_adapter/fore.py147
-rw-r--r--src/python/src/grpc/_adapter/rear.py172
-rw-r--r--src/python/src/grpc/early_adopter/implementations.py187
-rw-r--r--src/python/src/grpc/early_adopter/implementations_test.py10
-rw-r--r--src/python/src/grpc/framework/alpha/__init__.py (renamed from src/python/src/grpc/framework/base/packets/__init__.py)2
-rw-r--r--src/python/src/grpc/framework/alpha/_face_utilities.py (renamed from src/python/src/grpc/early_adopter/_assembly_utilities.py)111
-rw-r--r--src/python/src/grpc/framework/alpha/_reexport.py (renamed from src/python/src/grpc/early_adopter/_reexport.py)79
-rw-r--r--src/python/src/grpc/framework/alpha/exceptions.py (renamed from src/python/src/grpc/early_adopter/exceptions.py)0
-rw-r--r--src/python/src/grpc/framework/alpha/interfaces.py (renamed from src/python/src/grpc/early_adopter/interfaces.py)2
-rw-r--r--src/python/src/grpc/framework/alpha/utilities.py (renamed from src/python/src/grpc/early_adopter/utilities.py)2
-rw-r--r--src/python/src/grpc/framework/assembly/__init__.py30
-rw-r--r--src/python/src/grpc/framework/assembly/implementations.py317
-rw-r--r--src/python/src/grpc/framework/assembly/implementations_test.py284
-rw-r--r--src/python/src/grpc/framework/assembly/interfaces.py114
-rw-r--r--src/python/src/grpc/framework/assembly/utilities.py179
-rw-r--r--src/python/src/grpc/framework/base/_cancellation.py (renamed from src/python/src/grpc/framework/base/packets/_cancellation.py)8
-rw-r--r--src/python/src/grpc/framework/base/_constants.py (renamed from src/python/src/grpc/framework/base/packets/_constants.py)0
-rw-r--r--src/python/src/grpc/framework/base/_context.py (renamed from src/python/src/grpc/framework/base/packets/_context.py)20
-rw-r--r--src/python/src/grpc/framework/base/_emission.py (renamed from src/python/src/grpc/framework/base/packets/_emission.py)23
-rw-r--r--src/python/src/grpc/framework/base/_ends.py (renamed from src/python/src/grpc/framework/base/packets/_ends.py)90
-rw-r--r--src/python/src/grpc/framework/base/_expiration.py (renamed from src/python/src/grpc/framework/base/packets/_expiration.py)8
-rw-r--r--src/python/src/grpc/framework/base/_ingestion.py (renamed from src/python/src/grpc/framework/base/packets/_ingestion.py)45
-rw-r--r--src/python/src/grpc/framework/base/_interfaces.py (renamed from src/python/src/grpc/framework/base/packets/_interfaces.py)23
-rw-r--r--src/python/src/grpc/framework/base/_reception.py (renamed from src/python/src/grpc/framework/base/packets/_reception.py)251
-rw-r--r--src/python/src/grpc/framework/base/_termination.py (renamed from src/python/src/grpc/framework/base/packets/_termination.py)52
-rw-r--r--src/python/src/grpc/framework/base/_transmission.py (renamed from src/python/src/grpc/framework/base/packets/_transmission.py)254
-rw-r--r--src/python/src/grpc/framework/base/implementations.py (renamed from src/python/src/grpc/framework/base/packets/implementations.py)46
-rw-r--r--src/python/src/grpc/framework/base/implementations_test.py (renamed from src/python/src/grpc/framework/base/packets/implementations_test.py)8
-rw-r--r--src/python/src/grpc/framework/base/in_memory.py (renamed from src/python/src/grpc/framework/base/packets/in_memory.py)6
-rw-r--r--src/python/src/grpc/framework/base/interfaces.py131
-rw-r--r--src/python/src/grpc/framework/base/interfaces_test_case.py24
-rw-r--r--src/python/src/grpc/framework/base/null.py (renamed from src/python/src/grpc/framework/base/packets/null.py)2
-rw-r--r--src/python/src/grpc/framework/base/packets/interfaces.py84
-rw-r--r--src/python/src/grpc/framework/base/packets/packets.py111
-rw-r--r--src/python/src/grpc/framework/face/_service.py18
-rw-r--r--src/python/src/grpc/framework/face/_test_case.py30
-rw-r--r--src/python/src/grpc/framework/face/demonstration.py6
-rw-r--r--src/python/src/grpc/framework/face/implementations.py268
-rw-r--r--src/python/src/grpc/framework/face/interfaces.py462
-rw-r--r--src/python/src/grpc/framework/face/testing/base_util.py10
-rw-r--r--src/python/src/grpc/framework/face/testing/blocking_invocation_inline_service_test_case.py16
-rw-r--r--src/python/src/grpc/framework/face/testing/digest.py122
-rw-r--r--src/python/src/grpc/framework/face/testing/event_invocation_synchronous_event_service_test_case.py9
-rw-r--r--src/python/src/grpc/framework/face/testing/future_invocation_asynchronous_event_service_test_case.py17
-rw-r--r--src/python/src/grpc/framework/face/testing/service.py38
-rw-r--r--src/python/src/grpc/framework/face/testing/stock_service.py8
-rw-r--r--src/python/src/grpc/framework/face/testing/test_case.py53
-rw-r--r--src/python/src/grpc/framework/face/utilities.py174
-rw-r--r--src/python/src/grpc/framework/foundation/_logging_pool_test.py2
-rw-r--r--src/python/src/setup.py9
-rwxr-xr-xsrc/ruby/Rakefile53
-rwxr-xr-xsrc/ruby/bin/interop/interop_client.rb2
-rw-r--r--src/ruby/lib/grpc/generic/active_call.rb4
-rw-r--r--src/ruby/lib/grpc/generic/rpc_desc.rb1
-rw-r--r--src/ruby/lib/grpc/generic/service.rb17
-rw-r--r--src/ruby/spec/generic/active_call_spec.rb8
-rw-r--r--src/ruby/spec/generic/client_stub_spec.rb18
-rw-r--r--src/ruby/spec/generic/rpc_desc_spec.rb4
-rw-r--r--src/ruby/spec/generic/rpc_server_spec.rb79
248 files changed, 6045 insertions, 7277 deletions
diff --git a/src/compiler/config.h b/src/compiler/config.h
new file mode 100644
index 0000000000..e81de8d6c8
--- /dev/null
+++ b/src/compiler/config.h
@@ -0,0 +1,90 @@
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef SRC_COMPILER_CONFIG_H
+#define SRC_COMPILER_CONFIG_H
+
+#include <grpc++/config.h>
+
+#ifndef GRPC_CUSTOM_DESCRIPTOR
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
+#define GRPC_CUSTOM_DESCRIPTOR ::google::protobuf::Descriptor
+#define GRPC_CUSTOM_FILEDESCRIPTOR ::google::protobuf::FileDescriptor
+#define GRPC_CUSTOM_METHODDESCRIPTOR ::google::protobuf::MethodDescriptor
+#define GRPC_CUSTOM_SERVICEDESCRIPTOR ::google::protobuf::ServiceDescriptor
+#endif
+
+#ifndef GRPC_CUSTOM_CODEGENERATOR
+#include <google/protobuf/compiler/code_generator.h>
+#define GRPC_CUSTOM_CODEGENERATOR ::google::protobuf::compiler::CodeGenerator
+#define GRPC_CUSTOM_GENERATORCONTEXT ::google::protobuf::compiler::GeneratorContext
+#endif
+
+#ifndef GRPC_CUSTOM_PRINTER
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
+#define GRPC_CUSTOM_PRINTER ::google::protobuf::io::Printer
+#define GRPC_CUSTOM_CODEDOUTPUTSTREAM ::google::protobuf::io::CodedOutputStream
+#define GRPC_CUSTOM_STRINGOUTPUTSTREAM ::google::protobuf::io::StringOutputStream
+#endif
+
+#ifndef GRPC_CUSTOM_PLUGINMAIN
+#include <google/protobuf/compiler/plugin.h>
+#define GRPC_CUSTOM_PLUGINMAIN ::google::protobuf::compiler::PluginMain
+#endif
+
+namespace grpc {
+namespace protobuf {
+typedef GRPC_CUSTOM_DESCRIPTOR Descriptor;
+typedef GRPC_CUSTOM_FILEDESCRIPTOR FileDescriptor;
+typedef GRPC_CUSTOM_METHODDESCRIPTOR MethodDescriptor;
+typedef GRPC_CUSTOM_SERVICEDESCRIPTOR ServiceDescriptor;
+namespace compiler {
+typedef GRPC_CUSTOM_CODEGENERATOR CodeGenerator;
+typedef GRPC_CUSTOM_GENERATORCONTEXT GeneratorContext;
+static inline int PluginMain(int argc, char* argv[],
+ const CodeGenerator* generator) {
+ return GRPC_CUSTOM_PLUGINMAIN(argc, argv, generator);
+}
+} // namespace compiler
+namespace io {
+typedef GRPC_CUSTOM_PRINTER Printer;
+typedef GRPC_CUSTOM_CODEDOUTPUTSTREAM CodedOutputStream;
+typedef GRPC_CUSTOM_STRINGOUTPUTSTREAM StringOutputStream;
+} // namespace io
+} // namespace protobuf
+} // namespace grpc
+
+#endif // SRC_COMPILER_CONFIG_H
diff --git a/src/compiler/cpp_generator.cc b/src/compiler/cpp_generator.cc
index eade70d533..0a84c73520 100644
--- a/src/compiler/cpp_generator.cc
+++ b/src/compiler/cpp_generator.cc
@@ -31,45 +31,42 @@
*
*/
-#include <string>
#include <map>
#include "src/compiler/cpp_generator.h"
-
#include "src/compiler/cpp_generator_helpers.h"
-#include <google/protobuf/descriptor.h>
-#include <google/protobuf/descriptor.pb.h>
-#include <google/protobuf/io/printer.h>
-#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
+
+#include "src/compiler/config.h"
+
#include <sstream>
namespace grpc_cpp_generator {
namespace {
template <class T>
-std::string as_string(T x) {
+grpc::string as_string(T x) {
std::ostringstream out;
out << x;
return out.str();
}
-bool NoStreaming(const google::protobuf::MethodDescriptor *method) {
+bool NoStreaming(const grpc::protobuf::MethodDescriptor *method) {
return !method->client_streaming() && !method->server_streaming();
}
-bool ClientOnlyStreaming(const google::protobuf::MethodDescriptor *method) {
+bool ClientOnlyStreaming(const grpc::protobuf::MethodDescriptor *method) {
return method->client_streaming() && !method->server_streaming();
}
-bool ServerOnlyStreaming(const google::protobuf::MethodDescriptor *method) {
+bool ServerOnlyStreaming(const grpc::protobuf::MethodDescriptor *method) {
return !method->client_streaming() && method->server_streaming();
}
-bool BidiStreaming(const google::protobuf::MethodDescriptor *method) {
+bool BidiStreaming(const grpc::protobuf::MethodDescriptor *method) {
return method->client_streaming() && method->server_streaming();
}
-bool HasUnaryCalls(const google::protobuf::FileDescriptor *file) {
+bool HasUnaryCalls(const grpc::protobuf::FileDescriptor *file) {
for (int i = 0; i < file->service_count(); i++) {
for (int j = 0; j < file->service(i)->method_count(); j++) {
if (NoStreaming(file->service(i)->method(j))) {
@@ -80,7 +77,7 @@ bool HasUnaryCalls(const google::protobuf::FileDescriptor *file) {
return false;
}
-bool HasClientOnlyStreaming(const google::protobuf::FileDescriptor *file) {
+bool HasClientOnlyStreaming(const grpc::protobuf::FileDescriptor *file) {
for (int i = 0; i < file->service_count(); i++) {
for (int j = 0; j < file->service(i)->method_count(); j++) {
if (ClientOnlyStreaming(file->service(i)->method(j))) {
@@ -91,7 +88,7 @@ bool HasClientOnlyStreaming(const google::protobuf::FileDescriptor *file) {
return false;
}
-bool HasServerOnlyStreaming(const google::protobuf::FileDescriptor *file) {
+bool HasServerOnlyStreaming(const grpc::protobuf::FileDescriptor *file) {
for (int i = 0; i < file->service_count(); i++) {
for (int j = 0; j < file->service(i)->method_count(); j++) {
if (ServerOnlyStreaming(file->service(i)->method(j))) {
@@ -102,7 +99,7 @@ bool HasServerOnlyStreaming(const google::protobuf::FileDescriptor *file) {
return false;
}
-bool HasBidiStreaming(const google::protobuf::FileDescriptor *file) {
+bool HasBidiStreaming(const grpc::protobuf::FileDescriptor *file) {
for (int i = 0; i < file->service_count(); i++) {
for (int j = 0; j < file->service(i)->method_count(); j++) {
if (BidiStreaming(file->service(i)->method(j))) {
@@ -114,8 +111,9 @@ bool HasBidiStreaming(const google::protobuf::FileDescriptor *file) {
}
} // namespace
-std::string GetHeaderIncludes(const google::protobuf::FileDescriptor *file) {
- std::string temp =
+grpc::string GetHeaderIncludes(const grpc::protobuf::FileDescriptor *file,
+ const Parameters &params) {
+ grpc::string temp =
"#include <grpc++/impl/internal_stub.h>\n"
"#include <grpc++/impl/service_type.h>\n"
"#include <grpc++/status.h>\n"
@@ -161,7 +159,7 @@ std::string GetHeaderIncludes(const google::protobuf::FileDescriptor *file) {
return temp;
}
-std::string GetSourceIncludes() {
+grpc::string GetSourceIncludes(const Parameters &param) {
return "#include <grpc++/async_unary_call.h>\n"
"#include <grpc++/channel_interface.h>\n"
"#include <grpc++/impl/client_unary_call.h>\n"
@@ -171,9 +169,9 @@ std::string GetSourceIncludes() {
"#include <grpc++/stream.h>\n";
}
-void PrintHeaderClientMethod(google::protobuf::io::Printer *printer,
- const google::protobuf::MethodDescriptor *method,
- std::map<std::string, std::string> *vars) {
+void PrintHeaderClientMethod(grpc::protobuf::io::Printer *printer,
+ const grpc::protobuf::MethodDescriptor *method,
+ std::map<grpc::string, grpc::string> *vars) {
(*vars)["Method"] = method->name();
(*vars)["Request"] =
grpc_cpp_generator::ClassName(method->input_type(), true);
@@ -223,9 +221,9 @@ void PrintHeaderClientMethod(google::protobuf::io::Printer *printer,
}
void PrintHeaderServerMethodSync(
- google::protobuf::io::Printer *printer,
- const google::protobuf::MethodDescriptor *method,
- std::map<std::string, std::string> *vars) {
+ grpc::protobuf::io::Printer *printer,
+ const grpc::protobuf::MethodDescriptor *method,
+ std::map<grpc::string, grpc::string> *vars) {
(*vars)["Method"] = method->name();
(*vars)["Request"] =
grpc_cpp_generator::ClassName(method->input_type(), true);
@@ -258,9 +256,9 @@ void PrintHeaderServerMethodSync(
}
void PrintHeaderServerMethodAsync(
- google::protobuf::io::Printer *printer,
- const google::protobuf::MethodDescriptor *method,
- std::map<std::string, std::string> *vars) {
+ grpc::protobuf::io::Printer *printer,
+ const grpc::protobuf::MethodDescriptor *method,
+ std::map<grpc::string, grpc::string> *vars) {
(*vars)["Method"] = method->name();
(*vars)["Request"] =
grpc_cpp_generator::ClassName(method->input_type(), true);
@@ -294,9 +292,9 @@ void PrintHeaderServerMethodAsync(
}
}
-void PrintHeaderService(google::protobuf::io::Printer *printer,
- const google::protobuf::ServiceDescriptor *service,
- std::map<std::string, std::string> *vars) {
+void PrintHeaderService(grpc::protobuf::io::Printer *printer,
+ const grpc::protobuf::ServiceDescriptor *service,
+ std::map<grpc::string, grpc::string> *vars) {
(*vars)["Service"] = service->name();
printer->Print(*vars,
@@ -356,22 +354,33 @@ void PrintHeaderService(google::protobuf::io::Printer *printer,
printer->Print("};\n");
}
-std::string GetHeaderServices(const google::protobuf::FileDescriptor *file) {
- std::string output;
- google::protobuf::io::StringOutputStream output_stream(&output);
- google::protobuf::io::Printer printer(&output_stream, '$');
- std::map<std::string, std::string> vars;
+grpc::string GetHeaderServices(const grpc::protobuf::FileDescriptor *file,
+ const Parameters &params) {
+ grpc::string output;
+ grpc::protobuf::io::StringOutputStream output_stream(&output);
+ grpc::protobuf::io::Printer printer(&output_stream, '$');
+ std::map<grpc::string, grpc::string> vars;
+
+ if (!params.services_namespace.empty()) {
+ vars["services_namespace"] = params.services_namespace;
+ printer.Print(vars, "\nnamespace $services_namespace$ {\n\n");
+ }
for (int i = 0; i < file->service_count(); ++i) {
PrintHeaderService(&printer, file->service(i), &vars);
printer.Print("\n");
}
+
+ if (!params.services_namespace.empty()) {
+ printer.Print(vars, "} // namespace $services_namespace$\n\n");
+ }
+
return output;
}
-void PrintSourceClientMethod(google::protobuf::io::Printer *printer,
- const google::protobuf::MethodDescriptor *method,
- std::map<std::string, std::string> *vars) {
+void PrintSourceClientMethod(grpc::protobuf::io::Printer *printer,
+ const grpc::protobuf::MethodDescriptor *method,
+ std::map<grpc::string, grpc::string> *vars) {
(*vars)["Method"] = method->name();
(*vars)["Request"] =
grpc_cpp_generator::ClassName(method->input_type(), true);
@@ -379,18 +388,18 @@ void PrintSourceClientMethod(google::protobuf::io::Printer *printer,
grpc_cpp_generator::ClassName(method->output_type(), true);
if (NoStreaming(method)) {
printer->Print(*vars,
- "::grpc::Status $Service$::Stub::$Method$("
+ "::grpc::Status $ns$$Service$::Stub::$Method$("
"::grpc::ClientContext* context, "
"const $Request$& request, $Response$* response) {\n");
printer->Print(*vars,
" return ::grpc::BlockingUnaryCall(channel(),"
- "::grpc::RpcMethod($Service$_method_names[$Idx$]), "
+ "::grpc::RpcMethod($prefix$$Service$_method_names[$Idx$]), "
"context, request, response);\n"
"}\n\n");
printer->Print(
*vars,
"std::unique_ptr< ::grpc::ClientAsyncResponseReader< $Response$>> "
- "$Service$::Stub::Async$Method$(::grpc::ClientContext* context, "
+ "$ns$$Service$::Stub::Async$Method$(::grpc::ClientContext* context, "
"const $Request$& request, "
"::grpc::CompletionQueue* cq, void* tag) {\n");
printer->Print(*vars,
@@ -398,32 +407,32 @@ void PrintSourceClientMethod(google::protobuf::io::Printer *printer,
"::grpc::ClientAsyncResponseReader< $Response$>>(new "
"::grpc::ClientAsyncResponseReader< $Response$>("
"channel(), cq, "
- "::grpc::RpcMethod($Service$_method_names[$Idx$]), "
+ "::grpc::RpcMethod($prefix$$Service$_method_names[$Idx$]), "
"context, request, tag));\n"
"}\n\n");
} else if (ClientOnlyStreaming(method)) {
printer->Print(*vars,
"std::unique_ptr< ::grpc::ClientWriter< $Request$>> "
- "$Service$::Stub::$Method$("
+ "$ns$$Service$::Stub::$Method$("
"::grpc::ClientContext* context, $Response$* response) {\n");
printer->Print(*vars,
" return std::unique_ptr< ::grpc::ClientWriter< "
"$Request$>>(new ::grpc::ClientWriter< $Request$>("
"channel(),"
- "::grpc::RpcMethod($Service$_method_names[$Idx$], "
+ "::grpc::RpcMethod($prefix$$Service$_method_names[$Idx$], "
"::grpc::RpcMethod::RpcType::CLIENT_STREAMING), "
"context, response));\n"
"}\n\n");
printer->Print(*vars,
"std::unique_ptr< ::grpc::ClientAsyncWriter< $Request$>> "
- "$Service$::Stub::Async$Method$("
+ "$ns$$Service$::Stub::Async$Method$("
"::grpc::ClientContext* context, $Response$* response, "
"::grpc::CompletionQueue* cq, void* tag) {\n");
printer->Print(*vars,
" return std::unique_ptr< ::grpc::ClientAsyncWriter< "
"$Request$>>(new ::grpc::ClientAsyncWriter< $Request$>("
"channel(), cq, "
- "::grpc::RpcMethod($Service$_method_names[$Idx$], "
+ "::grpc::RpcMethod($prefix$$Service$_method_names[$Idx$], "
"::grpc::RpcMethod::RpcType::CLIENT_STREAMING), "
"context, response, tag));\n"
"}\n\n");
@@ -431,26 +440,26 @@ void PrintSourceClientMethod(google::protobuf::io::Printer *printer,
printer->Print(
*vars,
"std::unique_ptr< ::grpc::ClientReader< $Response$>> "
- "$Service$::Stub::$Method$("
+ "$ns$$Service$::Stub::$Method$("
"::grpc::ClientContext* context, const $Request$& request) {\n");
printer->Print(*vars,
" return std::unique_ptr< ::grpc::ClientReader< "
"$Response$>>(new ::grpc::ClientReader< $Response$>("
"channel(),"
- "::grpc::RpcMethod($Service$_method_names[$Idx$], "
+ "::grpc::RpcMethod($prefix$$Service$_method_names[$Idx$], "
"::grpc::RpcMethod::RpcType::SERVER_STREAMING), "
"context, request));\n"
"}\n\n");
printer->Print(*vars,
"std::unique_ptr< ::grpc::ClientAsyncReader< $Response$>> "
- "$Service$::Stub::Async$Method$("
+ "$ns$$Service$::Stub::Async$Method$("
"::grpc::ClientContext* context, const $Request$& request, "
"::grpc::CompletionQueue* cq, void* tag) {\n");
printer->Print(*vars,
" return std::unique_ptr< ::grpc::ClientAsyncReader< "
"$Response$>>(new ::grpc::ClientAsyncReader< $Response$>("
"channel(), cq, "
- "::grpc::RpcMethod($Service$_method_names[$Idx$], "
+ "::grpc::RpcMethod($prefix$$Service$_method_names[$Idx$], "
"::grpc::RpcMethod::RpcType::SERVER_STREAMING), "
"context, request, tag));\n"
"}\n\n");
@@ -458,36 +467,36 @@ void PrintSourceClientMethod(google::protobuf::io::Printer *printer,
printer->Print(
*vars,
"std::unique_ptr< ::grpc::ClientReaderWriter< $Request$, $Response$>> "
- "$Service$::Stub::$Method$(::grpc::ClientContext* context) {\n");
+ "$ns$$Service$::Stub::$Method$(::grpc::ClientContext* context) {\n");
printer->Print(*vars,
" return std::unique_ptr< ::grpc::ClientReaderWriter< "
"$Request$, $Response$>>(new ::grpc::ClientReaderWriter< "
"$Request$, $Response$>("
"channel(),"
- "::grpc::RpcMethod($Service$_method_names[$Idx$], "
+ "::grpc::RpcMethod($prefix$$Service$_method_names[$Idx$], "
"::grpc::RpcMethod::RpcType::BIDI_STREAMING), "
"context));\n"
"}\n\n");
printer->Print(*vars,
"std::unique_ptr< ::grpc::ClientAsyncReaderWriter< "
"$Request$, $Response$>> "
- "$Service$::Stub::Async$Method$(::grpc::ClientContext* context, "
+ "$ns$$Service$::Stub::Async$Method$(::grpc::ClientContext* context, "
"::grpc::CompletionQueue* cq, void* tag) {\n");
printer->Print(*vars,
" return std::unique_ptr< ::grpc::ClientAsyncReaderWriter< "
"$Request$, $Response$>>(new "
"::grpc::ClientAsyncReaderWriter< $Request$, $Response$>("
"channel(), cq, "
- "::grpc::RpcMethod($Service$_method_names[$Idx$], "
+ "::grpc::RpcMethod($prefix$$Service$_method_names[$Idx$], "
"::grpc::RpcMethod::RpcType::BIDI_STREAMING), "
"context, tag));\n"
"}\n\n");
}
}
-void PrintSourceServerMethod(google::protobuf::io::Printer *printer,
- const google::protobuf::MethodDescriptor *method,
- std::map<std::string, std::string> *vars) {
+void PrintSourceServerMethod(grpc::protobuf::io::Printer *printer,
+ const grpc::protobuf::MethodDescriptor *method,
+ std::map<grpc::string, grpc::string> *vars) {
(*vars)["Method"] = method->name();
(*vars)["Request"] =
grpc_cpp_generator::ClassName(method->input_type(), true);
@@ -495,7 +504,7 @@ void PrintSourceServerMethod(google::protobuf::io::Printer *printer,
grpc_cpp_generator::ClassName(method->output_type(), true);
if (NoStreaming(method)) {
printer->Print(*vars,
- "::grpc::Status $Service$::Service::$Method$("
+ "::grpc::Status $ns$$Service$::Service::$Method$("
"::grpc::ServerContext* context, "
"const $Request$* request, $Response$* response) {\n");
printer->Print(
@@ -504,7 +513,7 @@ void PrintSourceServerMethod(google::protobuf::io::Printer *printer,
printer->Print("}\n\n");
} else if (ClientOnlyStreaming(method)) {
printer->Print(*vars,
- "::grpc::Status $Service$::Service::$Method$("
+ "::grpc::Status $ns$$Service$::Service::$Method$("
"::grpc::ServerContext* context, "
"::grpc::ServerReader< $Request$>* reader, "
"$Response$* response) {\n");
@@ -514,7 +523,7 @@ void PrintSourceServerMethod(google::protobuf::io::Printer *printer,
printer->Print("}\n\n");
} else if (ServerOnlyStreaming(method)) {
printer->Print(*vars,
- "::grpc::Status $Service$::Service::$Method$("
+ "::grpc::Status $ns$$Service$::Service::$Method$("
"::grpc::ServerContext* context, "
"const $Request$* request, "
"::grpc::ServerWriter< $Response$>* writer) {\n");
@@ -524,7 +533,7 @@ void PrintSourceServerMethod(google::protobuf::io::Printer *printer,
printer->Print("}\n\n");
} else if (BidiStreaming(method)) {
printer->Print(*vars,
- "::grpc::Status $Service$::Service::$Method$("
+ "::grpc::Status $ns$$Service$::Service::$Method$("
"::grpc::ServerContext* context, "
"::grpc::ServerReaderWriter< $Response$, $Request$>* "
"stream) {\n");
@@ -536,9 +545,9 @@ void PrintSourceServerMethod(google::protobuf::io::Printer *printer,
}
void PrintSourceServerAsyncMethod(
- google::protobuf::io::Printer *printer,
- const google::protobuf::MethodDescriptor *method,
- std::map<std::string, std::string> *vars) {
+ grpc::protobuf::io::Printer *printer,
+ const grpc::protobuf::MethodDescriptor *method,
+ std::map<grpc::string, grpc::string> *vars) {
(*vars)["Method"] = method->name();
(*vars)["Request"] =
grpc_cpp_generator::ClassName(method->input_type(), true);
@@ -546,7 +555,7 @@ void PrintSourceServerAsyncMethod(
grpc_cpp_generator::ClassName(method->output_type(), true);
if (NoStreaming(method)) {
printer->Print(*vars,
- "void $Service$::AsyncService::Request$Method$("
+ "void $ns$$Service$::AsyncService::Request$Method$("
"::grpc::ServerContext* context, "
"$Request$* request, "
"::grpc::ServerAsyncResponseWriter< $Response$>* response, "
@@ -557,7 +566,7 @@ void PrintSourceServerAsyncMethod(
printer->Print("}\n\n");
} else if (ClientOnlyStreaming(method)) {
printer->Print(*vars,
- "void $Service$::AsyncService::Request$Method$("
+ "void $ns$$Service$::AsyncService::Request$Method$("
"::grpc::ServerContext* context, "
"::grpc::ServerAsyncReader< $Response$, $Request$>* reader, "
"::grpc::CompletionQueue* cq, void* tag) {\n");
@@ -567,7 +576,7 @@ void PrintSourceServerAsyncMethod(
printer->Print("}\n\n");
} else if (ServerOnlyStreaming(method)) {
printer->Print(*vars,
- "void $Service$::AsyncService::Request$Method$("
+ "void $ns$$Service$::AsyncService::Request$Method$("
"::grpc::ServerContext* context, "
"$Request$* request, "
"::grpc::ServerAsyncWriter< $Response$>* writer, "
@@ -579,7 +588,7 @@ void PrintSourceServerAsyncMethod(
} else if (BidiStreaming(method)) {
printer->Print(
*vars,
- "void $Service$::AsyncService::Request$Method$("
+ "void $ns$$Service$::AsyncService::Request$Method$("
"::grpc::ServerContext* context, "
"::grpc::ServerAsyncReaderWriter< $Response$, $Request$>* stream, "
"::grpc::CompletionQueue* cq, void *tag) {\n");
@@ -590,12 +599,12 @@ void PrintSourceServerAsyncMethod(
}
}
-void PrintSourceService(google::protobuf::io::Printer *printer,
- const google::protobuf::ServiceDescriptor *service,
- std::map<std::string, std::string> *vars) {
+void PrintSourceService(grpc::protobuf::io::Printer *printer,
+ const grpc::protobuf::ServiceDescriptor *service,
+ std::map<grpc::string, grpc::string> *vars) {
(*vars)["Service"] = service->name();
- printer->Print(*vars, "static const char* $Service$_method_names[] = {\n");
+ printer->Print(*vars, "static const char* $prefix$$Service$_method_names[] = {\n");
for (int i = 0; i < service->method_count(); ++i) {
(*vars)["Method"] = service->method(i)->name();
printer->Print(*vars, " \"/$Package$$Service$/$Method$\",\n");
@@ -604,9 +613,9 @@ void PrintSourceService(google::protobuf::io::Printer *printer,
printer->Print(
*vars,
- "std::unique_ptr< $Service$::Stub> $Service$::NewStub("
+ "std::unique_ptr< $ns$$Service$::Stub> $ns$$Service$::NewStub("
"const std::shared_ptr< ::grpc::ChannelInterface>& channel) {\n"
- " std::unique_ptr< $Service$::Stub> stub(new $Service$::Stub());\n"
+ " std::unique_ptr< $ns$$Service$::Stub> stub(new $ns$$Service$::Stub());\n"
" stub->set_channel(channel);\n"
" return stub;\n"
"}\n\n");
@@ -618,12 +627,12 @@ void PrintSourceService(google::protobuf::io::Printer *printer,
(*vars)["MethodCount"] = as_string(service->method_count());
printer->Print(
*vars,
- "$Service$::AsyncService::AsyncService(::grpc::CompletionQueue* cq) : "
- "::grpc::AsynchronousService(cq, $Service$_method_names, $MethodCount$) "
+ "$ns$$Service$::AsyncService::AsyncService(::grpc::CompletionQueue* cq) : "
+ "::grpc::AsynchronousService(cq, $prefix$$Service$_method_names, $MethodCount$) "
"{}\n\n");
printer->Print(*vars,
- "$Service$::Service::~Service() {\n"
+ "$ns$$Service$::Service::~Service() {\n"
" delete service_;\n"
"}\n\n");
for (int i = 0; i < service->method_count(); ++i) {
@@ -632,7 +641,7 @@ void PrintSourceService(google::protobuf::io::Printer *printer,
PrintSourceServerAsyncMethod(printer, service->method(i), vars);
}
printer->Print(*vars,
- "::grpc::RpcService* $Service$::Service::service() {\n");
+ "::grpc::RpcService* $ns$$Service$::Service::service() {\n");
printer->Indent();
printer->Print(
"if (service_ != nullptr) {\n"
@@ -640,7 +649,7 @@ void PrintSourceService(google::protobuf::io::Printer *printer,
"}\n");
printer->Print("service_ = new ::grpc::RpcService();\n");
for (int i = 0; i < service->method_count(); ++i) {
- const google::protobuf::MethodDescriptor *method = service->method(i);
+ const grpc::protobuf::MethodDescriptor *method = service->method(i);
(*vars)["Idx"] = as_string(i);
(*vars)["Method"] = method->name();
(*vars)["Request"] =
@@ -651,52 +660,52 @@ void PrintSourceService(google::protobuf::io::Printer *printer,
printer->Print(
*vars,
"service_->AddMethod(new ::grpc::RpcServiceMethod(\n"
- " $Service$_method_names[$Idx$],\n"
+ " $prefix$$Service$_method_names[$Idx$],\n"
" ::grpc::RpcMethod::NORMAL_RPC,\n"
- " new ::grpc::RpcMethodHandler< $Service$::Service, $Request$, "
+ " new ::grpc::RpcMethodHandler< $ns$$Service$::Service, $Request$, "
"$Response$>(\n"
- " std::function< ::grpc::Status($Service$::Service*, "
+ " std::function< ::grpc::Status($ns$$Service$::Service*, "
"::grpc::ServerContext*, const $Request$*, $Response$*)>("
- "&$Service$::Service::$Method$), this),\n"
+ "&$ns$$Service$::Service::$Method$), this),\n"
" new $Request$, new $Response$));\n");
} else if (ClientOnlyStreaming(method)) {
printer->Print(
*vars,
"service_->AddMethod(new ::grpc::RpcServiceMethod(\n"
- " $Service$_method_names[$Idx$],\n"
+ " $prefix$$Service$_method_names[$Idx$],\n"
" ::grpc::RpcMethod::CLIENT_STREAMING,\n"
" new ::grpc::ClientStreamingHandler< "
- "$Service$::Service, $Request$, $Response$>(\n"
- " std::function< ::grpc::Status($Service$::Service*, "
+ "$ns$$Service$::Service, $Request$, $Response$>(\n"
+ " std::function< ::grpc::Status($ns$$Service$::Service*, "
"::grpc::ServerContext*, "
"::grpc::ServerReader< $Request$>*, $Response$*)>("
- "&$Service$::Service::$Method$), this),\n"
+ "&$ns$$Service$::Service::$Method$), this),\n"
" new $Request$, new $Response$));\n");
} else if (ServerOnlyStreaming(method)) {
printer->Print(
*vars,
"service_->AddMethod(new ::grpc::RpcServiceMethod(\n"
- " $Service$_method_names[$Idx$],\n"
+ " $prefix$$Service$_method_names[$Idx$],\n"
" ::grpc::RpcMethod::SERVER_STREAMING,\n"
" new ::grpc::ServerStreamingHandler< "
- "$Service$::Service, $Request$, $Response$>(\n"
- " std::function< ::grpc::Status($Service$::Service*, "
+ "$ns$$Service$::Service, $Request$, $Response$>(\n"
+ " std::function< ::grpc::Status($ns$$Service$::Service*, "
"::grpc::ServerContext*, "
"const $Request$*, ::grpc::ServerWriter< $Response$>*)>("
- "&$Service$::Service::$Method$), this),\n"
+ "&$ns$$Service$::Service::$Method$), this),\n"
" new $Request$, new $Response$));\n");
} else if (BidiStreaming(method)) {
printer->Print(
*vars,
"service_->AddMethod(new ::grpc::RpcServiceMethod(\n"
- " $Service$_method_names[$Idx$],\n"
+ " $prefix$$Service$_method_names[$Idx$],\n"
" ::grpc::RpcMethod::BIDI_STREAMING,\n"
" new ::grpc::BidiStreamingHandler< "
- "$Service$::Service, $Request$, $Response$>(\n"
- " std::function< ::grpc::Status($Service$::Service*, "
+ "$ns$$Service$::Service, $Request$, $Response$>(\n"
+ " std::function< ::grpc::Status($ns$$Service$::Service*, "
"::grpc::ServerContext*, "
"::grpc::ServerReaderWriter< $Response$, $Request$>*)>("
- "&$Service$::Service::$Method$), this),\n"
+ "&$ns$$Service$::Service::$Method$), this),\n"
" new $Request$, new $Response$));\n");
}
}
@@ -705,17 +714,25 @@ void PrintSourceService(google::protobuf::io::Printer *printer,
printer->Print("}\n\n");
}
-std::string GetSourceServices(const google::protobuf::FileDescriptor *file) {
- std::string output;
- google::protobuf::io::StringOutputStream output_stream(&output);
- google::protobuf::io::Printer printer(&output_stream, '$');
- std::map<std::string, std::string> vars;
+grpc::string GetSourceServices(const grpc::protobuf::FileDescriptor *file,
+ const Parameters &params) {
+ grpc::string output;
+ grpc::protobuf::io::StringOutputStream output_stream(&output);
+ grpc::protobuf::io::Printer printer(&output_stream, '$');
+ std::map<grpc::string, grpc::string> vars;
// Package string is empty or ends with a dot. It is used to fully qualify
// method names.
vars["Package"] = file->package();
if (!file->package().empty()) {
vars["Package"].append(".");
}
+ if (!params.services_namespace.empty()) {
+ vars["ns"] = params.services_namespace + "::";
+ vars["prefix"] = params.services_namespace;
+ } else {
+ vars["ns"] = "";
+ vars["prefix"] = "";
+ }
for (int i = 0; i < file->service_count(); ++i) {
PrintSourceService(&printer, file->service(i), &vars);
diff --git a/src/compiler/cpp_generator.h b/src/compiler/cpp_generator.h
index 1bfe5a8819..04ad71c067 100644
--- a/src/compiler/cpp_generator.h
+++ b/src/compiler/cpp_generator.h
@@ -34,27 +34,30 @@
#ifndef GRPC_INTERNAL_COMPILER_CPP_GENERATOR_H
#define GRPC_INTERNAL_COMPILER_CPP_GENERATOR_H
-#include <string>
-
-namespace google {
-namespace protobuf {
-class FileDescriptor;
-} // namespace protobuf
-} // namespace google
+#include "src/compiler/config.h"
namespace grpc_cpp_generator {
+// Contains all the parameters that are parsed from the command line.
+struct Parameters {
+ // Puts the service into a namespace
+ grpc::string services_namespace;
+};
+
// Return the includes needed for generated header file.
-std::string GetHeaderIncludes(const google::protobuf::FileDescriptor *file);
+grpc::string GetHeaderIncludes(const grpc::protobuf::FileDescriptor *file,
+ const Parameters &params);
// Return the includes needed for generated source file.
-std::string GetSourceIncludes();
+grpc::string GetSourceIncludes(const Parameters &params);
// Return the services for generated header file.
-std::string GetHeaderServices(const google::protobuf::FileDescriptor *file);
+grpc::string GetHeaderServices(const grpc::protobuf::FileDescriptor *file,
+ const Parameters &params);
// Return the services for generated source file.
-std::string GetSourceServices(const google::protobuf::FileDescriptor *file);
+grpc::string GetSourceServices(const grpc::protobuf::FileDescriptor *file,
+ const Parameters &params);
} // namespace grpc_cpp_generator
diff --git a/src/compiler/cpp_generator_helpers.h b/src/compiler/cpp_generator_helpers.h
index 16abbde8d4..be68cbe695 100644
--- a/src/compiler/cpp_generator_helpers.h
+++ b/src/compiler/cpp_generator_helpers.h
@@ -35,30 +35,28 @@
#define GRPC_INTERNAL_COMPILER_CPP_GENERATOR_HELPERS_H
#include <map>
-#include <string>
-#include <google/protobuf/descriptor.h>
-#include <google/protobuf/descriptor.pb.h>
+#include "src/compiler/config.h"
#include "src/compiler/generator_helpers.h"
namespace grpc_cpp_generator {
-inline std::string DotsToColons(const std::string &name) {
+inline grpc::string DotsToColons(const grpc::string &name) {
return grpc_generator::StringReplace(name, ".", "::");
}
-inline std::string DotsToUnderscores(const std::string &name) {
+inline grpc::string DotsToUnderscores(const grpc::string &name) {
return grpc_generator::StringReplace(name, ".", "_");
}
-inline std::string ClassName(const google::protobuf::Descriptor *descriptor,
- bool qualified) {
+inline grpc::string ClassName(const grpc::protobuf::Descriptor *descriptor,
+ bool qualified) {
// Find "outer", the descriptor of the top-level message in which
// "descriptor" is embedded.
- const google::protobuf::Descriptor *outer = descriptor;
+ const grpc::protobuf::Descriptor *outer = descriptor;
while (outer->containing_type() != NULL) outer = outer->containing_type();
- const std::string &outer_name = outer->full_name();
- std::string inner_name = descriptor->full_name().substr(outer_name.size());
+ const grpc::string &outer_name = outer->full_name();
+ grpc::string inner_name = descriptor->full_name().substr(outer_name.size());
if (qualified) {
return "::" + DotsToColons(outer_name) + DotsToUnderscores(inner_name);
diff --git a/src/compiler/cpp_plugin.cc b/src/compiler/cpp_plugin.cc
index feb158f89e..57f25a1f75 100644
--- a/src/compiler/cpp_plugin.cc
+++ b/src/compiler/cpp_plugin.cc
@@ -35,26 +35,21 @@
//
#include <memory>
-#include <string>
+
+#include "src/compiler/config.h"
#include "src/compiler/cpp_generator.h"
#include "src/compiler/cpp_generator_helpers.h"
-#include <google/protobuf/descriptor.h>
-#include <google/protobuf/descriptor.pb.h>
-#include <google/protobuf/compiler/code_generator.h>
-#include <google/protobuf/compiler/plugin.h>
-#include <google/protobuf/io/coded_stream.h>
-#include <google/protobuf/io/zero_copy_stream.h>
-class CppGrpcGenerator : public google::protobuf::compiler::CodeGenerator {
+class CppGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator {
public:
CppGrpcGenerator() {}
virtual ~CppGrpcGenerator() {}
- virtual bool Generate(const google::protobuf::FileDescriptor *file,
- const std::string &parameter,
- google::protobuf::compiler::GeneratorContext *context,
- std::string *error) const {
+ virtual bool Generate(const grpc::protobuf::FileDescriptor *file,
+ const grpc::string &parameter,
+ grpc::protobuf::compiler::GeneratorContext *context,
+ grpc::string *error) const {
if (file->options().cc_generic_services()) {
*error =
"cpp grpc proto compiler plugin does not work with generic "
@@ -63,35 +58,54 @@ class CppGrpcGenerator : public google::protobuf::compiler::CodeGenerator {
return false;
}
- std::string file_name = grpc_generator::StripProto(file->name());
+ grpc_cpp_generator::Parameters generator_parameters;
+
+ if (!parameter.empty()) {
+ std::vector<grpc::string> parameters_list =
+ grpc_generator::tokenize(parameter, ",");
+ for (auto parameter_string = parameters_list.begin();
+ parameter_string != parameters_list.end();
+ parameter_string++) {
+ std::vector<grpc::string> param =
+ grpc_generator::tokenize(*parameter_string, "=");
+ if (param[0] == "services_namespace") {
+ generator_parameters.services_namespace = param[1];
+ } else {
+ *error = grpc::string("Unknown parameter: ") + *parameter_string;
+ return false;
+ }
+ }
+ }
+
+ grpc::string file_name = grpc_generator::StripProto(file->name());
// Generate .pb.h
Insert(context, file_name + ".pb.h", "includes",
- grpc_cpp_generator::GetHeaderIncludes(file));
+ grpc_cpp_generator::GetHeaderIncludes(file, generator_parameters));
Insert(context, file_name + ".pb.h", "namespace_scope",
- grpc_cpp_generator::GetHeaderServices(file));
+ grpc_cpp_generator::GetHeaderServices(file, generator_parameters));
// Generate .pb.cc
Insert(context, file_name + ".pb.cc", "includes",
- grpc_cpp_generator::GetSourceIncludes());
+ grpc_cpp_generator::GetSourceIncludes(generator_parameters));
Insert(context, file_name + ".pb.cc", "namespace_scope",
- grpc_cpp_generator::GetSourceServices(file));
+ grpc_cpp_generator::GetSourceServices(file, generator_parameters));
return true;
}
private:
// Insert the given code into the given file at the given insertion point.
- void Insert(google::protobuf::compiler::GeneratorContext *context,
- const std::string &filename, const std::string &insertion_point,
- const std::string &code) const {
- std::unique_ptr<google::protobuf::io::ZeroCopyOutputStream> output(
+ void Insert(grpc::protobuf::compiler::GeneratorContext *context,
+ const grpc::string &filename, const grpc::string &insertion_point,
+ const grpc::string &code) const {
+ std::unique_ptr<grpc::protobuf::io::ZeroCopyOutputStream> output(
context->OpenForInsert(filename, insertion_point));
- google::protobuf::io::CodedOutputStream coded_out(output.get());
+ grpc::protobuf::io::CodedOutputStream coded_out(output.get());
coded_out.WriteRaw(code.data(), code.size());
}
};
int main(int argc, char *argv[]) {
CppGrpcGenerator generator;
- return google::protobuf::compiler::PluginMain(argc, argv, &generator);
+ return grpc::protobuf::compiler::PluginMain(argc, argv, &generator);
}
diff --git a/src/compiler/generator_helpers.h b/src/compiler/generator_helpers.h
index 2035820f0d..30857891c7 100644
--- a/src/compiler/generator_helpers.h
+++ b/src/compiler/generator_helpers.h
@@ -35,14 +35,15 @@
#define GRPC_INTERNAL_COMPILER_GENERATOR_HELPERS_H
#include <map>
-#include <string>
+
+#include "src/compiler/config.h"
namespace grpc_generator {
-inline bool StripSuffix(std::string *filename, const std::string &suffix) {
+inline bool StripSuffix(grpc::string *filename, const grpc::string &suffix) {
if (filename->length() >= suffix.length()) {
size_t suffix_pos = filename->length() - suffix.length();
- if (filename->compare(suffix_pos, std::string::npos, suffix) == 0) {
+ if (filename->compare(suffix_pos, grpc::string::npos, suffix) == 0) {
filename->resize(filename->size() - suffix.size());
return true;
}
@@ -51,20 +52,20 @@ inline bool StripSuffix(std::string *filename, const std::string &suffix) {
return false;
}
-inline std::string StripProto(std::string filename) {
+inline grpc::string StripProto(grpc::string filename) {
if (!StripSuffix(&filename, ".protodevel")) {
StripSuffix(&filename, ".proto");
}
return filename;
}
-inline std::string StringReplace(std::string str, const std::string &from,
- const std::string &to) {
+inline grpc::string StringReplace(grpc::string str, const grpc::string &from,
+ const grpc::string &to) {
size_t pos = 0;
for (;;) {
pos = str.find(from, pos);
- if (pos == std::string::npos) {
+ if (pos == grpc::string::npos) {
break;
}
str.replace(pos, from.length(), to);
@@ -74,6 +75,26 @@ inline std::string StringReplace(std::string str, const std::string &from,
return str;
}
+inline std::vector<grpc::string> tokenize(const grpc::string &input,
+ const grpc::string &delimiters) {
+ std::vector<grpc::string> tokens;
+ size_t pos, last_pos = 0;
+
+ for (;;) {
+ bool done = false;
+ pos = input.find_first_of(delimiters, last_pos);
+ if (pos == grpc::string::npos) {
+ done = true;
+ pos = input.length();
+ }
+
+ tokens.push_back(input.substr(last_pos, pos - last_pos));
+ if (done) return tokens;
+
+ last_pos = pos + 1;
+ }
+}
+
} // namespace grpc_generator
#endif // GRPC_INTERNAL_COMPILER_GENERATOR_HELPERS_H
diff --git a/src/compiler/python_generator.cc b/src/compiler/python_generator.cc
index b217c0d911..748417e477 100644
--- a/src/compiler/python_generator.cc
+++ b/src/compiler/python_generator.cc
@@ -36,35 +36,71 @@
#include <cctype>
#include <cstring>
#include <map>
+#include <memory>
#include <ostream>
#include <sstream>
+#include <tuple>
#include <vector>
+#include "grpc++/config.h"
+#include "src/compiler/config.h"
#include "src/compiler/generator_helpers.h"
#include "src/compiler/python_generator.h"
-#include <google/protobuf/io/printer.h>
-#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
-#include <google/protobuf/descriptor.pb.h>
-#include <google/protobuf/descriptor.h>
using grpc_generator::StringReplace;
using grpc_generator::StripProto;
-using google::protobuf::Descriptor;
-using google::protobuf::FileDescriptor;
-using google::protobuf::MethodDescriptor;
-using google::protobuf::ServiceDescriptor;
-using google::protobuf::io::Printer;
-using google::protobuf::io::StringOutputStream;
+using grpc::protobuf::Descriptor;
+using grpc::protobuf::FileDescriptor;
+using grpc::protobuf::MethodDescriptor;
+using grpc::protobuf::ServiceDescriptor;
+using grpc::protobuf::compiler::GeneratorContext;
+using grpc::protobuf::io::CodedOutputStream;
+using grpc::protobuf::io::Printer;
+using grpc::protobuf::io::StringOutputStream;
+using grpc::protobuf::io::ZeroCopyOutputStream;
using std::initializer_list;
using std::make_pair;
using std::map;
using std::pair;
using std::replace;
-using std::string;
-using std::strlen;
using std::vector;
namespace grpc_python_generator {
+
+PythonGrpcGenerator::PythonGrpcGenerator(const GeneratorConfiguration& config)
+ : config_(config) {}
+
+PythonGrpcGenerator::~PythonGrpcGenerator() {}
+
+bool PythonGrpcGenerator::Generate(
+ const FileDescriptor* file, const grpc::string& parameter,
+ GeneratorContext* context, grpc::string* error) const {
+ // Get output file name.
+ grpc::string file_name;
+ static const int proto_suffix_length = strlen(".proto");
+ if (file->name().size() > static_cast<size_t>(proto_suffix_length) &&
+ file->name().find_last_of(".proto") == file->name().size() - 1) {
+ file_name = file->name().substr(
+ 0, file->name().size() - proto_suffix_length) + "_pb2.py";
+ } else {
+ *error = "Invalid proto file name. Proto file must end with .proto";
+ return false;
+ }
+
+ std::unique_ptr<ZeroCopyOutputStream> output(
+ context->OpenForInsert(file_name, "module_scope"));
+ CodedOutputStream coded_out(output.get());
+ bool success = false;
+ grpc::string code = "";
+ tie(success, code) = grpc_python_generator::GetServices(file, config_);
+ if (success) {
+ coded_out.WriteRaw(code.data(), code.size());
+ return true;
+ } else {
+ return false;
+ }
+}
+
namespace {
//////////////////////////////////
// BEGIN FORMATTING BOILERPLATE //
@@ -72,14 +108,15 @@ namespace {
// Converts an initializer list of the form { key0, value0, key1, value1, ... }
// into a map of key* to value*. Is merely a readability helper for later code.
-map<string, string> ListToDict(const initializer_list<string>& values) {
+map<grpc::string, grpc::string> ListToDict(
+ const initializer_list<grpc::string>& values) {
assert(values.size() % 2 == 0);
- map<string, string> value_map;
+ map<grpc::string, grpc::string> value_map;
auto value_iter = values.begin();
for (unsigned i = 0; i < values.size()/2; ++i) {
- string key = *value_iter;
+ grpc::string key = *value_iter;
++value_iter;
- string value = *value_iter;
+ grpc::string value = *value_iter;
value_map[key] = value;
++value_iter;
}
@@ -113,8 +150,8 @@ class IndentScope {
bool PrintServicer(const ServiceDescriptor* service,
Printer* out) {
- string doc = "<fill me in later!>";
- map<string, string> dict = ListToDict({
+ grpc::string doc = "<fill me in later!>";
+ map<grpc::string, grpc::string> dict = ListToDict({
"Service", service->name(),
"Documentation", doc,
});
@@ -125,7 +162,7 @@ bool PrintServicer(const ServiceDescriptor* service,
out->Print("__metaclass__ = abc.ABCMeta\n");
for (int i = 0; i < service->method_count(); ++i) {
auto meth = service->method(i);
- string arg_name = meth->client_streaming() ?
+ grpc::string arg_name = meth->client_streaming() ?
"request_iterator" : "request";
out->Print("@abc.abstractmethod\n");
out->Print("def $Method$(self, $ArgName$, context):\n",
@@ -140,8 +177,8 @@ bool PrintServicer(const ServiceDescriptor* service,
}
bool PrintServer(const ServiceDescriptor* service, Printer* out) {
- string doc = "<fill me in later!>";
- map<string, string> dict = ListToDict({
+ grpc::string doc = "<fill me in later!>";
+ map<grpc::string, grpc::string> dict = ListToDict({
"Service", service->name(),
"Documentation", doc,
});
@@ -169,8 +206,8 @@ bool PrintServer(const ServiceDescriptor* service, Printer* out) {
bool PrintStub(const ServiceDescriptor* service,
Printer* out) {
- string doc = "<fill me in later!>";
- map<string, string> dict = ListToDict({
+ grpc::string doc = "<fill me in later!>";
+ map<grpc::string, grpc::string> dict = ListToDict({
"Service", service->name(),
"Documentation", doc,
});
@@ -181,7 +218,7 @@ bool PrintStub(const ServiceDescriptor* service,
out->Print("__metaclass__ = abc.ABCMeta\n");
for (int i = 0; i < service->method_count(); ++i) {
const MethodDescriptor* meth = service->method(i);
- string arg_name = meth->client_streaming() ?
+ grpc::string arg_name = meth->client_streaming() ?
"request_iterator" : "request";
auto methdict = ListToDict({"Method", meth->name(), "ArgName", arg_name});
out->Print("@abc.abstractmethod\n");
@@ -198,29 +235,29 @@ bool PrintStub(const ServiceDescriptor* service,
// TODO(protobuf team): Export `ModuleName` from protobuf's
// `src/google/protobuf/compiler/python/python_generator.cc` file.
-string ModuleName(const string& filename) {
- string basename = StripProto(filename);
+grpc::string ModuleName(const grpc::string& filename) {
+ grpc::string basename = StripProto(filename);
basename = StringReplace(basename, "-", "_");
basename = StringReplace(basename, "/", ".");
return basename + "_pb2";
}
bool GetModuleAndMessagePath(const Descriptor* type,
- pair<string, string>* out) {
+ pair<grpc::string, grpc::string>* out) {
const Descriptor* path_elem_type = type;
vector<const Descriptor*> message_path;
do {
message_path.push_back(path_elem_type);
path_elem_type = path_elem_type->containing_type();
} while (path_elem_type != nullptr);
- string file_name = type->file()->name();
+ grpc::string file_name = type->file()->name();
static const int proto_suffix_length = strlen(".proto");
if (!(file_name.size() > static_cast<size_t>(proto_suffix_length) &&
file_name.find_last_of(".proto") == file_name.size() - 1)) {
return false;
}
- string module = ModuleName(file_name);
- string message_type;
+ grpc::string module = ModuleName(file_name);
+ grpc::string message_type;
for (auto path_iter = message_path.rbegin();
path_iter != message_path.rend(); ++path_iter) {
message_type += (*path_iter)->name() + ".";
@@ -231,27 +268,30 @@ bool GetModuleAndMessagePath(const Descriptor* type,
return true;
}
-bool PrintServerFactory(const ServiceDescriptor* service, Printer* out) {
+bool PrintServerFactory(const grpc::string& package_qualified_service_name,
+ const ServiceDescriptor* service, Printer* out) {
out->Print("def early_adopter_create_$Service$_server(servicer, port, "
"root_certificates, key_chain_pairs):\n",
"Service", service->name());
{
IndentScope raii_create_server_indent(out);
- map<string, string> method_description_constructors;
- map<string, pair<string, string>> input_message_modules_and_classes;
- map<string, pair<string, string>> output_message_modules_and_classes;
+ map<grpc::string, grpc::string> method_description_constructors;
+ map<grpc::string, pair<grpc::string, grpc::string>>
+ input_message_modules_and_classes;
+ map<grpc::string, pair<grpc::string, grpc::string>>
+ output_message_modules_and_classes;
for (int i = 0; i < service->method_count(); ++i) {
const MethodDescriptor* method = service->method(i);
- const string method_description_constructor =
- string(method->client_streaming() ? "stream_" : "unary_") +
- string(method->server_streaming() ? "stream_" : "unary_") +
+ const grpc::string method_description_constructor =
+ grpc::string(method->client_streaming() ? "stream_" : "unary_") +
+ grpc::string(method->server_streaming() ? "stream_" : "unary_") +
"service_description";
- pair<string, string> input_message_module_and_class;
+ pair<grpc::string, grpc::string> input_message_module_and_class;
if (!GetModuleAndMessagePath(method->input_type(),
&input_message_module_and_class)) {
return false;
}
- pair<string, string> output_message_module_and_class;
+ pair<grpc::string, grpc::string> output_message_module_and_class;
if (!GetModuleAndMessagePath(method->output_type(),
&output_message_module_and_class)) {
return false;
@@ -269,17 +309,20 @@ bool PrintServerFactory(const ServiceDescriptor* service, Printer* out) {
make_pair(method->name(), output_message_module_and_class));
}
out->Print("method_service_descriptions = {\n");
- for (auto& name_and_description_constructor :
- method_description_constructors) {
+ for (auto name_and_description_constructor =
+ method_description_constructors.begin();
+ name_and_description_constructor !=
+ method_description_constructors.end();
+ name_and_description_constructor++) {
IndentScope raii_descriptions_indent(out);
- const string method_name = name_and_description_constructor.first;
+ const grpc::string method_name = name_and_description_constructor->first;
auto input_message_module_and_class =
input_message_modules_and_classes.find(method_name);
auto output_message_module_and_class =
output_message_modules_and_classes.find(method_name);
out->Print("\"$Method$\": utilities.$Constructor$(\n", "Method",
method_name, "Constructor",
- name_and_description_constructor.second);
+ name_and_description_constructor->second);
{
IndentScope raii_description_arguments_indent(out);
out->Print("servicer.$Method$,\n", "Method", method_name);
@@ -295,38 +338,41 @@ bool PrintServerFactory(const ServiceDescriptor* service, Printer* out) {
out->Print("),\n");
}
out->Print("}\n");
- // out->Print("return implementations.insecure_server("
- // "method_service_descriptions, port)\n");
out->Print(
"return implementations.secure_server("
- "method_service_descriptions, port, root_certificates,"
- " key_chain_pairs)\n");
+ "\"$PackageQualifiedServiceName$\","
+ " method_service_descriptions, port, root_certificates,"
+ " key_chain_pairs)\n",
+ "PackageQualifiedServiceName", package_qualified_service_name);
}
return true;
}
-bool PrintStubFactory(const ServiceDescriptor* service, Printer* out) {
- map<string, string> dict = ListToDict({
+bool PrintStubFactory(const grpc::string& package_qualified_service_name,
+ const ServiceDescriptor* service, Printer* out) {
+ map<grpc::string, grpc::string> dict = ListToDict({
"Service", service->name(),
});
out->Print(dict, "def early_adopter_create_$Service$_stub(host, port):\n");
{
IndentScope raii_create_server_indent(out);
- map<string, string> method_description_constructors;
- map<string, pair<string, string>> input_message_modules_and_classes;
- map<string, pair<string, string>> output_message_modules_and_classes;
+ map<grpc::string, grpc::string> method_description_constructors;
+ map<grpc::string, pair<grpc::string, grpc::string>>
+ input_message_modules_and_classes;
+ map<grpc::string, pair<grpc::string, grpc::string>>
+ output_message_modules_and_classes;
for (int i = 0; i < service->method_count(); ++i) {
const MethodDescriptor* method = service->method(i);
- const string method_description_constructor =
- string(method->client_streaming() ? "stream_" : "unary_") +
- string(method->server_streaming() ? "stream_" : "unary_") +
+ const grpc::string method_description_constructor =
+ grpc::string(method->client_streaming() ? "stream_" : "unary_") +
+ grpc::string(method->server_streaming() ? "stream_" : "unary_") +
"invocation_description";
- pair<string, string> input_message_module_and_class;
+ pair<grpc::string, grpc::string> input_message_module_and_class;
if (!GetModuleAndMessagePath(method->input_type(),
&input_message_module_and_class)) {
return false;
}
- pair<string, string> output_message_module_and_class;
+ pair<grpc::string, grpc::string> output_message_module_and_class;
if (!GetModuleAndMessagePath(method->output_type(),
&output_message_module_and_class)) {
return false;
@@ -344,17 +390,20 @@ bool PrintStubFactory(const ServiceDescriptor* service, Printer* out) {
make_pair(method->name(), output_message_module_and_class));
}
out->Print("method_invocation_descriptions = {\n");
- for (auto& name_and_description_constructor :
- method_description_constructors) {
+ for (auto name_and_description_constructor =
+ method_description_constructors.begin();
+ name_and_description_constructor !=
+ method_description_constructors.end();
+ name_and_description_constructor++) {
IndentScope raii_descriptions_indent(out);
- const string method_name = name_and_description_constructor.first;
+ const grpc::string method_name = name_and_description_constructor->first;
auto input_message_module_and_class =
input_message_modules_and_classes.find(method_name);
auto output_message_module_and_class =
output_message_modules_and_classes.find(method_name);
out->Print("\"$Method$\": utilities.$Constructor$(\n", "Method",
method_name, "Constructor",
- name_and_description_constructor.second);
+ name_and_description_constructor->second);
{
IndentScope raii_description_arguments_indent(out);
out->Print(
@@ -371,36 +420,46 @@ bool PrintStubFactory(const ServiceDescriptor* service, Printer* out) {
out->Print("}\n");
out->Print(
"return implementations.insecure_stub("
- "method_invocation_descriptions, host, port)\n");
+ "\"$PackageQualifiedServiceName$\","
+ " method_invocation_descriptions, host, port)\n",
+ "PackageQualifiedServiceName", package_qualified_service_name);
}
return true;
}
-bool PrintPreamble(const FileDescriptor* file, Printer* out) {
+bool PrintPreamble(const FileDescriptor* file,
+ const GeneratorConfiguration& config, Printer* out) {
out->Print("import abc\n");
- out->Print("from grpc.early_adopter import implementations\n");
- out->Print("from grpc.early_adopter import utilities\n");
+ out->Print("from $Package$ import implementations\n",
+ "Package", config.implementations_package_root);
+ out->Print("from grpc.framework.alpha import utilities\n");
return true;
}
} // namespace
-pair<bool, string> GetServices(const FileDescriptor* file) {
- string output;
+pair<bool, grpc::string> GetServices(const FileDescriptor* file,
+ const GeneratorConfiguration& config) {
+ grpc::string output;
{
// Scope the output stream so it closes and finalizes output to the string.
StringOutputStream output_stream(&output);
Printer out(&output_stream, '$');
- if (!PrintPreamble(file, &out)) {
+ if (!PrintPreamble(file, config, &out)) {
return make_pair(false, "");
}
+ auto package = file->package();
+ if (!package.empty()) {
+ package = package.append(".");
+ }
for (int i = 0; i < file->service_count(); ++i) {
auto service = file->service(i);
+ auto package_qualified_service_name = package + service->name();
if (!(PrintServicer(service, &out) &&
PrintServer(service, &out) &&
PrintStub(service, &out) &&
- PrintServerFactory(service, &out) &&
- PrintStubFactory(service, &out))) {
+ PrintServerFactory(package_qualified_service_name, service, &out) &&
+ PrintStubFactory(package_qualified_service_name, service, &out))) {
return make_pair(false, "");
}
}
diff --git a/src/compiler/python_generator.h b/src/compiler/python_generator.h
index df29ca17e3..b47f3c1243 100644
--- a/src/compiler/python_generator.h
+++ b/src/compiler/python_generator.h
@@ -34,18 +34,34 @@
#ifndef GRPC_INTERNAL_COMPILER_PYTHON_GENERATOR_H
#define GRPC_INTERNAL_COMPILER_PYTHON_GENERATOR_H
-#include <string>
#include <utility>
-namespace google {
-namespace protobuf {
-class FileDescriptor;
-} // namespace protobuf
-} // namespace google
+#include "src/compiler/config.h"
namespace grpc_python_generator {
-std::pair<bool, std::string> GetServices(const google::protobuf::FileDescriptor* file);
+// Data pertaining to configuration of the generator with respect to anything
+// that may be used internally at Google.
+struct GeneratorConfiguration {
+ grpc::string implementations_package_root;
+};
+
+class PythonGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator {
+ public:
+ PythonGrpcGenerator(const GeneratorConfiguration& config);
+ ~PythonGrpcGenerator();
+
+ bool Generate(const grpc::protobuf::FileDescriptor* file,
+ const grpc::string& parameter,
+ grpc::protobuf::compiler::GeneratorContext* context,
+ grpc::string* error) const;
+ private:
+ GeneratorConfiguration config_;
+};
+
+std::pair<bool, grpc::string> GetServices(
+ const grpc::protobuf::FileDescriptor* file,
+ const GeneratorConfiguration& config);
} // namespace grpc_python_generator
diff --git a/src/compiler/python_plugin.cc b/src/compiler/python_plugin.cc
index 825f15a5c7..d1f49442da 100644
--- a/src/compiler/python_plugin.cc
+++ b/src/compiler/python_plugin.cc
@@ -33,62 +33,12 @@
// Generates a Python gRPC service interface out of Protobuf IDL.
-#include <cstring>
-#include <memory>
-#include <string>
-#include <tuple>
-
+#include "src/compiler/config.h"
#include "src/compiler/python_generator.h"
-#include <google/protobuf/compiler/code_generator.h>
-#include <google/protobuf/compiler/plugin.h>
-#include <google/protobuf/io/coded_stream.h>
-#include <google/protobuf/io/zero_copy_stream.h>
-#include <google/protobuf/descriptor.h>
-
-using google::protobuf::FileDescriptor;
-using google::protobuf::compiler::CodeGenerator;
-using google::protobuf::compiler::GeneratorContext;
-using google::protobuf::compiler::PluginMain;
-using google::protobuf::io::CodedOutputStream;
-using google::protobuf::io::ZeroCopyOutputStream;
-using std::string;
-using std::strlen;
-
-class PythonGrpcGenerator : public CodeGenerator {
- public:
- PythonGrpcGenerator() {}
- ~PythonGrpcGenerator() {}
-
- bool Generate(const FileDescriptor* file, const string& parameter,
- GeneratorContext* context, string* error) const {
- // Get output file name.
- string file_name;
- static const int proto_suffix_length = strlen(".proto");
- if (file->name().size() > static_cast<size_t>(proto_suffix_length) &&
- file->name().find_last_of(".proto") == file->name().size() - 1) {
- file_name = file->name().substr(
- 0, file->name().size() - proto_suffix_length) + "_pb2.py";
- } else {
- *error = "Invalid proto file name. Proto file must end with .proto";
- return false;
- }
-
- std::unique_ptr<ZeroCopyOutputStream> output(
- context->OpenForInsert(file_name, "module_scope"));
- CodedOutputStream coded_out(output.get());
- bool success = false;
- string code = "";
- tie(success, code) = grpc_python_generator::GetServices(file);
- if (success) {
- coded_out.WriteRaw(code.data(), code.size());
- return true;
- } else {
- return false;
- }
- }
-};
int main(int argc, char* argv[]) {
- PythonGrpcGenerator generator;
- return PluginMain(argc, argv, &generator);
+ grpc_python_generator::GeneratorConfiguration config;
+ config.implementations_package_root = "grpc.early_adopter";
+ grpc_python_generator::PythonGrpcGenerator generator(config);
+ return grpc::protobuf::compiler::PluginMain(argc, argv, &generator);
}
diff --git a/src/compiler/ruby_generator.cc b/src/compiler/ruby_generator.cc
index 32b6a8d8e4..a0bb92848b 100644
--- a/src/compiler/ruby_generator.cc
+++ b/src/compiler/ruby_generator.cc
@@ -32,24 +32,20 @@
*/
#include <cctype>
-#include <string>
#include <map>
#include <vector>
+#include "src/compiler/config.h"
#include "src/compiler/ruby_generator.h"
#include "src/compiler/ruby_generator_helpers-inl.h"
#include "src/compiler/ruby_generator_map-inl.h"
#include "src/compiler/ruby_generator_string-inl.h"
-#include <google/protobuf/io/printer.h>
-#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
-#include <google/protobuf/descriptor.pb.h>
-#include <google/protobuf/descriptor.h>
-
-using google::protobuf::FileDescriptor;
-using google::protobuf::ServiceDescriptor;
-using google::protobuf::MethodDescriptor;
-using google::protobuf::io::Printer;
-using google::protobuf::io::StringOutputStream;
+
+using grpc::protobuf::FileDescriptor;
+using grpc::protobuf::ServiceDescriptor;
+using grpc::protobuf::MethodDescriptor;
+using grpc::protobuf::io::Printer;
+using grpc::protobuf::io::StringOutputStream;
using std::map;
using std::vector;
@@ -57,38 +53,38 @@ namespace grpc_ruby_generator {
namespace {
// Prints out the method using the ruby gRPC DSL.
-void PrintMethod(const MethodDescriptor *method, const std::string &package,
+void PrintMethod(const MethodDescriptor *method, const grpc::string &package,
Printer *out) {
- std::string input_type = RubyTypeOf(method->input_type()->name(), package);
+ grpc::string input_type = RubyTypeOf(method->input_type()->name(), package);
if (method->client_streaming()) {
input_type = "stream(" + input_type + ")";
}
- std::string output_type = RubyTypeOf(method->output_type()->name(), package);
+ grpc::string output_type = RubyTypeOf(method->output_type()->name(), package);
if (method->server_streaming()) {
output_type = "stream(" + output_type + ")";
}
- std::map<std::string, std::string> method_vars =
+ std::map<grpc::string, grpc::string> method_vars =
ListToDict({"mth.name", method->name(), "input.type", input_type,
"output.type", output_type, });
out->Print(method_vars, "rpc :$mth.name$, $input.type$, $output.type$\n");
}
// Prints out the service using the ruby gRPC DSL.
-void PrintService(const ServiceDescriptor *service, const std::string &package,
+void PrintService(const ServiceDescriptor *service, const grpc::string &package,
Printer *out) {
if (service->method_count() == 0) {
return;
}
// Begin the service module
- std::map<std::string, std::string> module_vars =
+ std::map<grpc::string, grpc::string> module_vars =
ListToDict({"module.name", CapitalizeFirst(service->name()), });
out->Print(module_vars, "module $module.name$\n");
out->Indent();
// TODO(temiola): add documentation
- std::string doc = "TODO: add proto service documentation here";
- std::map<std::string, std::string> template_vars =
+ grpc::string doc = "TODO: add proto service documentation here";
+ std::map<grpc::string, grpc::string> template_vars =
ListToDict({"Documentation", doc, });
out->Print("\n");
out->Print(template_vars, "# $Documentation$\n");
@@ -101,7 +97,7 @@ void PrintService(const ServiceDescriptor *service, const std::string &package,
out->Print("\n");
out->Print("self.marshal_class_method = :encode\n");
out->Print("self.unmarshal_class_method = :decode\n");
- std::map<std::string, std::string> pkg_vars =
+ std::map<grpc::string, grpc::string> pkg_vars =
ListToDict({"service.name", service->name(), "pkg.name", package, });
out->Print(pkg_vars, "self.service_name = '$pkg.name$.$service.name$'\n");
out->Print("\n");
@@ -121,8 +117,8 @@ void PrintService(const ServiceDescriptor *service, const std::string &package,
} // namespace
-std::string GetServices(const FileDescriptor *file) {
- std::string output;
+grpc::string GetServices(const FileDescriptor *file) {
+ grpc::string output;
StringOutputStream output_stream(&output);
Printer out(&output_stream, '$');
@@ -133,7 +129,7 @@ std::string GetServices(const FileDescriptor *file) {
}
// Write out a file header.
- std::map<std::string, std::string> header_comment_vars = ListToDict(
+ std::map<grpc::string, grpc::string> header_comment_vars = ListToDict(
{"file.name", file->name(), "file.package", file->package(), });
out.Print("# Generated by the protocol buffer compiler. DO NOT EDIT!\n");
out.Print(header_comment_vars,
@@ -144,15 +140,15 @@ std::string GetServices(const FileDescriptor *file) {
// Write out require statemment to import the separately generated file
// that defines the messages used by the service. This is generated by the
// main ruby plugin.
- std::map<std::string, std::string> dep_vars =
+ std::map<grpc::string, grpc::string> dep_vars =
ListToDict({"dep.name", MessagesRequireName(file), });
out.Print(dep_vars, "require '$dep.name$'\n");
// Write out services within the modules
out.Print("\n");
- std::vector<std::string> modules = Split(file->package(), '.');
+ std::vector<grpc::string> modules = Split(file->package(), '.');
for (size_t i = 0; i < modules.size(); ++i) {
- std::map<std::string, std::string> module_vars =
+ std::map<grpc::string, grpc::string> module_vars =
ListToDict({"module.name", CapitalizeFirst(modules[i]), });
out.Print(module_vars, "module $module.name$\n");
out.Indent();
diff --git a/src/compiler/ruby_generator.h b/src/compiler/ruby_generator.h
index 4dd38e0c27..a2ab36d4d9 100644
--- a/src/compiler/ruby_generator.h
+++ b/src/compiler/ruby_generator.h
@@ -34,17 +34,11 @@
#ifndef GRPC_INTERNAL_COMPILER_RUBY_GENERATOR_H
#define GRPC_INTERNAL_COMPILER_RUBY_GENERATOR_H
-#include <string>
-
-namespace google {
-namespace protobuf {
-class FileDescriptor;
-} // namespace protobuf
-} // namespace google
+#include "src/compiler/config.h"
namespace grpc_ruby_generator {
-std::string GetServices(const google::protobuf::FileDescriptor *file);
+grpc::string GetServices(const grpc::protobuf::FileDescriptor *file);
} // namespace grpc_ruby_generator
diff --git a/src/compiler/ruby_generator_helpers-inl.h b/src/compiler/ruby_generator_helpers-inl.h
index f3a087b3f8..9da7cab3c7 100644
--- a/src/compiler/ruby_generator_helpers-inl.h
+++ b/src/compiler/ruby_generator_helpers-inl.h
@@ -34,15 +34,13 @@
#ifndef GRPC_INTERNAL_COMPILER_RUBY_GENERATOR_HELPERS_INL_H
#define GRPC_INTERNAL_COMPILER_RUBY_GENERATOR_HELPERS_INL_H
-#include <string>
-
-#include <google/protobuf/descriptor.h>
+#include "src/compiler/config.h"
#include "src/compiler/ruby_generator_string-inl.h"
namespace grpc_ruby_generator {
-inline bool ServicesFilename(const google::protobuf::FileDescriptor *file,
- std::string *file_name_or_error) {
+inline bool ServicesFilename(const grpc::protobuf::FileDescriptor *file,
+ grpc::string *file_name_or_error) {
// Get output file name.
static const unsigned proto_suffix_length = 6; // length of ".proto"
if (file->name().size() > proto_suffix_length &&
@@ -57,8 +55,8 @@ inline bool ServicesFilename(const google::protobuf::FileDescriptor *file,
}
}
-inline std::string MessagesRequireName(
- const google::protobuf::FileDescriptor *file) {
+inline grpc::string MessagesRequireName(
+ const grpc::protobuf::FileDescriptor *file) {
return Replace(file->name(), ".proto", "");
}
diff --git a/src/compiler/ruby_generator_map-inl.h b/src/compiler/ruby_generator_map-inl.h
index f902b6d98f..6b87774f21 100644
--- a/src/compiler/ruby_generator_map-inl.h
+++ b/src/compiler/ruby_generator_map-inl.h
@@ -34,11 +34,12 @@
#ifndef GRPC_INTERNAL_COMPILER_RUBY_GENERATOR_MAP_INL_H
#define GRPC_INTERNAL_COMPILER_RUBY_GENERATOR_MAP_INL_H
+#include "src/compiler/config.h"
+
#include <iostream>
#include <initializer_list>
#include <map>
#include <ostream> // NOLINT
-#include <string>
#include <vector>
using std::initializer_list;
@@ -49,18 +50,18 @@ namespace grpc_ruby_generator {
// Converts an initializer list of the form { key0, value0, key1, value1, ... }
// into a map of key* to value*. Is merely a readability helper for later code.
-inline std::map<std::string, std::string> ListToDict(
- const initializer_list<std::string> &values) {
+inline std::map<grpc::string, grpc::string> ListToDict(
+ const initializer_list<grpc::string> &values) {
if (values.size() % 2 != 0) {
std::cerr << "Not every 'key' has a value in `values`."
<< std::endl;
}
- std::map<std::string, std::string> value_map;
+ std::map<grpc::string, grpc::string> value_map;
auto value_iter = values.begin();
for (unsigned i = 0; i < values.size() / 2; ++i) {
- std::string key = *value_iter;
+ grpc::string key = *value_iter;
++value_iter;
- std::string value = *value_iter;
+ grpc::string value = *value_iter;
value_map[key] = value;
++value_iter;
}
diff --git a/src/compiler/ruby_generator_string-inl.h b/src/compiler/ruby_generator_string-inl.h
index bdd314c16e..8da3a88da2 100644
--- a/src/compiler/ruby_generator_string-inl.h
+++ b/src/compiler/ruby_generator_string-inl.h
@@ -34,8 +34,9 @@
#ifndef GRPC_INTERNAL_COMPILER_RUBY_GENERATOR_STRING_INL_H
#define GRPC_INTERNAL_COMPILER_RUBY_GENERATOR_STRING_INL_H
+#include "src/compiler/config.h"
+
#include <algorithm>
-#include <string>
#include <sstream>
#include <vector>
@@ -45,10 +46,10 @@ using std::transform;
namespace grpc_ruby_generator {
// Split splits a string using char into elems.
-inline std::vector<std::string> &Split(const std::string &s, char delim,
- std::vector<std::string> *elems) {
+inline std::vector<grpc::string> &Split(const grpc::string &s, char delim,
+ std::vector<grpc::string> *elems) {
std::stringstream ss(s);
- std::string item;
+ grpc::string item;
while (getline(ss, item, delim)) {
elems->push_back(item);
}
@@ -56,17 +57,17 @@ inline std::vector<std::string> &Split(const std::string &s, char delim,
}
// Split splits a string using char, returning the result in a vector.
-inline std::vector<std::string> Split(const std::string &s, char delim) {
- std::vector<std::string> elems;
+inline std::vector<grpc::string> Split(const grpc::string &s, char delim) {
+ std::vector<grpc::string> elems;
Split(s, delim, &elems);
return elems;
}
// Replace replaces from with to in s.
-inline std::string Replace(std::string s, const std::string &from,
- const std::string &to) {
+inline grpc::string Replace(grpc::string s, const grpc::string &from,
+ const grpc::string &to) {
size_t start_pos = s.find(from);
- if (start_pos == std::string::npos) {
+ if (start_pos == grpc::string::npos) {
return s;
}
s.replace(start_pos, from.length(), to);
@@ -74,10 +75,10 @@ inline std::string Replace(std::string s, const std::string &from,
}
// ReplaceAll replaces all instances of search with replace in s.
-inline std::string ReplaceAll(std::string s, const std::string &search,
- const std::string &replace) {
+inline grpc::string ReplaceAll(grpc::string s, const grpc::string &search,
+ const grpc::string &replace) {
size_t pos = 0;
- while ((pos = s.find(search, pos)) != std::string::npos) {
+ while ((pos = s.find(search, pos)) != grpc::string::npos) {
s.replace(pos, search.length(), replace);
pos += replace.length();
}
@@ -85,10 +86,10 @@ inline std::string ReplaceAll(std::string s, const std::string &search,
}
// ReplacePrefix replaces from with to in s if search is a prefix of s.
-inline bool ReplacePrefix(std::string *s, const std::string &from,
- const std::string &to) {
+inline bool ReplacePrefix(grpc::string *s, const grpc::string &from,
+ const grpc::string &to) {
size_t start_pos = s->find(from);
- if (start_pos == std::string::npos || start_pos != 0) {
+ if (start_pos == grpc::string::npos || start_pos != 0) {
return false;
}
s->replace(start_pos, from.length(), to);
@@ -96,7 +97,7 @@ inline bool ReplacePrefix(std::string *s, const std::string &from,
}
// CapitalizeFirst capitalizes the first char in a string.
-inline std::string CapitalizeFirst(std::string s) {
+inline grpc::string CapitalizeFirst(grpc::string s) {
if (s.empty()) {
return s;
}
@@ -105,15 +106,15 @@ inline std::string CapitalizeFirst(std::string s) {
}
// RubyTypeOf updates a proto type to the required ruby equivalent.
-inline std::string RubyTypeOf(const std::string &a_type,
- const std::string &package) {
- std::string res(a_type);
+inline grpc::string RubyTypeOf(const grpc::string &a_type,
+ const grpc::string &package) {
+ grpc::string res(a_type);
ReplacePrefix(&res, package, ""); // remove the leading package if present
ReplacePrefix(&res, ".", ""); // remove the leading . (no package)
- if (res.find('.') == std::string::npos) {
+ if (res.find('.') == grpc::string::npos) {
return res;
} else {
- std::vector<std::string> prefixes_and_type = Split(res, '.');
+ std::vector<grpc::string> prefixes_and_type = Split(res, '.');
for (unsigned int i = 0; i < prefixes_and_type.size(); ++i) {
if (i != 0) {
res += "::"; // switch '.' to the ruby module delim
diff --git a/src/compiler/ruby_plugin.cc b/src/compiler/ruby_plugin.cc
index 4a6e9f7a5d..bd10d46e9c 100644
--- a/src/compiler/ruby_plugin.cc
+++ b/src/compiler/ruby_plugin.cc
@@ -32,43 +32,35 @@
*/
// Generates Ruby gRPC service interface out of Protobuf IDL.
-//
-// This is a Proto2 compiler plugin. See net/proto2/compiler/proto/plugin.proto
-// and net/proto2/compiler/public/plugin.h for more information on plugins.
#include <memory>
-#include <string>
+#include "src/compiler/config.h"
#include "src/compiler/ruby_generator.h"
#include "src/compiler/ruby_generator_helpers-inl.h"
-#include <google/protobuf/compiler/code_generator.h>
-#include <google/protobuf/compiler/plugin.h>
-#include <google/protobuf/io/coded_stream.h>
-#include <google/protobuf/io/zero_copy_stream.h>
-#include <google/protobuf/descriptor.h>
-class RubyGrpcGenerator : public google::protobuf::compiler::CodeGenerator {
+class RubyGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator {
public:
RubyGrpcGenerator() {}
~RubyGrpcGenerator() {}
- bool Generate(const google::protobuf::FileDescriptor *file,
- const std::string &parameter,
- google::protobuf::compiler::GeneratorContext *context,
- std::string *error) const {
- std::string code = grpc_ruby_generator::GetServices(file);
+ bool Generate(const grpc::protobuf::FileDescriptor *file,
+ const grpc::string &parameter,
+ grpc::protobuf::compiler::GeneratorContext *context,
+ grpc::string *error) const {
+ grpc::string code = grpc_ruby_generator::GetServices(file);
if (code.size() == 0) {
return true; // don't generate a file if there are no services
}
// Get output file name.
- std::string file_name;
+ grpc::string file_name;
if (!grpc_ruby_generator::ServicesFilename(file, &file_name)) {
return false;
}
- std::unique_ptr<google::protobuf::io::ZeroCopyOutputStream> output(
+ std::unique_ptr<grpc::protobuf::io::ZeroCopyOutputStream> output(
context->Open(file_name));
- google::protobuf::io::CodedOutputStream coded_out(output.get());
+ grpc::protobuf::io::CodedOutputStream coded_out(output.get());
coded_out.WriteRaw(code.data(), code.size());
return true;
}
@@ -76,5 +68,5 @@ class RubyGrpcGenerator : public google::protobuf::compiler::CodeGenerator {
int main(int argc, char *argv[]) {
RubyGrpcGenerator generator;
- return google::protobuf::compiler::PluginMain(argc, argv, &generator);
+ return grpc::protobuf::compiler::PluginMain(argc, argv, &generator);
}
diff --git a/src/core/channel/http_server_filter.c b/src/core/channel/http_server_filter.c
index d1616a3450..f565cbf3ae 100644
--- a/src/core/channel/http_server_filter.c
+++ b/src/core/channel/http_server_filter.c
@@ -66,6 +66,10 @@ typedef struct channel_data {
grpc_mdelem *status_ok;
grpc_mdelem *status_not_found;
grpc_mdstr *path_key;
+ grpc_mdstr *authority_key;
+ grpc_mdstr *host_key;
+
+ grpc_mdctx *mdctx;
size_t gettable_count;
gettable *gettables;
@@ -181,6 +185,15 @@ static void call_op(grpc_call_element *elem, grpc_call_element *from_elem,
}
calld->path = op->data.metadata;
op->done_cb(op->user_data, GRPC_OP_OK);
+ } else if (op->data.metadata->key == channeld->host_key) {
+ /* translate host to :authority since :authority may be
+ omitted */
+ grpc_mdelem *authority = grpc_mdelem_from_metadata_strings(
+ channeld->mdctx, channeld->authority_key, op->data.metadata->value);
+ grpc_mdelem_unref(op->data.metadata);
+ op->data.metadata = authority;
+ /* pass the event up */
+ grpc_call_next_op(elem, op);
} else {
/* pass the event up */
grpc_call_next_op(elem, op);
@@ -305,9 +318,13 @@ static void init_channel_elem(grpc_channel_element *elem,
channeld->https_scheme = grpc_mdelem_from_strings(mdctx, ":scheme", "https");
channeld->grpc_scheme = grpc_mdelem_from_strings(mdctx, ":scheme", "grpc");
channeld->path_key = grpc_mdstr_from_string(mdctx, ":path");
+ channeld->authority_key = grpc_mdstr_from_string(mdctx, ":authority");
+ channeld->host_key = grpc_mdstr_from_string(mdctx, "host");
channeld->content_type =
grpc_mdelem_from_strings(mdctx, "content-type", "application/grpc");
+ channeld->mdctx = mdctx;
+
/* initialize http download support */
channeld->gettable_count = 0;
channeld->gettables = NULL;
@@ -357,6 +374,8 @@ static void destroy_channel_elem(grpc_channel_element *elem) {
grpc_mdelem_unref(channeld->grpc_scheme);
grpc_mdelem_unref(channeld->content_type);
grpc_mdstr_unref(channeld->path_key);
+ grpc_mdstr_unref(channeld->authority_key);
+ grpc_mdstr_unref(channeld->host_key);
}
const grpc_channel_filter grpc_http_server_filter = {
diff --git a/src/core/channel/metadata_buffer.c b/src/core/channel/metadata_buffer.c
index da66a028c4..eac852e4a4 100644
--- a/src/core/channel/metadata_buffer.c
+++ b/src/core/channel/metadata_buffer.c
@@ -147,54 +147,3 @@ void grpc_metadata_buffer_flush(grpc_metadata_buffer *buffer,
gpr_free(impl);
*buffer = NULL;
}
-
-size_t grpc_metadata_buffer_count(const grpc_metadata_buffer *buffer) {
- return *buffer ? (*buffer)->elems : 0;
-}
-
-typedef struct {
- grpc_metadata_buffer_impl *impl;
-} elems_hdr;
-
-grpc_metadata *grpc_metadata_buffer_extract_elements(
- grpc_metadata_buffer *buffer) {
- grpc_metadata_buffer_impl *impl;
- elems_hdr *hdr;
- qelem *src;
- grpc_metadata *out;
- size_t i;
-
- impl = *buffer;
-
- if (!impl) {
- return NULL;
- }
-
- hdr = gpr_malloc(sizeof(elems_hdr) + impl->elems * sizeof(grpc_metadata));
- src = ELEMS(impl);
- out = (grpc_metadata *)(hdr + 1);
-
- hdr->impl = impl;
- for (i = 0; i < impl->elems; i++) {
- out[i].key = (char *)grpc_mdstr_as_c_string(src[i].md->key);
- out[i].value = (char *)grpc_mdstr_as_c_string(src[i].md->value);
- out[i].value_length = GPR_SLICE_LENGTH(src[i].md->value->slice);
- }
-
- /* clear out buffer (it's not possible to extract elements twice */
- *buffer = NULL;
-
- return out;
-}
-
-void grpc_metadata_buffer_cleanup_elements(void *elements,
- grpc_op_error error) {
- elems_hdr *hdr = ((elems_hdr *)elements) - 1;
-
- if (!elements) {
- return;
- }
-
- grpc_metadata_buffer_destroy(&hdr->impl, error);
- gpr_free(hdr);
-}
diff --git a/src/core/iomgr/fd_posix.c b/src/core/iomgr/fd_posix.c
index abdd49bbda..9c8133d2d4 100644
--- a/src/core/iomgr/fd_posix.c
+++ b/src/core/iomgr/fd_posix.c
@@ -210,7 +210,7 @@ static void notify_on(grpc_fd *fd, gpr_atm *st, grpc_iomgr_closure *closure,
/* swap was unsuccessful due to an intervening set_ready call.
Fall through to the READY code below */
case READY:
- assert(gpr_atm_acq_load(st) == READY);
+ assert(gpr_atm_no_barrier_load(st) == READY);
gpr_atm_rel_store(st, NOT_READY);
make_callback(closure->cb, closure->cb_arg,
!gpr_atm_acq_load(&fd->shutdown),
@@ -245,8 +245,8 @@ static void set_ready_locked(gpr_atm *st, grpc_iomgr_closure *callbacks,
Fall through to the WAITING code below */
state = gpr_atm_acq_load(st);
default: /* waiting */
- assert(gpr_atm_acq_load(st) != READY &&
- gpr_atm_acq_load(st) != NOT_READY);
+ assert(gpr_atm_no_barrier_load(st) != READY &&
+ gpr_atm_no_barrier_load(st) != NOT_READY);
callbacks[(*ncallbacks)++] = *(grpc_iomgr_closure *)state;
gpr_atm_rel_store(st, NOT_READY);
return;
@@ -271,7 +271,7 @@ void grpc_fd_shutdown(grpc_fd *fd) {
grpc_iomgr_closure cb[2];
size_t ncb = 0;
gpr_mu_lock(&fd->set_state_mu);
- GPR_ASSERT(!gpr_atm_acq_load(&fd->shutdown));
+ GPR_ASSERT(!gpr_atm_no_barrier_load(&fd->shutdown));
gpr_atm_rel_store(&fd->shutdown, 1);
set_ready_locked(&fd->readst, cb, &ncb);
set_ready_locked(&fd->writest, cb, &ncb);
diff --git a/src/core/iomgr/iocp_windows.c b/src/core/iomgr/iocp_windows.c
index 8b019e8049..aec626509a 100644
--- a/src/core/iomgr/iocp_windows.c
+++ b/src/core/iomgr/iocp_windows.c
@@ -52,10 +52,11 @@ static OVERLAPPED g_iocp_custom_overlap;
static gpr_event g_shutdown_iocp;
static gpr_event g_iocp_done;
+static gpr_atm g_orphans = 0;
static HANDLE g_iocp;
-static int do_iocp_work() {
+static void do_iocp_work() {
BOOL success;
DWORD bytes = 0;
DWORD flags = 0;
@@ -71,14 +72,14 @@ static int do_iocp_work() {
gpr_time_to_millis(wait_time));
if (!success && !overlapped) {
/* The deadline got attained. */
- return 0;
+ return;
}
GPR_ASSERT(completion_key && overlapped);
if (overlapped == &g_iocp_custom_overlap) {
if (completion_key == (ULONG_PTR) &g_iocp_kick_token) {
/* We were awoken from a kick. */
gpr_log(GPR_DEBUG, "do_iocp_work - got a kick");
- return 1;
+ return;
}
gpr_log(GPR_ERROR, "Unknown custom completion key.");
abort();
@@ -97,8 +98,13 @@ static int do_iocp_work() {
}
success = WSAGetOverlappedResult(socket->socket, &info->overlapped, &bytes,
FALSE, &flags);
- gpr_log(GPR_DEBUG, "bytes: %u, flags: %u - op %s", bytes, flags,
- success ? "succeeded" : "failed");
+ gpr_log(GPR_DEBUG, "bytes: %u, flags: %u - op %s %s", bytes, flags,
+ success ? "succeeded" : "failed", socket->orphan ? "orphan" : "");
+ if (socket->orphan) {
+ grpc_winsocket_destroy(socket);
+ gpr_atm_full_fetch_add(&g_orphans, -1);
+ return;
+ }
info->bytes_transfered = bytes;
info->wsa_error = success ? 0 : WSAGetLastError();
GPR_ASSERT(overlapped == &info->overlapped);
@@ -113,12 +119,10 @@ static int do_iocp_work() {
}
gpr_mu_unlock(&socket->state_mu);
if (f) f(opaque, 1);
-
- return 1;
}
static void iocp_loop(void *p) {
- while (!gpr_event_get(&g_shutdown_iocp)) {
+ while (gpr_atm_acq_load(&g_orphans) || !gpr_event_get(&g_shutdown_iocp)) {
grpc_maybe_call_delayed_callbacks(NULL, 1);
do_iocp_work();
}
@@ -138,13 +142,19 @@ void grpc_iocp_init(void) {
gpr_thd_new(&id, iocp_loop, NULL, NULL);
}
-void grpc_iocp_shutdown(void) {
+void grpc_iocp_kick(void) {
BOOL success;
- gpr_event_set(&g_shutdown_iocp, (void *)1);
+
success = PostQueuedCompletionStatus(g_iocp, 0,
(ULONG_PTR) &g_iocp_kick_token,
&g_iocp_custom_overlap);
GPR_ASSERT(success);
+}
+
+void grpc_iocp_shutdown(void) {
+ BOOL success;
+ gpr_event_set(&g_shutdown_iocp, (void *)1);
+ grpc_iocp_kick();
gpr_event_wait(&g_iocp_done, gpr_inf_future);
success = CloseHandle(g_iocp);
GPR_ASSERT(success);
@@ -166,6 +176,10 @@ void grpc_iocp_add_socket(grpc_winsocket *socket) {
GPR_ASSERT(ret == g_iocp);
}
+void grpc_iocp_socket_orphan(grpc_winsocket *socket) {
+ gpr_atm_full_fetch_add(&g_orphans, 1);
+}
+
static void socket_notify_on_iocp(grpc_winsocket *socket,
void(*cb)(void *, int), void *opaque,
grpc_winsocket_callback_info *info) {
diff --git a/src/core/iomgr/iocp_windows.h b/src/core/iomgr/iocp_windows.h
index 33133193a1..fa3f5eee10 100644
--- a/src/core/iomgr/iocp_windows.h
+++ b/src/core/iomgr/iocp_windows.h
@@ -42,6 +42,7 @@
void grpc_iocp_init(void);
void grpc_iocp_shutdown(void);
void grpc_iocp_add_socket(grpc_winsocket *);
+void grpc_iocp_socket_orphan(grpc_winsocket *);
void grpc_socket_notify_on_write(grpc_winsocket *, void(*cb)(void *, int success),
void *opaque);
diff --git a/src/core/iomgr/iomgr.c b/src/core/iomgr/iomgr.c
index 058685b295..d0e6706fbd 100644
--- a/src/core/iomgr/iomgr.c
+++ b/src/core/iomgr/iomgr.c
@@ -117,7 +117,16 @@ void grpc_iomgr_shutdown(void) {
gpr_mu_lock(&g_mu);
}
if (g_refs) {
- if (gpr_cv_wait(&g_rcv, &g_mu, shutdown_deadline) && g_cbs_head == NULL) {
+ int timeout = 0;
+ gpr_timespec short_deadline = gpr_time_add(gpr_now(),
+ gpr_time_from_millis(100));
+ while (gpr_cv_wait(&g_rcv, &g_mu, short_deadline) && g_cbs_head == NULL) {
+ if (gpr_time_cmp(gpr_now(), shutdown_deadline) > 0) {
+ timeout = 1;
+ break;
+ }
+ }
+ if (timeout) {
gpr_log(GPR_DEBUG,
"Failed to free %d iomgr objects before shutdown deadline: "
"memory leaks are likely",
diff --git a/src/core/iomgr/sockaddr_win32.h b/src/core/iomgr/sockaddr_win32.h
index 3a5f27bb34..c0385ea614 100644
--- a/src/core/iomgr/sockaddr_win32.h
+++ b/src/core/iomgr/sockaddr_win32.h
@@ -38,4 +38,9 @@
#include <winsock2.h>
#include <mswsock.h>
+#ifdef __MINGW32__
+/* mingw seems to be missing that definition. */
+const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
+#endif
+
#endif /* GRPC_INTERNAL_CORE_IOMGR_SOCKADDR_WIN32_H */
diff --git a/src/core/iomgr/socket_windows.c b/src/core/iomgr/socket_windows.c
index 99f38b0e03..22dad41783 100644
--- a/src/core/iomgr/socket_windows.c
+++ b/src/core/iomgr/socket_windows.c
@@ -55,7 +55,7 @@ grpc_winsocket *grpc_winsocket_create(SOCKET socket) {
return r;
}
-void shutdown_op(grpc_winsocket_callback_info *info) {
+static void shutdown_op(grpc_winsocket_callback_info *info) {
if (!info->cb) return;
grpc_iomgr_add_delayed_callback(info->cb, info->opaque, 0);
}
@@ -68,8 +68,13 @@ void grpc_winsocket_shutdown(grpc_winsocket *socket) {
void grpc_winsocket_orphan(grpc_winsocket *socket) {
gpr_log(GPR_DEBUG, "grpc_winsocket_orphan");
+ grpc_iocp_socket_orphan(socket);
+ socket->orphan = 1;
grpc_iomgr_unref();
closesocket(socket->socket);
+}
+
+void grpc_winsocket_destroy(grpc_winsocket *socket) {
gpr_mu_destroy(&socket->state_mu);
gpr_free(socket);
}
diff --git a/src/core/iomgr/socket_windows.h b/src/core/iomgr/socket_windows.h
index d4776ab10f..cbae91692c 100644
--- a/src/core/iomgr/socket_windows.h
+++ b/src/core/iomgr/socket_windows.h
@@ -57,12 +57,13 @@ typedef struct grpc_winsocket_callback_info {
typedef struct grpc_winsocket {
SOCKET socket;
- int added_to_iocp;
-
grpc_winsocket_callback_info write_info;
grpc_winsocket_callback_info read_info;
gpr_mu state_mu;
+
+ int added_to_iocp;
+ int orphan;
} grpc_winsocket;
/* Create a wrapped windows handle.
@@ -71,5 +72,6 @@ grpc_winsocket *grpc_winsocket_create(SOCKET socket);
void grpc_winsocket_shutdown(grpc_winsocket *socket);
void grpc_winsocket_orphan(grpc_winsocket *socket);
+void grpc_winsocket_destroy(grpc_winsocket *socket);
#endif /* GRPC_INTERNAL_CORE_IOMGR_SOCKET_WINDOWS_H */
diff --git a/src/core/iomgr/tcp_server_windows.c b/src/core/iomgr/tcp_server_windows.c
index 59319da26d..0c3ab1dc91 100644
--- a/src/core/iomgr/tcp_server_windows.c
+++ b/src/core/iomgr/tcp_server_windows.c
@@ -53,9 +53,6 @@
#define INIT_PORT_CAP 2
#define MIN_SAFE_ACCEPT_QUEUE_SIZE 100
-static gpr_once s_init_max_accept_queue_size;
-static int s_max_accept_queue_size;
-
/* one listening port */
typedef struct server_port {
gpr_uint8 addresses[sizeof(struct sockaddr_in6) * 2 + 32];
diff --git a/src/core/iomgr/tcp_windows.c b/src/core/iomgr/tcp_windows.c
index 3efd69a71b..ec5496e7ee 100644
--- a/src/core/iomgr/tcp_windows.c
+++ b/src/core/iomgr/tcp_windows.c
@@ -172,7 +172,7 @@ static void win_notify_on_read(grpc_endpoint *ep,
tcp->read_slice = gpr_slice_malloc(8192);
buffer.len = GPR_SLICE_LENGTH(tcp->read_slice);
- buffer.buf = GPR_SLICE_START_PTR(tcp->read_slice);
+ buffer.buf = (char *)GPR_SLICE_START_PTR(tcp->read_slice);
gpr_log(GPR_DEBUG, "win_notify_on_read: calling WSARecv without overlap");
status = WSARecv(tcp->socket->socket, &buffer, 1, &bytes_read, &flags,
@@ -284,7 +284,7 @@ static grpc_endpoint_write_status win_write(grpc_endpoint *ep,
for (i = 0; i < tcp->write_slices.count; i++) {
buffers[i].len = GPR_SLICE_LENGTH(tcp->write_slices.slices[i]);
- buffers[i].buf = GPR_SLICE_START_PTR(tcp->write_slices.slices[i]);
+ buffers[i].buf = (char *)GPR_SLICE_START_PTR(tcp->write_slices.slices[i]);
}
gpr_log(GPR_DEBUG, "win_write: calling WSASend without overlap");
diff --git a/src/core/security/credentials.c b/src/core/security/credentials.c
index 3ad1e7edd7..698e099134 100644
--- a/src/core/security/credentials.c
+++ b/src/core/security/credentials.c
@@ -46,20 +46,6 @@
#include <grpc/support/sync.h>
#include <grpc/support/time.h>
-/* -- Constants. -- */
-
-#define GRPC_SECURE_TOKEN_REFRESH_THRESHOLD_SECS 60
-
-#define GRPC_COMPUTE_ENGINE_METADATA_HOST "metadata"
-#define GRPC_COMPUTE_ENGINE_METADATA_TOKEN_PATH \
- "/computeMetadata/v1/instance/service-accounts/default/token"
-
-#define GRPC_SERVICE_ACCOUNT_HOST "www.googleapis.com"
-#define GRPC_SERVICE_ACCOUNT_TOKEN_PATH "/oauth2/v3/token"
-#define GRPC_SERVICE_ACCOUNT_POST_BODY_PREFIX \
- "grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&" \
- "assertion="
-
/* -- Common. -- */
typedef struct {
@@ -671,8 +657,8 @@ static void service_account_fetch_oauth2(
}
gpr_asprintf(&body, "%s%s", GRPC_SERVICE_ACCOUNT_POST_BODY_PREFIX, jwt);
memset(&request, 0, sizeof(grpc_httpcli_request));
- request.host = GRPC_SERVICE_ACCOUNT_HOST;
- request.path = GRPC_SERVICE_ACCOUNT_TOKEN_PATH;
+ request.host = GRPC_GOOGLE_OAUTH2_SERVICE_HOST;
+ request.path = GRPC_GOOGLE_OAUTH2_SERVICE_TOKEN_PATH;
request.hdr_count = 1;
request.hdrs = &header;
request.use_ssl = 1;
@@ -703,6 +689,67 @@ grpc_credentials *grpc_service_account_credentials_create(
return &c->base.base;
}
+/* -- RefreshToken credentials. -- */
+
+typedef struct {
+ grpc_oauth2_token_fetcher_credentials base;
+ grpc_auth_refresh_token refresh_token;
+} grpc_refresh_token_credentials;
+
+static void refresh_token_destroy(grpc_credentials *creds) {
+ grpc_refresh_token_credentials *c =
+ (grpc_refresh_token_credentials *)creds;
+ grpc_auth_refresh_token_destruct(&c->refresh_token);
+ oauth2_token_fetcher_destroy(&c->base.base);
+}
+
+static grpc_credentials_vtable refresh_token_vtable = {
+ refresh_token_destroy, oauth2_token_fetcher_has_request_metadata,
+ oauth2_token_fetcher_has_request_metadata_only,
+ oauth2_token_fetcher_get_request_metadata};
+
+static void refresh_token_fetch_oauth2(
+ grpc_credentials_metadata_request *metadata_req,
+ grpc_httpcli_response_cb response_cb, gpr_timespec deadline) {
+ grpc_refresh_token_credentials *c =
+ (grpc_refresh_token_credentials *)metadata_req->creds;
+ grpc_httpcli_header header = {"Content-Type",
+ "application/x-www-form-urlencoded"};
+ grpc_httpcli_request request;
+ char *body = NULL;
+ gpr_asprintf(&body, GRPC_REFRESH_TOKEN_POST_BODY_FORMAT_STRING,
+ c->refresh_token.client_id, c->refresh_token.client_secret,
+ c->refresh_token.refresh_token);
+ memset(&request, 0, sizeof(grpc_httpcli_request));
+ request.host = GRPC_GOOGLE_OAUTH2_SERVICE_HOST;
+ request.path = GRPC_GOOGLE_OAUTH2_SERVICE_TOKEN_PATH;
+ request.hdr_count = 1;
+ request.hdrs = &header;
+ request.use_ssl = 1;
+ grpc_httpcli_post(&request, body, strlen(body), deadline, response_cb,
+ metadata_req);
+ gpr_free(body);
+}
+
+grpc_credentials *grpc_refresh_token_credentials_create(
+ const char *json_refresh_token) {
+ grpc_refresh_token_credentials *c;
+ grpc_auth_refresh_token refresh_token =
+ grpc_auth_refresh_token_create_from_string(json_refresh_token);
+
+ if (!grpc_auth_refresh_token_is_valid(&refresh_token)) {
+ gpr_log(GPR_ERROR,
+ "Invalid input for refresh token credentials creation");
+ return NULL;
+ }
+ c = gpr_malloc(sizeof(grpc_refresh_token_credentials));
+ memset(c, 0, sizeof(grpc_refresh_token_credentials));
+ init_oauth2_token_fetcher(&c->base, refresh_token_fetch_oauth2);
+ c->base.base.vtable = &refresh_token_vtable;
+ c->refresh_token = refresh_token;
+ return &c->base.base;
+}
+
/* -- Fake Oauth2 credentials. -- */
typedef struct {
diff --git a/src/core/security/credentials.h b/src/core/security/credentials.h
index 454e66845d..0f70670ced 100644
--- a/src/core/security/credentials.h
+++ b/src/core/security/credentials.h
@@ -64,6 +64,22 @@ typedef enum {
#define GRPC_GOOGLE_WELL_KNOWN_CREDENTIALS_FILE \
"application_default_credentials.json"
+#define GRPC_SECURE_TOKEN_REFRESH_THRESHOLD_SECS 60
+
+#define GRPC_COMPUTE_ENGINE_METADATA_HOST "metadata"
+#define GRPC_COMPUTE_ENGINE_METADATA_TOKEN_PATH \
+ "/computeMetadata/v1/instance/service-accounts/default/token"
+
+#define GRPC_GOOGLE_OAUTH2_SERVICE_HOST "www.googleapis.com"
+#define GRPC_GOOGLE_OAUTH2_SERVICE_TOKEN_PATH "/oauth2/v3/token"
+
+#define GRPC_SERVICE_ACCOUNT_POST_BODY_PREFIX \
+ "grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&" \
+ "assertion="
+
+#define GRPC_REFRESH_TOKEN_POST_BODY_FORMAT_STRING \
+ "client_id=%s&client_secret=%s&refresh_token=%s&grant_type=refresh_token"
+
/* --- grpc_credentials. --- */
/* It is the caller's responsibility to gpr_free the result if not NULL. */
diff --git a/src/core/security/google_default_credentials.c b/src/core/security/google_default_credentials.c
index bdc907e7b3..ebea70dad2 100644
--- a/src/core/security/google_default_credentials.c
+++ b/src/core/security/google_default_credentials.c
@@ -138,6 +138,23 @@ static grpc_credentials *create_jwt_creds_from_path(char *creds_path) {
return result;
}
+/* Takes ownership of creds_path if not NULL. */
+static grpc_credentials *create_refresh_token_creds_from_path(
+ char *creds_path) {
+ grpc_credentials *result = NULL;
+ gpr_slice creds_data;
+ int file_ok = 0;
+ if (creds_path == NULL) return NULL;
+ creds_data = gpr_load_file(creds_path, &file_ok);
+ gpr_free(creds_path);
+ if (file_ok) {
+ result = grpc_refresh_token_credentials_create(
+ (const char *)GPR_SLICE_START_PTR(creds_data));
+ gpr_slice_unref(creds_data);
+ }
+ return result;
+}
+
grpc_credentials *grpc_google_default_credentials_create(void) {
grpc_credentials *result = NULL;
int serving_cached_credentials = 0;
@@ -157,7 +174,7 @@ grpc_credentials *grpc_google_default_credentials_create(void) {
if (result != NULL) goto end;
/* Then the well-known file. */
- result = create_jwt_creds_from_path(
+ result = create_refresh_token_creds_from_path(
grpc_get_well_known_google_credentials_file_path());
if (result != NULL) goto end;
diff --git a/src/core/security/json_token.c b/src/core/security/json_token.c
index 40b612b206..eadae33609 100644
--- a/src/core/security/json_token.c
+++ b/src/core/security/json_token.c
@@ -52,8 +52,9 @@
/* 1 hour max. */
const gpr_timespec grpc_max_auth_token_lifetime = {3600, 0};
-#define GRPC_AUTH_JSON_KEY_TYPE_INVALID "invalid"
-#define GRPC_AUTH_JSON_KEY_TYPE_SERVICE_ACCOUNT "service_account"
+#define GRPC_AUTH_JSON_TYPE_INVALID "invalid"
+#define GRPC_AUTH_JSON_TYPE_SERVICE_ACCOUNT "service_account"
+#define GRPC_AUTH_JSON_TYPE_AUTHORIZED_USER "authorized_user"
#define GRPC_JWT_RSA_SHA256_ALGORITHM "RS256"
#define GRPC_JWT_TYPE "JWT"
@@ -87,7 +88,7 @@ static int set_json_key_string_property(grpc_json *json, const char *prop_name,
int grpc_auth_json_key_is_valid(const grpc_auth_json_key *json_key) {
return (json_key != NULL) &&
- strcmp(json_key->type, GRPC_AUTH_JSON_KEY_TYPE_INVALID);
+ strcmp(json_key->type, GRPC_AUTH_JSON_TYPE_INVALID);
}
grpc_auth_json_key grpc_auth_json_key_create_from_string(
@@ -100,7 +101,7 @@ grpc_auth_json_key grpc_auth_json_key_create_from_string(
int success = 0;
memset(&result, 0, sizeof(grpc_auth_json_key));
- result.type = GRPC_AUTH_JSON_KEY_TYPE_INVALID;
+ result.type = GRPC_AUTH_JSON_TYPE_INVALID;
if (json == NULL) {
gpr_log(GPR_ERROR, "Invalid json string %s", json_string);
goto end;
@@ -108,10 +109,10 @@ grpc_auth_json_key grpc_auth_json_key_create_from_string(
prop_value = json_get_string_property(json, "type");
if (prop_value == NULL ||
- strcmp(prop_value, GRPC_AUTH_JSON_KEY_TYPE_SERVICE_ACCOUNT)) {
+ strcmp(prop_value, GRPC_AUTH_JSON_TYPE_SERVICE_ACCOUNT)) {
goto end;
}
- result.type = GRPC_AUTH_JSON_KEY_TYPE_SERVICE_ACCOUNT;
+ result.type = GRPC_AUTH_JSON_TYPE_SERVICE_ACCOUNT;
if (!set_json_key_string_property(json, "private_key_id",
&result.private_key_id) ||
@@ -148,7 +149,7 @@ end:
void grpc_auth_json_key_destruct(grpc_auth_json_key *json_key) {
if (json_key == NULL) return;
- json_key->type = GRPC_AUTH_JSON_KEY_TYPE_INVALID;
+ json_key->type = GRPC_AUTH_JSON_TYPE_INVALID;
if (json_key->client_id != NULL) {
gpr_free(json_key->client_id);
json_key->client_id = NULL;
@@ -331,3 +332,67 @@ void grpc_jwt_encode_and_sign_set_override(
grpc_jwt_encode_and_sign_override func) {
g_jwt_encode_and_sign_override = func;
}
+
+/* --- grpc_auth_refresh_token --- */
+
+int grpc_auth_refresh_token_is_valid(
+ const grpc_auth_refresh_token *refresh_token) {
+ return (refresh_token != NULL) &&
+ strcmp(refresh_token->type, GRPC_AUTH_JSON_TYPE_INVALID);
+}
+
+grpc_auth_refresh_token grpc_auth_refresh_token_create_from_string(
+ const char *json_string) {
+ grpc_auth_refresh_token result;
+ char *scratchpad = gpr_strdup(json_string);
+ grpc_json *json = grpc_json_parse_string(scratchpad);
+ const char *prop_value;
+ int success = 0;
+
+ memset(&result, 0, sizeof(grpc_auth_refresh_token));
+ result.type = GRPC_AUTH_JSON_TYPE_INVALID;
+ if (json == NULL) {
+ gpr_log(GPR_ERROR, "Invalid json string %s", json_string);
+ goto end;
+ }
+
+ prop_value = json_get_string_property(json, "type");
+ if (prop_value == NULL ||
+ strcmp(prop_value, GRPC_AUTH_JSON_TYPE_AUTHORIZED_USER)) {
+ goto end;
+ }
+ result.type = GRPC_AUTH_JSON_TYPE_AUTHORIZED_USER;
+
+ if (!set_json_key_string_property(json, "client_secret",
+ &result.client_secret) ||
+ !set_json_key_string_property(json, "client_id", &result.client_id) ||
+ !set_json_key_string_property(json, "refresh_token",
+ &result.refresh_token)) {
+ goto end;
+ }
+ success = 1;
+
+end:
+ if (json != NULL) grpc_json_destroy(json);
+ if (!success) grpc_auth_refresh_token_destruct(&result);
+ gpr_free(scratchpad);
+ return result;
+}
+
+void grpc_auth_refresh_token_destruct(grpc_auth_refresh_token *refresh_token) {
+ if (refresh_token == NULL) return;
+ refresh_token->type = GRPC_AUTH_JSON_TYPE_INVALID;
+ if (refresh_token->client_id != NULL) {
+ gpr_free(refresh_token->client_id);
+ refresh_token->client_id = NULL;
+ }
+ if (refresh_token->client_secret != NULL) {
+ gpr_free(refresh_token->client_secret);
+ refresh_token->client_secret = NULL;
+ }
+ if (refresh_token->refresh_token != NULL) {
+ gpr_free(refresh_token->refresh_token);
+ refresh_token->refresh_token = NULL;
+ }
+}
+
diff --git a/src/core/security/json_token.h b/src/core/security/json_token.h
index 029ede3955..197796ab4c 100644
--- a/src/core/security/json_token.h
+++ b/src/core/security/json_token.h
@@ -44,7 +44,7 @@
/* --- auth_json_key parsing. --- */
typedef struct {
- char *type;
+ const char *type;
char *private_key_id;
char *client_id;
char *client_email;
@@ -79,4 +79,25 @@ typedef char *(*grpc_jwt_encode_and_sign_override)(
void grpc_jwt_encode_and_sign_set_override(
grpc_jwt_encode_and_sign_override func);
+/* --- auth_refresh_token parsing. --- */
+
+typedef struct {
+ const char *type;
+ char *client_id;
+ char *client_secret;
+ char *refresh_token;
+} grpc_auth_refresh_token;
+
+/* Returns 1 if the object is valid, 0 otherwise. */
+int grpc_auth_refresh_token_is_valid(
+ const grpc_auth_refresh_token *refresh_token);
+
+/* Creates a refresh token object from string. Returns an invalid object if a
+ parsing error has been encountered. */
+grpc_auth_refresh_token grpc_auth_refresh_token_create_from_string(
+ const char *json_string);
+
+/* Destructs the object. */
+void grpc_auth_refresh_token_destruct(grpc_auth_refresh_token *refresh_token);
+
#endif /* GRPC_INTERNAL_CORE_SECURITY_JSON_TOKEN_H */
diff --git a/src/core/security/roots.pem b/src/core/security/roots.pem
deleted file mode 100644
index 70990f1f82..0000000000
--- a/src/core/security/roots.pem
+++ /dev/null
@@ -1,2183 +0,0 @@
-# Issuer: CN=GTE CyberTrust Global Root O=GTE Corporation OU=GTE CyberTrust Solutions, Inc.
-# Subject: CN=GTE CyberTrust Global Root O=GTE Corporation OU=GTE CyberTrust Solutions, Inc.
-# Label: "GTE CyberTrust Global Root"
-# Serial: 421
-# MD5 Fingerprint: ca:3d:d3:68:f1:03:5c:d0:32:fa:b8:2b:59:e8:5a:db
-# SHA1 Fingerprint: 97:81:79:50:d8:1c:96:70:cc:34:d8:09:cf:79:44:31:36:7e:f4:74
-# SHA256 Fingerprint: a5:31:25:18:8d:21:10:aa:96:4b:02:c7:b7:c6:da:32:03:17:08:94:e5:fb:71:ff:fb:66:67:d5:e6:81:0a:36
------BEGIN CERTIFICATE-----
-MIICWjCCAcMCAgGlMA0GCSqGSIb3DQEBBAUAMHUxCzAJBgNVBAYTAlVTMRgwFgYD
-VQQKEw9HVEUgQ29ycG9yYXRpb24xJzAlBgNVBAsTHkdURSBDeWJlclRydXN0IFNv
-bHV0aW9ucywgSW5jLjEjMCEGA1UEAxMaR1RFIEN5YmVyVHJ1c3QgR2xvYmFsIFJv
-b3QwHhcNOTgwODEzMDAyOTAwWhcNMTgwODEzMjM1OTAwWjB1MQswCQYDVQQGEwJV
-UzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMScwJQYDVQQLEx5HVEUgQ3liZXJU
-cnVzdCBTb2x1dGlvbnMsIEluYy4xIzAhBgNVBAMTGkdURSBDeWJlclRydXN0IEds
-b2JhbCBSb290MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVD6C28FCc6HrH
-iM3dFw4usJTQGz0O9pTAipTHBsiQl8i4ZBp6fmw8U+E3KHNgf7KXUwefU/ltWJTS
-r41tiGeA5u2ylc9yMcqlHHK6XALnZELn+aks1joNrI1CqiQBOeacPwGFVw1Yh0X4
-04Wqk2kmhXBIgD8SFcd5tB8FLztimQIDAQABMA0GCSqGSIb3DQEBBAUAA4GBAG3r
-GwnpXtlR22ciYaQqPEh346B8pt5zohQDhT37qw4wxYMWM4ETCJ57NE7fQMh017l9
-3PR2VX2bY1QY6fDq81yx2YtCHrnAlU66+tXifPVoYb+O7AWXX1uw16OFNMQkpw0P
-lZPvy5TYnh+dXIVtx6quTx8itc2VrbqnzPmrC3p/
------END CERTIFICATE-----
-
-# Issuer: CN=Thawte Server CA O=Thawte Consulting cc OU=Certification Services Division
-# Subject: CN=Thawte Server CA O=Thawte Consulting cc OU=Certification Services Division
-# Label: "Thawte Server CA"
-# Serial: 1
-# MD5 Fingerprint: c5:70:c4:a2:ed:53:78:0c:c8:10:53:81:64:cb:d0:1d
-# SHA1 Fingerprint: 23:e5:94:94:51:95:f2:41:48:03:b4:d5:64:d2:a3:a3:f5:d8:8b:8c
-# SHA256 Fingerprint: b4:41:0b:73:e2:e6:ea:ca:47:fb:c4:2f:8f:a4:01:8a:f4:38:1d:c5:4c:fa:a8:44:50:46:1e:ed:09:45:4d:e9
------BEGIN CERTIFICATE-----
-MIIDEzCCAnygAwIBAgIBATANBgkqhkiG9w0BAQQFADCBxDELMAkGA1UEBhMCWkEx
-FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYD
-VQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlv
-biBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcGA1UEAxMQVGhhd3RlIFNlcnZlciBDQTEm
-MCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0ZS5jb20wHhcNOTYwODAx
-MDAwMDAwWhcNMjAxMjMxMjM1OTU5WjCBxDELMAkGA1UEBhMCWkExFTATBgNVBAgT
-DFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3
-dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNl
-cyBEaXZpc2lvbjEZMBcGA1UEAxMQVGhhd3RlIFNlcnZlciBDQTEmMCQGCSqGSIb3
-DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0ZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQAD
-gY0AMIGJAoGBANOkUG7I/1Zr5s9dtuoMaHVHoqrC2oQl/Kj0R1HahbUgdJSGHg91
-yekIYfUGbTBuFRkC6VLAYttNmZ7iagxEOM3+vuNkCXDF/rFrKbYvScg71CcEJRCX
-L+eQbcAoQpnXTEPew/UhbVSfXcNY4cDk2VuwuNy0e982OsK1ZiIS1ocNAgMBAAGj
-EzARMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEEBQADgYEAB/pMaVz7lcxG
-7oWDTSEwjsrZqG9JGubaUeNgcGyEYRGhGshIPllDfU+VPaGLtwtimHp1it2ITk6e
-QNuozDJ0uW8NxuOzRAvZim+aKZuZGCg70eNAKJpaPNW15yAbi8qkq43pUdniTCxZ
-qdq5snUb9kLy78fyGPmJvKP/iiMucEc=
------END CERTIFICATE-----
-
-# Issuer: CN=Thawte Premium Server CA O=Thawte Consulting cc OU=Certification Services Division
-# Subject: CN=Thawte Premium Server CA O=Thawte Consulting cc OU=Certification Services Division
-# Label: "Thawte Premium Server CA"
-# Serial: 1
-# MD5 Fingerprint: 06:9f:69:79:16:66:90:02:1b:8c:8c:a2:c3:07:6f:3a
-# SHA1 Fingerprint: 62:7f:8d:78:27:65:63:99:d2:7d:7f:90:44:c9:fe:b3:f3:3e:fa:9a
-# SHA256 Fingerprint: ab:70:36:36:5c:71:54:aa:29:c2:c2:9f:5d:41:91:16:3b:16:2a:22:25:01:13:57:d5:6d:07:ff:a7:bc:1f:72
------BEGIN CERTIFICATE-----
-MIIDJzCCApCgAwIBAgIBATANBgkqhkiG9w0BAQQFADCBzjELMAkGA1UEBhMCWkEx
-FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYD
-VQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlv
-biBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhhd3RlIFByZW1pdW0gU2Vy
-dmVyIENBMSgwJgYJKoZIhvcNAQkBFhlwcmVtaXVtLXNlcnZlckB0aGF3dGUuY29t
-MB4XDTk2MDgwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgc4xCzAJBgNVBAYTAlpB
-MRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEdMBsG
-A1UEChMUVGhhd3RlIENvbnN1bHRpbmcgY2MxKDAmBgNVBAsTH0NlcnRpZmljYXRp
-b24gU2VydmljZXMgRGl2aXNpb24xITAfBgNVBAMTGFRoYXd0ZSBQcmVtaXVtIFNl
-cnZlciBDQTEoMCYGCSqGSIb3DQEJARYZcHJlbWl1bS1zZXJ2ZXJAdGhhd3RlLmNv
-bTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0jY2aovXwlue2oFBYo847kkE
-VdbQ7xwblRZH7xhINTpS9CtqBo87L+pW46+GjZ4X9560ZXUCTe/LCaIhUdib0GfQ
-ug2SBhRz1JPLlyoAnFxODLz6FVL88kRu2hFKbgifLy3j+ao6hnO2RlNYyIkFvYMR
-uHM/qgeN9EJN50CdHDcCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG
-9w0BAQQFAAOBgQAmSCwWwlj66BZ0DKqqX1Q/8tfJeGBeXm43YyJ3Nn6yF8Q0ufUI
-hfzJATj/Tb7yFkJD57taRvvBxhEf8UqwKEbJw8RCfbz6q1lu1bdRiBHjpIUZa4JM
-pAwSremkrj/xw0llmozFyD4lt5SZu5IycQfwhl7tUCemDaYj+bvLpgcUQg==
------END CERTIFICATE-----
-
-# Issuer: O=Equifax OU=Equifax Secure Certificate Authority
-# Subject: O=Equifax OU=Equifax Secure Certificate Authority
-# Label: "Equifax Secure CA"
-# Serial: 903804111
-# MD5 Fingerprint: 67:cb:9d:c0:13:24:8a:82:9b:b2:17:1e:d1:1b:ec:d4
-# SHA1 Fingerprint: d2:32:09:ad:23:d3:14:23:21:74:e4:0d:7f:9d:62:13:97:86:63:3a
-# SHA256 Fingerprint: 08:29:7a:40:47:db:a2:36:80:c7:31:db:6e:31:76:53:ca:78:48:e1:be:bd:3a:0b:01:79:a7:07:f9:2c:f1:78
------BEGIN CERTIFICATE-----
-MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV
-UzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2Vy
-dGlmaWNhdGUgQXV0aG9yaXR5MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1
-MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0VxdWlmYXgxLTArBgNVBAsTJEVx
-dWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCBnzANBgkqhkiG9w0B
-AQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2RFGiYCh7+2gRvE4RiIcPRfM6f
-BeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO/t0BCezhABRP/PvwDN1Dulsr4R+A
-cJkVV5MW8Q+XarfCaCMczE1ZMKxRHjuvK9buY0V7xdlfUNLjUA86iOe/FP3gx7kC
-AwEAAaOCAQkwggEFMHAGA1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQ
-MA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlm
-aWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTgw
-ODIyMTY0MTUxWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvSspXXR9gj
-IBBPM5iQn9QwHQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQF
-MAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUA
-A4GBAFjOKer89961zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y
-7qj/WsjTVbJmcVfewCHrPSqnI0kBBIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh
-1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee9570+sB3c4
------END CERTIFICATE-----
-
-# Issuer: O=VeriSign, Inc. OU=Class 3 Public Primary Certification Authority
-# Subject: O=VeriSign, Inc. OU=Class 3 Public Primary Certification Authority
-# Label: "Verisign Class 3 Public Primary Certification Authority"
-# Serial: 149843929435818692848040365716851702463
-# MD5 Fingerprint: 10:fc:63:5d:f6:26:3e:0d:f3:25:be:5f:79:cd:67:67
-# SHA1 Fingerprint: 74:2c:31:92:e6:07:e4:24:eb:45:49:54:2b:e1:bb:c5:3e:61:74:e2
-# SHA256 Fingerprint: e7:68:56:34:ef:ac:f6:9a:ce:93:9a:6b:25:5b:7b:4f:ab:ef:42:93:5b:50:a2:65:ac:b5:cb:60:27:e4:4e:70
------BEGIN CERTIFICATE-----
-MIICPDCCAaUCEHC65B0Q2Sk0tjjKewPMur8wDQYJKoZIhvcNAQECBQAwXzELMAkG
-A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz
-cyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2
-MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV
-BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmlt
-YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN
-ADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhE
-BarsAx94f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/is
-I19wKTakyYbnsZogy1Olhec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0G
-CSqGSIb3DQEBAgUAA4GBALtMEivPLCYATxQT3ab7/AoRhIzzKBxnki98tsX63/Do
-lbwdj2wsqFHMc9ikwFPwTtYmwHYBV4GSXiHx0bH/59AhWM1pF+NEHJwZRDmJXNyc
-AA9WjQKZ7aKQRUzkuxCkPfAyAw7xzvjoyVGM5mKf5p/AfbdynMk2OmufTqj/ZA1k
------END CERTIFICATE-----
-
-# Issuer: O=VeriSign, Inc. OU=Class 3 Public Primary Certification Authority - G2/(c) 1998 VeriSign, Inc. - For authorized use only/VeriSign Trust Network
-# Subject: O=VeriSign, Inc. OU=Class 3 Public Primary Certification Authority - G2/(c) 1998 VeriSign, Inc. - For authorized use only/VeriSign Trust Network
-# Label: "Verisign Class 3 Public Primary Certification Authority - G2"
-# Serial: 167285380242319648451154478808036881606
-# MD5 Fingerprint: a2:33:9b:4c:74:78:73:d4:6c:e7:c1:f3:8d:cb:5c:e9
-# SHA1 Fingerprint: 85:37:1c:a6:e5:50:14:3d:ce:28:03:47:1b:de:3a:09:e8:f8:77:0f
-# SHA256 Fingerprint: 83:ce:3c:12:29:68:8a:59:3d:48:5f:81:97:3c:0f:91:95:43:1e:da:37:cc:5e:36:43:0e:79:c7:a8:88:63:8b
------BEGIN CERTIFICATE-----
-MIIDAjCCAmsCEH3Z/gfPqB63EHln+6eJNMYwDQYJKoZIhvcNAQEFBQAwgcExCzAJ
-BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xh
-c3MgMyBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcy
-MTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3Jp
-emVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMB4X
-DTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVTMRcw
-FQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMyBQdWJsaWMg
-UHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEo
-YykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5
-MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEB
-AQUAA4GNADCBiQKBgQDMXtERXVxp0KvTuWpMmR9ZmDCOFoUgRm1HP9SFIIThbbP4
-pO0M8RcPO/mn+SXXwc+EY/J8Y8+iR/LGWzOOZEAEaMGAuWQcRXfH2G71lSk8UOg0
-13gfqLptQ5GVj0VXXn7F+8qkBOvqlzdUMG+7AUcyM83cV5tkaWH4mx0ciU9cZwID
-AQABMA0GCSqGSIb3DQEBBQUAA4GBAFFNzb5cy5gZnBWyATl4Lk0PZ3BwmcYQWpSk
-U01UbSuvDV1Ai2TT1+7eVmGSX6bEHRBhNtMsJzzoKQm5EWR0zLVznxxIqbxhAe7i
-F6YM40AIOw7n60RzKprxaZLvcRTDOaxxp5EJb+RxBrO6WVcmeQD2+A2iMzAo1KpY
-oJ2daZH9
------END CERTIFICATE-----
-
-# Issuer: CN=GlobalSign Root CA O=GlobalSign nv-sa OU=Root CA
-# Subject: CN=GlobalSign Root CA O=GlobalSign nv-sa OU=Root CA
-# Label: "GlobalSign Root CA"
-# Serial: 4835703278459707669005204
-# MD5 Fingerprint: 3e:45:52:15:09:51:92:e1:b7:5d:37:9f:b1:87:29:8a
-# SHA1 Fingerprint: b1:bc:96:8b:d4:f4:9d:62:2a:a8:9a:81:f2:15:01:52:a4:1d:82:9c
-# SHA256 Fingerprint: eb:d4:10:40:e4:bb:3e:c7:42:c9:e3:81:d3:1e:f2:a4:1a:48:b6:68:5c:96:e7:ce:f3:c1:df:6c:d4:33:1c:99
------BEGIN CERTIFICATE-----
-MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG
-A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv
-b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw
-MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i
-YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT
-aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ
-jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp
-xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp
-1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG
-snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ
-U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8
-9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E
-BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B
-AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz
-yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE
-38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP
-AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad
-DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME
-HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==
------END CERTIFICATE-----
-
-# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R2
-# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R2
-# Label: "GlobalSign Root CA - R2"
-# Serial: 4835703278459682885658125
-# MD5 Fingerprint: 94:14:77:7e:3e:5e:fd:8f:30:bd:41:b0:cf:e7:d0:30
-# SHA1 Fingerprint: 75:e0:ab:b6:13:85:12:27:1c:04:f8:5f:dd:de:38:e4:b7:24:2e:fe
-# SHA256 Fingerprint: ca:42:dd:41:74:5f:d0:b8:1e:b9:02:36:2c:f9:d8:bf:71:9d:a1:bd:1b:1e:fc:94:6f:5b:4c:99:f4:2c:1b:9e
------BEGIN CERTIFICATE-----
-MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4G
-A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNp
-Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1
-MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEG
-A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI
-hvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6ErPL
-v4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8
-eoLrvozps6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklq
-tTleiDTsvHgMCJiEbKjNS7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzd
-C9XZzPnqJworc5HGnRusyMvo4KD0L5CLTfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pa
-zq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6CygPCm48CAwEAAaOBnDCB
-mTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUm+IH
-V2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5n
-bG9iYWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG
-3lm0mi3f3BmGLjANBgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4Gs
-J0/WwbgcQ3izDJr86iw8bmEbTUsp9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO
-291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu01yiPqFbQfXf5WRDLenVOavS
-ot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG79G+dwfCMNYxd
-AfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7
-TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg==
------END CERTIFICATE-----
-
-# Issuer: CN=http://www.valicert.com/ O=ValiCert, Inc. OU=ValiCert Class 1 Policy Validation Authority
-# Subject: CN=http://www.valicert.com/ O=ValiCert, Inc. OU=ValiCert Class 1 Policy Validation Authority
-# Label: "ValiCert Class 1 VA"
-# Serial: 1
-# MD5 Fingerprint: 65:58:ab:15:ad:57:6c:1e:a8:a7:b5:69:ac:bf:ff:eb
-# SHA1 Fingerprint: e5:df:74:3c:b6:01:c4:9b:98:43:dc:ab:8c:e8:6a:81:10:9f:e4:8e
-# SHA256 Fingerprint: f4:c1:49:55:1a:30:13:a3:5b:c7:bf:fe:17:a7:f3:44:9b:c1:ab:5b:5a:0a:e7:4b:06:c2:3b:90:00:4c:01:04
------BEGIN CERTIFICATE-----
-MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0
-IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz
-BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDEgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y
-aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG
-9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNTIyMjM0OFoXDTE5MDYy
-NTIyMjM0OFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y
-azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs
-YXNzIDEgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw
-Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl
-cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDYWYJ6ibiWuqYvaG9Y
-LqdUHAZu9OqNSLwxlBfw8068srg1knaw0KWlAdcAAxIiGQj4/xEjm84H9b9pGib+
-TunRf50sQB1ZaG6m+FiwnRqP0z/x3BkGgagO4DrdyFNFCQbmD3DD+kCmDuJWBQ8Y
-TfwggtFzVXSNdnKgHZ0dwN0/cQIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFBoPUn0
-LBwGlN+VYH+Wexf+T3GtZMjdd9LvWVXoP+iOBSoh8gfStadS/pyxtuJbdxdA6nLW
-I8sogTLDAHkY7FkXicnGah5xyf23dKUlRWnFSKsZ4UWKJWsZ7uW7EvV/96aNUcPw
-nXS3qT6gpf+2SQMT2iLM7XGCK5nPOrf1LXLI
------END CERTIFICATE-----
-
-# Issuer: CN=http://www.valicert.com/ O=ValiCert, Inc. OU=ValiCert Class 2 Policy Validation Authority
-# Subject: CN=http://www.valicert.com/ O=ValiCert, Inc. OU=ValiCert Class 2 Policy Validation Authority
-# Label: "ValiCert Class 2 VA"
-# Serial: 1
-# MD5 Fingerprint: a9:23:75:9b:ba:49:36:6e:31:c2:db:f2:e7:66:ba:87
-# SHA1 Fingerprint: 31:7a:2a:d0:7f:2b:33:5e:f5:a1:c3:4e:4b:57:e8:b7:d8:f1:fc:a6
-# SHA256 Fingerprint: 58:d0:17:27:9c:d4:dc:63:ab:dd:b1:96:a6:c9:90:6c:30:c4:e0:87:83:ea:e8:c1:60:99:54:d6:93:55:59:6b
------BEGIN CERTIFICATE-----
-MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0
-IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz
-BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y
-aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG
-9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAwMTk1NFoXDTE5MDYy
-NjAwMTk1NFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y
-azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs
-YXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw
-Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl
-cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOOnHK5avIWZJV16vY
-dA757tn2VUdZZUcOBVXc65g2PFxTXdMwzzjsvUGJ7SVCCSRrCl6zfN1SLUzm1NZ9
-WlmpZdRJEy0kTRxQb7XBhVQ7/nHk01xC+YDgkRoKWzk2Z/M/VXwbP7RfZHM047QS
-v4dk+NoS/zcnwbNDu+97bi5p9wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBADt/UG9v
-UJSZSWI4OB9L+KXIPqeCgfYrx+jFzug6EILLGACOTb2oWH+heQC1u+mNr0HZDzTu
-IYEZoDJJKPTEjlbVUjP9UNV+mWwD5MlM/Mtsq2azSiGM5bUMMj4QssxsodyamEwC
-W/POuZ6lcg5Ktz885hZo+L7tdEy8W9ViH0Pd
------END CERTIFICATE-----
-
-# Issuer: CN=http://www.valicert.com/ O=ValiCert, Inc. OU=ValiCert Class 3 Policy Validation Authority
-# Subject: CN=http://www.valicert.com/ O=ValiCert, Inc. OU=ValiCert Class 3 Policy Validation Authority
-# Label: "RSA Root Certificate 1"
-# Serial: 1
-# MD5 Fingerprint: a2:6f:53:b7:ee:40:db:4a:68:e7:fa:18:d9:10:4b:72
-# SHA1 Fingerprint: 69:bd:8c:f4:9c:d3:00:fb:59:2e:17:93:ca:55:6a:f3:ec:aa:35:fb
-# SHA256 Fingerprint: bc:23:f9:8a:31:3c:b9:2d:e3:bb:fc:3a:5a:9f:44:61:ac:39:49:4c:4a:e1:5a:9e:9d:f1:31:e9:9b:73:01:9a
------BEGIN CERTIFICATE-----
-MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0
-IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz
-BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDMgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y
-aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG
-9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAwMjIzM1oXDTE5MDYy
-NjAwMjIzM1owgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y
-azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs
-YXNzIDMgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw
-Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl
-cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDjmFGWHOjVsQaBalfD
-cnWTq8+epvzzFlLWLU2fNUSoLgRNB0mKOCn1dzfnt6td3zZxFJmP3MKS8edgkpfs
-2Ejcv8ECIMYkpChMMFp2bbFc893enhBxoYjHW5tBbcqwuI4V7q0zK89HBFx1cQqY
-JJgpp0lZpd34t0NiYfPT4tBVPwIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFa7AliE
-Zwgs3x/be0kz9dNnnfS0ChCzycUs4pJqcXgn8nCDQtM+z6lU9PHYkhaM0QTLS6vJ
-n0WuPIqpsHEzXcjFV9+vqDWzf4mH6eglkrh/hXqu1rweN1gqZ8mRzyqBPu3GOd/A
-PhmcGcwTTYJBtYze4D1gCCAPRX5ron+jjBXu
------END CERTIFICATE-----
-
-# Issuer: CN=VeriSign Class 3 Public Primary Certification Authority - G3 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 1999 VeriSign, Inc. - For authorized use only
-# Subject: CN=VeriSign Class 3 Public Primary Certification Authority - G3 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 1999 VeriSign, Inc. - For authorized use only
-# Label: "Verisign Class 3 Public Primary Certification Authority - G3"
-# Serial: 206684696279472310254277870180966723415
-# MD5 Fingerprint: cd:68:b6:a7:c7:c4:ce:75:e0:1d:4f:57:44:61:92:09
-# SHA1 Fingerprint: 13:2d:0d:45:53:4b:69:97:cd:b2:d5:c3:39:e2:55:76:60:9b:5c:c6
-# SHA256 Fingerprint: eb:04:cf:5e:b1:f3:9a:fa:76:2f:2b:b1:20:f2:96:cb:a5:20:c1:b9:7d:b1:58:95:65:b8:1c:b9:a1:7b:72:44
------BEGIN CERTIFICATE-----
-MIIEGjCCAwICEQCbfgZJoz5iudXukEhxKe9XMA0GCSqGSIb3DQEBBQUAMIHKMQsw
-CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl
-cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu
-LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT
-aWduIENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp
-dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD
-VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT
-aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ
-bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu
-IENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg
-LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMu6nFL8eB8aHm8b
-N3O9+MlrlBIwT/A2R/XQkQr1F8ilYcEWQE37imGQ5XYgwREGfassbqb1EUGO+i2t
-KmFZpGcmTNDovFJbcCAEWNF6yaRpvIMXZK0Fi7zQWM6NjPXr8EJJC52XJ2cybuGu
-kxUccLwgTS8Y3pKI6GyFVxEa6X7jJhFUokWWVYPKMIno3Nij7SqAP395ZVc+FSBm
-CC+Vk7+qRy+oRpfwEuL+wgorUeZ25rdGt+INpsyow0xZVYnm6FNcHOqd8GIWC6fJ
-Xwzw3sJ2zq/3avL6QaaiMxTJ5Xpj055iN9WFZZ4O5lMkdBteHRJTW8cs54NJOxWu
-imi5V5cCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAERSWwauSCPc/L8my/uRan2Te
-2yFPhpk0djZX3dAVL8WtfxUfN2JzPtTnX84XA9s1+ivbrmAJXx5fj267Cz3qWhMe
-DGBvtcC1IyIuBwvLqXTLR7sdwdela8wv0kL9Sd2nic9TutoAWii/gt/4uhMdUIaC
-/Y4wjylGsB49Ndo4YhYYSq3mtlFs3q9i6wHQHiT+eo8SGhJouPtmmRQURVyu565p
-F4ErWjfJXir0xuKhXFSbplQAz/DxwceYMBo7Nhbbo27q/a2ywtrvAkcTisDxszGt
-TxzhT5yvDwyd93gN2PQ1VoDat20Xj50egWTh/sVFuq1ruQp6Tk9LhO5L8X3dEQ==
------END CERTIFICATE-----
-
-# Issuer: CN=VeriSign Class 4 Public Primary Certification Authority - G3 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 1999 VeriSign, Inc. - For authorized use only
-# Subject: CN=VeriSign Class 4 Public Primary Certification Authority - G3 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 1999 VeriSign, Inc. - For authorized use only
-# Label: "Verisign Class 4 Public Primary Certification Authority - G3"
-# Serial: 314531972711909413743075096039378935511
-# MD5 Fingerprint: db:c8:f2:27:2e:b1:ea:6a:29:23:5d:fe:56:3e:33:df
-# SHA1 Fingerprint: c8:ec:8c:87:92:69:cb:4b:ab:39:e9:8d:7e:57:67:f3:14:95:73:9d
-# SHA256 Fingerprint: e3:89:36:0d:0f:db:ae:b3:d2:50:58:4b:47:30:31:4e:22:2f:39:c1:56:a0:20:14:4e:8d:96:05:61:79:15:06
------BEGIN CERTIFICATE-----
-MIIEGjCCAwICEQDsoKeLbnVqAc/EfMwvlF7XMA0GCSqGSIb3DQEBBQUAMIHKMQsw
-CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl
-cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu
-LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT
-aWduIENsYXNzIDQgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp
-dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD
-VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT
-aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ
-bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu
-IENsYXNzIDQgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg
-LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK3LpRFpxlmr8Y+1
-GQ9Wzsy1HyDkniYlS+BzZYlZ3tCD5PUPtbut8XzoIfzk6AzufEUiGXaStBO3IFsJ
-+mGuqPKljYXCKtbeZjbSmwL0qJJgfJxptI8kHtCGUvYynEFYHiK9zUVilQhu0Gbd
-U6LM8BDcVHOLBKFGMzNcF0C5nk3T875Vg+ixiY5afJqWIpA7iCXy0lOIAgwLePLm
-NxdLMEYH5IBtptiWLugs+BGzOA1mppvqySNb247i8xOOGlktqgLw7KSHZtzBP/XY
-ufTsgsbSPZUd5cBPhMnZo0QoBmrXRazwa2rvTl/4EYIeOGM0ZlDUPpNz+jDDZq3/
-ky2X7wMCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAj/ola09b5KROJ1WrIhVZPMq1
-CtRK26vdoV9TxaBXOcLORyu+OshWv8LZJxA6sQU8wHcxuzrTBXttmhwwjIDLk5Mq
-g6sFUYICABFna/OIYUdfA5PVWw3g8dShMjWFsjrbsIKr0csKvE+MW8VLADsfKoKm
-fjaF3H48ZwC15DtS4KjrXRX5xm3wrR0OhbepmnMUWluPQSjA1egtTaRezarZ7c7c
-2NU8Qh0XwRJdRTjDOPP8hS6DRkiy1yBfkjaP53kPmF6Z6PDQpLv1U70qzlmwr25/
-bLvSHgCwIe34QWKCudiyxLtGUPMxxY8BqHTr9Xgn2uf3ZkPznoM+IKrDNWCRzg==
------END CERTIFICATE-----
-
-# Issuer: CN=Entrust.net Secure Server Certification Authority O=Entrust.net OU=www.entrust.net/CPS incorp. by ref. (limits liab.)/(c) 1999 Entrust.net Limited
-# Subject: CN=Entrust.net Secure Server Certification Authority O=Entrust.net OU=www.entrust.net/CPS incorp. by ref. (limits liab.)/(c) 1999 Entrust.net Limited
-# Label: "Entrust.net Secure Server CA"
-# Serial: 927650371
-# MD5 Fingerprint: df:f2:80:73:cc:f1:e6:61:73:fc:f5:42:e9:c5:7c:ee
-# SHA1 Fingerprint: 99:a6:9b:e6:1a:fe:88:6b:4d:2b:82:00:7c:b8:54:fc:31:7e:15:39
-# SHA256 Fingerprint: 62:f2:40:27:8c:56:4c:4d:d8:bf:7d:9d:4f:6f:36:6e:a8:94:d2:2f:5f:34:d9:89:a9:83:ac:ec:2f:ff:ed:50
------BEGIN CERTIFICATE-----
-MIIE2DCCBEGgAwIBAgIEN0rSQzANBgkqhkiG9w0BAQUFADCBwzELMAkGA1UEBhMC
-VVMxFDASBgNVBAoTC0VudHJ1c3QubmV0MTswOQYDVQQLEzJ3d3cuZW50cnVzdC5u
-ZXQvQ1BTIGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMc
-KGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDE6MDgGA1UEAxMxRW50cnVzdC5u
-ZXQgU2VjdXJlIFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw05OTA1
-MjUxNjA5NDBaFw0xOTA1MjUxNjM5NDBaMIHDMQswCQYDVQQGEwJVUzEUMBIGA1UE
-ChMLRW50cnVzdC5uZXQxOzA5BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5j
-b3JwLiBieSByZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBF
-bnRydXN0Lm5ldCBMaW1pdGVkMTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUg
-U2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGdMA0GCSqGSIb3DQEBAQUA
-A4GLADCBhwKBgQDNKIM0VBuJ8w+vN5Ex/68xYMmo6LIQaO2f55M28Qpku0f1BBc/
-I0dNxScZgSYMVHINiC3ZH5oSn7yzcdOAGT9HZnuMNSjSuQrfJNqc1lB5gXpa0zf3
-wkrYKZImZNHkmGw6AIr1NJtl+O3jEP/9uElY3KDegjlrgbEWGWG5VLbmQwIBA6OC
-AdcwggHTMBEGCWCGSAGG+EIBAQQEAwIABzCCARkGA1UdHwSCARAwggEMMIHeoIHb
-oIHYpIHVMIHSMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxOzA5
-BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5jb3JwLiBieSByZWYuIChsaW1p
-dHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBFbnRydXN0Lm5ldCBMaW1pdGVk
-MTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENlcnRpZmljYXRp
-b24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMCmgJ6AlhiNodHRwOi8vd3d3LmVu
-dHJ1c3QubmV0L0NSTC9uZXQxLmNybDArBgNVHRAEJDAigA8xOTk5MDUyNTE2MDk0
-MFqBDzIwMTkwNTI1MTYwOTQwWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAU8Bdi
-E1U9s/8KAGv7UISX8+1i0BowHQYDVR0OBBYEFPAXYhNVPbP/CgBr+1CEl/PtYtAa
-MAwGA1UdEwQFMAMBAf8wGQYJKoZIhvZ9B0EABAwwChsEVjQuMAMCBJAwDQYJKoZI
-hvcNAQEFBQADgYEAkNwwAvpkdMKnCqV8IY00F6j7Rw7/JXyNEwr75Ji174z4xRAN
-95K+8cPV1ZVqBLssziY2ZcgxxufuP+NXdYR6Ee9GTxj005i7qIcyunL2POI9n9cd
-2cNgQ4xYDiKWL2KjLB+6rQXvqzJ4h6BUcxm1XAX5Uj5tLUUL9wqT6u0G+bI=
------END CERTIFICATE-----
-
-# Issuer: CN=Entrust.net Certification Authority (2048) O=Entrust.net OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.)/(c) 1999 Entrust.net Limited
-# Subject: CN=Entrust.net Certification Authority (2048) O=Entrust.net OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.)/(c) 1999 Entrust.net Limited
-# Label: "Entrust.net Premium 2048 Secure Server CA"
-# Serial: 946059622
-# MD5 Fingerprint: ba:21:ea:20:d6:dd:db:8f:c1:57:8b:40:ad:a1:fc:fc
-# SHA1 Fingerprint: 80:1d:62:d0:7b:44:9d:5c:5c:03:5c:98:ea:61:fa:44:3c:2a:58:fe
-# SHA256 Fingerprint: d1:c3:39:ea:27:84:eb:87:0f:93:4f:c5:63:4e:4a:a9:ad:55:05:01:64:01:f2:64:65:d3:7a:57:46:63:35:9f
------BEGIN CERTIFICATE-----
-MIIEXDCCA0SgAwIBAgIEOGO5ZjANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChML
-RW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBp
-bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5
-IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENlcnRp
-ZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQxNzUwNTFaFw0xOTEy
-MjQxODIwNTFaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3d3d3
-LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxp
-YWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEG
-A1UEAxMqRW50cnVzdC5uZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgp
-MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArU1LqRKGsuqjIAcVFmQq
-K0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOLGp18EzoOH1u3Hs/lJBQe
-sYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSrhRSGlVuX
-MlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVT
-XTzWnLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/
-HoZdenoVve8AjhUiVBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH
-4QIDAQABo3QwcjARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAUVeSB0RGA
-vtiJuQijMfmhJAkWuXAwHQYDVR0OBBYEFFXkgdERgL7YibkIozH5oSQJFrlwMB0G
-CSqGSIb2fQdBAAQQMA4bCFY1LjA6NC4wAwIEkDANBgkqhkiG9w0BAQUFAAOCAQEA
-WUesIYSKF8mciVMeuoCFGsY8Tj6xnLZ8xpJdGGQC49MGCBFhfGPjK50xA3B20qMo
-oPS7mmNz7W3lKtvtFKkrxjYR0CvrB4ul2p5cGZ1WEvVUKcgF7bISKo30Axv/55IQ
-h7A6tcOdBTcSo8f0FbnVpDkWm1M6I5HxqIKiaohowXkCIryqptau37AUX7iH0N18
-f3v/rxzP5tsHrV7bhZ3QKw0z2wTR5klAEyt2+z7pnIkPFc4YsIV4IU9rTw76NmfN
-B/L/CNDi3tm/Kq+4h4YhPATKt5Rof8886ZjXOP/swNlQ8C5LWK5Gb9Auw2DaclVy
-vUxFnmG6v4SBkgPR0ml8xQ==
------END CERTIFICATE-----
-
-# Issuer: CN=Baltimore CyberTrust Root O=Baltimore OU=CyberTrust
-# Subject: CN=Baltimore CyberTrust Root O=Baltimore OU=CyberTrust
-# Label: "Baltimore CyberTrust Root"
-# Serial: 33554617
-# MD5 Fingerprint: ac:b6:94:a5:9c:17:e0:d7:91:52:9b:b1:97:06:a6:e4
-# SHA1 Fingerprint: d4:de:20:d0:5e:66:fc:53:fe:1a:50:88:2c:78:db:28:52:ca:e4:74
-# SHA256 Fingerprint: 16:af:57:a9:f6:76:b0:ab:12:60:95:aa:5e:ba:de:f2:2a:b3:11:19:d6:44:ac:95:cd:4b:93:db:f3:f2:6a:eb
------BEGIN CERTIFICATE-----
-MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ
-RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD
-VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoX
-DTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9y
-ZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVy
-VHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKr
-mD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjr
-IZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeK
-mpYcqWe4PwzV9/lSEy/CG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSu
-XmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZy
-dc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/ye
-jl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1
-BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3
-DQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT92
-9hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx
-jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0
-Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhz
-ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS
-R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp
------END CERTIFICATE-----
-
-# Issuer: CN=Equifax Secure Global eBusiness CA-1 O=Equifax Secure Inc.
-# Subject: CN=Equifax Secure Global eBusiness CA-1 O=Equifax Secure Inc.
-# Label: "Equifax Secure Global eBusiness CA"
-# Serial: 1
-# MD5 Fingerprint: 8f:5d:77:06:27:c4:98:3c:5b:93:78:e7:d7:7d:9b:cc
-# SHA1 Fingerprint: 7e:78:4a:10:1c:82:65:cc:2d:e1:f1:6d:47:b4:40:ca:d9:0a:19:45
-# SHA256 Fingerprint: 5f:0b:62:ea:b5:e3:53:ea:65:21:65:16:58:fb:b6:53:59:f4:43:28:0a:4a:fb:d1:04:d7:7d:10:f9:f0:4c:07
------BEGIN CERTIFICATE-----
-MIICkDCCAfmgAwIBAgIBATANBgkqhkiG9w0BAQQFADBaMQswCQYDVQQGEwJVUzEc
-MBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5jLjEtMCsGA1UEAxMkRXF1aWZheCBT
-ZWN1cmUgR2xvYmFsIGVCdXNpbmVzcyBDQS0xMB4XDTk5MDYyMTA0MDAwMFoXDTIw
-MDYyMTA0MDAwMFowWjELMAkGA1UEBhMCVVMxHDAaBgNVBAoTE0VxdWlmYXggU2Vj
-dXJlIEluYy4xLTArBgNVBAMTJEVxdWlmYXggU2VjdXJlIEdsb2JhbCBlQnVzaW5l
-c3MgQ0EtMTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAuucXkAJlsTRVPEnC
-UdXfp9E3j9HngXNBUmCbnaEXJnitx7HoJpQytd4zjTov2/KaelpzmKNc6fuKcxtc
-58O/gGzNqfTWK8D3+ZmqY6KxRwIP1ORROhI8bIpaVIRw28HFkM9yRcuoWcDNM50/
-o5brhTMhHD4ePmBudpxnhcXIw2ECAwEAAaNmMGQwEQYJYIZIAYb4QgEBBAQDAgAH
-MA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUvqigdHJQa0S3ySPY+6j/s1dr
-aGwwHQYDVR0OBBYEFL6ooHRyUGtEt8kj2Puo/7NXa2hsMA0GCSqGSIb3DQEBBAUA
-A4GBADDiAVGqx+pf2rnQZQ8w1j7aDRRJbpGTJxQx78T3LUX47Me/okENI7SS+RkA
-Z70Br83gcfxaz2TE4JaY0KNA4gGK7ycH8WUBikQtBmV1UsCGECAhX2xrD2yuCRyv
-8qIYNMR1pHMc8Y3c7635s3a0kr/clRAevsvIO1qEYBlWlKlV
------END CERTIFICATE-----
-
-# Issuer: CN=Equifax Secure eBusiness CA-1 O=Equifax Secure Inc.
-# Subject: CN=Equifax Secure eBusiness CA-1 O=Equifax Secure Inc.
-# Label: "Equifax Secure eBusiness CA 1"
-# Serial: 4
-# MD5 Fingerprint: 64:9c:ef:2e:44:fc:c6:8f:52:07:d0:51:73:8f:cb:3d
-# SHA1 Fingerprint: da:40:18:8b:91:89:a3:ed:ee:ae:da:97:fe:2f:9d:f5:b7:d1:8a:41
-# SHA256 Fingerprint: cf:56:ff:46:a4:a1:86:10:9d:d9:65:84:b5:ee:b5:8a:51:0c:42:75:b0:e5:f9:4f:40:bb:ae:86:5e:19:f6:73
------BEGIN CERTIFICATE-----
-MIICgjCCAeugAwIBAgIBBDANBgkqhkiG9w0BAQQFADBTMQswCQYDVQQGEwJVUzEc
-MBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1aWZheCBT
-ZWN1cmUgZUJ1c2luZXNzIENBLTEwHhcNOTkwNjIxMDQwMDAwWhcNMjAwNjIxMDQw
-MDAwWjBTMQswCQYDVQQGEwJVUzEcMBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5j
-LjEmMCQGA1UEAxMdRXF1aWZheCBTZWN1cmUgZUJ1c2luZXNzIENBLTEwgZ8wDQYJ
-KoZIhvcNAQEBBQADgY0AMIGJAoGBAM4vGbwXt3fek6lfWg0XTzQaDJj0ItlZ1MRo
-RvC0NcWFAyDGr0WlIVFFQesWWDYyb+JQYmT5/VGcqiTZ9J2DKocKIdMSODRsjQBu
-WqDZQu4aIZX5UkxVWsUPOE9G+m34LjXWHXzr4vCwdYDIqROsvojvOm6rXyo4YgKw
-Env+j6YDAgMBAAGjZjBkMBEGCWCGSAGG+EIBAQQEAwIABzAPBgNVHRMBAf8EBTAD
-AQH/MB8GA1UdIwQYMBaAFEp4MlIR21kWNl7fwRQ2QGpHfEyhMB0GA1UdDgQWBBRK
-eDJSEdtZFjZe38EUNkBqR3xMoTANBgkqhkiG9w0BAQQFAAOBgQB1W6ibAxHm6VZM
-zfmpTMANmvPMZWnmJXbMWbfWVMMdzZmsGd20hdXgPfxiIKeES1hl8eL5lSE/9dR+
-WB5Hh1Q+WKG1tfgq73HnvMP2sUlG4tega+VWeponmHxGYhTnyfxuAxJ5gDgdSIKN
-/Bf+KpYrtWKmpj29f5JZzVoqgrI3eQ==
------END CERTIFICATE-----
-
-# Issuer: O=Equifax Secure OU=Equifax Secure eBusiness CA-2
-# Subject: O=Equifax Secure OU=Equifax Secure eBusiness CA-2
-# Label: "Equifax Secure eBusiness CA 2"
-# Serial: 930140085
-# MD5 Fingerprint: aa:bf:bf:64:97:da:98:1d:6f:c6:08:3a:95:70:33:ca
-# SHA1 Fingerprint: 39:4f:f6:85:0b:06:be:52:e5:18:56:cc:10:e1:80:e8:82:b3:85:cc
-# SHA256 Fingerprint: 2f:27:4e:48:ab:a4:ac:7b:76:59:33:10:17:75:50:6d:c3:0e:e3:8e:f6:ac:d5:c0:49:32:cf:e0:41:23:42:20
------BEGIN CERTIFICATE-----
-MIIDIDCCAomgAwIBAgIEN3DPtTANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV
-UzEXMBUGA1UEChMORXF1aWZheCBTZWN1cmUxJjAkBgNVBAsTHUVxdWlmYXggU2Vj
-dXJlIGVCdXNpbmVzcyBDQS0yMB4XDTk5MDYyMzEyMTQ0NVoXDTE5MDYyMzEyMTQ0
-NVowTjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkVxdWlmYXggU2VjdXJlMSYwJAYD
-VQQLEx1FcXVpZmF4IFNlY3VyZSBlQnVzaW5lc3MgQ0EtMjCBnzANBgkqhkiG9w0B
-AQEFAAOBjQAwgYkCgYEA5Dk5kx5SBhsoNviyoynF7Y6yEb3+6+e0dMKP/wXn2Z0G
-vxLIPw7y1tEkshHe0XMJitSxLJgJDR5QRrKDpkWNYmi7hRsgcDKqQM2mll/EcTc/
-BPO3QSQ5BxoeLmFYoBIL5aXfxavqN3HMHMg3OrmXUqesxWoklE6ce8/AatbfIb0C
-AwEAAaOCAQkwggEFMHAGA1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEX
-MBUGA1UEChMORXF1aWZheCBTZWN1cmUxJjAkBgNVBAsTHUVxdWlmYXggU2VjdXJl
-IGVCdXNpbmVzcyBDQS0yMQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTkw
-NjIzMTIxNDQ1WjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUUJ4L6q9euSBIplBq
-y/3YIHqngnYwHQYDVR0OBBYEFFCeC+qvXrkgSKZQasv92CB6p4J2MAwGA1UdEwQF
-MAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUA
-A4GBAAyGgq3oThr1jokn4jVYPSm0B482UJW/bsGe68SQsoWou7dC4A8HOd/7npCy
-0cE+U58DRLB+S/Rv5Hwf5+Kx5Lia78O9zt4LMjTZ3ijtM2vE1Nc9ElirfQkty3D1
-E4qUoSek1nDFbZS1yX2doNLGCEnZZpum0/QL3MUmV+GRMOrN
------END CERTIFICATE-----
-
-# Issuer: CN=AddTrust Class 1 CA Root O=AddTrust AB OU=AddTrust TTP Network
-# Subject: CN=AddTrust Class 1 CA Root O=AddTrust AB OU=AddTrust TTP Network
-# Label: "AddTrust Low-Value Services Root"
-# Serial: 1
-# MD5 Fingerprint: 1e:42:95:02:33:92:6b:b9:5f:c0:7f:da:d6:b2:4b:fc
-# SHA1 Fingerprint: cc:ab:0e:a0:4c:23:01:d6:69:7b:dd:37:9f:cd:12:eb:24:e3:94:9d
-# SHA256 Fingerprint: 8c:72:09:27:9a:c0:4e:27:5e:16:d0:7f:d3:b7:75:e8:01:54:b5:96:80:46:e3:1f:52:dd:25:76:63:24:e9:a7
------BEGIN CERTIFICATE-----
-MIIEGDCCAwCgAwIBAgIBATANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQGEwJTRTEU
-MBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3
-b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3QwHhcNMDAwNTMw
-MTAzODMxWhcNMjAwNTMwMTAzODMxWjBlMQswCQYDVQQGEwJTRTEUMBIGA1UEChML
-QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYD
-VQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUA
-A4IBDwAwggEKAoIBAQCWltQhSWDia+hBBwzexODcEyPNwTXH+9ZOEQpnXvUGW2ul
-CDtbKRY654eyNAbFvAWlA3yCyykQruGIgb3WntP+LVbBFc7jJp0VLhD7Bo8wBN6n
-tGO0/7Gcrjyvd7ZWxbWroulpOj0OM3kyP3CCkplhbY0wCI9xP6ZIVxn4JdxLZlyl
-dI+Yrsj5wAYi56xz36Uu+1LcsRVlIPo1Zmne3yzxbrww2ywkEtvrNTVokMsAsJch
-PXQhI2U0K7t4WaPW4XY5mqRJjox0r26kmqPZm9I4XJuiGMx1I4S+6+JNM3GOGvDC
-+Mcdoq0Dlyz4zyXG9rgkMbFjXZJ/Y/AlyVMuH79NAgMBAAGjgdIwgc8wHQYDVR0O
-BBYEFJWxtPCUtr3H2tERCSG+wa9J/RB7MAsGA1UdDwQEAwIBBjAPBgNVHRMBAf8E
-BTADAQH/MIGPBgNVHSMEgYcwgYSAFJWxtPCUtr3H2tERCSG+wa9J/RB7oWmkZzBl
-MQswCQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFk
-ZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENB
-IFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBACxtZBsfzQ3duQH6lmM0MkhHma6X
-7f1yFqZzR1r0693p9db7RcwpiURdv0Y5PejuvE1Uhh4dbOMXJ0PhiVYrqW9yTkkz
-43J8KiOavD7/KCrto/8cI7pDVwlnTUtiBi34/2ydYB7YHEt9tTEv2dB8Xfjea4MY
-eDdXL+gzB2ffHsdrKpV2ro9Xo/D0UrSpUwjP4E/TelOL/bscVjby/rK25Xa71SJl
-pz/+0WatC7xrmYbvP33zGDLKe8bjq2RGlfgmadlVg3sslgf/WSxEo8bl6ancoWOA
-WiFeIc9TVPC6b4nbqKqVz4vjccweGyBECMB6tkD9xOQ14R0WHNC8K47Wcdk=
------END CERTIFICATE-----
-
-# Issuer: CN=AddTrust External CA Root O=AddTrust AB OU=AddTrust External TTP Network
-# Subject: CN=AddTrust External CA Root O=AddTrust AB OU=AddTrust External TTP Network
-# Label: "AddTrust External Root"
-# Serial: 1
-# MD5 Fingerprint: 1d:35:54:04:85:78:b0:3f:42:42:4d:bf:20:73:0a:3f
-# SHA1 Fingerprint: 02:fa:f3:e2:91:43:54:68:60:78:57:69:4d:f5:e4:5b:68:85:18:68
-# SHA256 Fingerprint: 68:7f:a4:51:38:22:78:ff:f0:c8:b1:1f:8d:43:d5:76:67:1c:6e:b2:bc:ea:b4:13:fb:83:d9:65:d0:6d:2f:f2
------BEGIN CERTIFICATE-----
-MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEU
-MBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFs
-IFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290
-MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFowbzELMAkGA1UEBhMCU0Ux
-FDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRUcnVzdCBFeHRlcm5h
-bCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0EgUm9v
-dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvt
-H7xsD821+iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9
-uMq/NzgtHj6RQa1wVsfwTz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzX
-mk6vBbOmcZSccbNQYArHE504B4YCqOmoaSYYkKtMsE8jqzpPhNjfzp/haW+710LX
-a0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy2xSoRcRdKn23tNbE7qzN
-E0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv77+ldU9U0
-WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYD
-VR0PBAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0
-Jvf6xCZU7wO94CTLVBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRU
-cnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsx
-IjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENBIFJvb3SCAQEwDQYJKoZIhvcN
-AQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZlj7DYd7usQWxH
-YINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5
-6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvC
-Nr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEX
-c4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5a
-mnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ=
------END CERTIFICATE-----
-
-# Issuer: CN=AddTrust Public CA Root O=AddTrust AB OU=AddTrust TTP Network
-# Subject: CN=AddTrust Public CA Root O=AddTrust AB OU=AddTrust TTP Network
-# Label: "AddTrust Public Services Root"
-# Serial: 1
-# MD5 Fingerprint: c1:62:3e:23:c5:82:73:9c:03:59:4b:2b:e9:77:49:7f
-# SHA1 Fingerprint: 2a:b6:28:48:5e:78:fb:f3:ad:9e:79:10:dd:6b:df:99:72:2c:96:e5
-# SHA256 Fingerprint: 07:91:ca:07:49:b2:07:82:aa:d3:c7:d7:bd:0c:df:c9:48:58:35:84:3e:b2:d7:99:60:09:ce:43:ab:6c:69:27
------BEGIN CERTIFICATE-----
-MIIEFTCCAv2gAwIBAgIBATANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJTRTEU
-MBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3
-b3JrMSAwHgYDVQQDExdBZGRUcnVzdCBQdWJsaWMgQ0EgUm9vdDAeFw0wMDA1MzAx
-MDQxNTBaFw0yMDA1MzAxMDQxNTBaMGQxCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtB
-ZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQIE5ldHdvcmsxIDAeBgNV
-BAMTF0FkZFRydXN0IFB1YmxpYyBDQSBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOC
-AQ8AMIIBCgKCAQEA6Rowj4OIFMEg2Dybjxt+A3S72mnTRqX4jsIMEZBRpS9mVEBV
-6tsfSlbunyNu9DnLoblv8n75XYcmYZ4c+OLspoH4IcUkzBEMP9smcnrHAZcHF/nX
-GCwwfQ56HmIexkvA/X1id9NEHif2P0tEs7c42TkfYNVRknMDtABp4/MUTu7R3AnP
-dzRGULD4EfL+OHn3Bzn+UZKXC1sIXzSGAa2Il+tmzV7R/9x98oTaunet3IAIx6eH
-1lWfl2royBFkuucZKT8Rs3iQhCBSWxHveNCD9tVIkNAwHM+A+WD+eeSI8t0A65RF
-62WUaUC6wNW0uLp9BBGo6zEFlpROWCGOn9Bg/QIDAQABo4HRMIHOMB0GA1UdDgQW
-BBSBPjfYkrAfd59ctKtzquf2NGAv+jALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/BAUw
-AwEB/zCBjgYDVR0jBIGGMIGDgBSBPjfYkrAfd59ctKtzquf2NGAv+qFopGYwZDEL
-MAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQLExRBZGRU
-cnVzdCBUVFAgTmV0d29yazEgMB4GA1UEAxMXQWRkVHJ1c3QgUHVibGljIENBIFJv
-b3SCAQEwDQYJKoZIhvcNAQEFBQADggEBAAP3FUr4JNojVhaTdt02KLmuG7jD8WS6
-IBh4lSknVwW8fCr0uVFV2ocC3g8WFzH4qnkuCRO7r7IgGRLlk/lL+YPoRNWyQSW/
-iHVv/xD8SlTQX/D67zZzfRs2RcYhbbQVuE7PnFylPVoAjgbjPGsye/Kf8Lb93/Ao
-GEjwxrzQvzSAlsJKsW2Ox5BF3i9nrEUEo3rcVZLJR2bYGozH7ZxOmuASu7VqTITh
-4SINhwBk/ox9Yjllpu9CtoAlEmEBqCQTcAARJl/6NVDFSMwGR+gn2HCNX2TmoUQm
-XiLsks3/QppEIW1cxeMiHV9HEufOX1362KqxMy3ZdvJOOjMMK7MtkAY=
------END CERTIFICATE-----
-
-# Issuer: CN=AddTrust Qualified CA Root O=AddTrust AB OU=AddTrust TTP Network
-# Subject: CN=AddTrust Qualified CA Root O=AddTrust AB OU=AddTrust TTP Network
-# Label: "AddTrust Qualified Certificates Root"
-# Serial: 1
-# MD5 Fingerprint: 27:ec:39:47:cd:da:5a:af:e2:9a:01:65:21:a9:4c:bb
-# SHA1 Fingerprint: 4d:23:78:ec:91:95:39:b5:00:7f:75:8f:03:3b:21:1e:c5:4d:8b:cf
-# SHA256 Fingerprint: 80:95:21:08:05:db:4b:bc:35:5e:44:28:d8:fd:6e:c2:cd:e3:ab:5f:b9:7a:99:42:98:8e:b8:f4:dc:d0:60:16
------BEGIN CERTIFICATE-----
-MIIEHjCCAwagAwIBAgIBATANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQGEwJTRTEU
-MBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3
-b3JrMSMwIQYDVQQDExpBZGRUcnVzdCBRdWFsaWZpZWQgQ0EgUm9vdDAeFw0wMDA1
-MzAxMDQ0NTBaFw0yMDA1MzAxMDQ0NTBaMGcxCzAJBgNVBAYTAlNFMRQwEgYDVQQK
-EwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQIE5ldHdvcmsxIzAh
-BgNVBAMTGkFkZFRydXN0IFF1YWxpZmllZCBDQSBSb290MIIBIjANBgkqhkiG9w0B
-AQEFAAOCAQ8AMIIBCgKCAQEA5B6a/twJWoekn0e+EV+vhDTbYjx5eLfpMLXsDBwq
-xBb/4Oxx64r1EW7tTw2R0hIYLUkVAcKkIhPHEWT/IhKauY5cLwjPcWqzZwFZ8V1G
-87B4pfYOQnrjfxvM0PC3KP0q6p6zsLkEqv32x7SxuCqg+1jxGaBvcCV+PmlKfw8i
-2O+tCBGaKZnhqkRFmhJePp1tUvznoD1oL/BLcHwTOK28FSXx1s6rosAx1i+f4P8U
-WfyEk9mHfExUE+uf0S0R+Bg6Ot4l2ffTQO2kBhLEO+GRwVY18BTcZTYJbqukB8c1
-0cIDMzZbdSZtQvESa0NvS3GU+jQd7RNuyoB/mC9suWXY6QIDAQABo4HUMIHRMB0G
-A1UdDgQWBBQ5lYtii1zJ1IC6WA+XPxUIQ8yYpzALBgNVHQ8EBAMCAQYwDwYDVR0T
-AQH/BAUwAwEB/zCBkQYDVR0jBIGJMIGGgBQ5lYtii1zJ1IC6WA+XPxUIQ8yYp6Fr
-pGkwZzELMAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQL
-ExRBZGRUcnVzdCBUVFAgTmV0d29yazEjMCEGA1UEAxMaQWRkVHJ1c3QgUXVhbGlm
-aWVkIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBABmrder4i2VhlRO6aQTv
-hsoToMeqT2QbPxj2qC0sVY8FtzDqQmodwCVRLae/DLPt7wh/bDxGGuoYQ992zPlm
-hpwsaPXpF/gxsxjE1kh9I0xowX67ARRvxdlu3rsEQmr49lx95dr6h+sNNVJn0J6X
-dgWTP5XHAeZpVTh/EGGZyeNfpso+gmNIquIISD6q8rKFYqa0p9m9N5xotS1WfbC3
-P6CxB9bpT9zeRXEwMn8bLgn5v1Kh7sKAPgZcLlVAwRv1cEWw3F369nJad9Jjzc9Y
-iQBCYz95OdBEsIJuQRno3eDBiFrRHnGTHyQwdOUeqN48Jzd/g66ed8/wMLH/S5no
-xqE=
------END CERTIFICATE-----
-
-# Issuer: CN=Entrust Root Certification Authority O=Entrust, Inc. OU=www.entrust.net/CPS is incorporated by reference/(c) 2006 Entrust, Inc.
-# Subject: CN=Entrust Root Certification Authority O=Entrust, Inc. OU=www.entrust.net/CPS is incorporated by reference/(c) 2006 Entrust, Inc.
-# Label: "Entrust Root Certification Authority"
-# Serial: 1164660820
-# MD5 Fingerprint: d6:a5:c3:ed:5d:dd:3e:00:c1:3d:87:92:1f:1d:3f:e4
-# SHA1 Fingerprint: b3:1e:b1:b7:40:e3:6c:84:02:da:dc:37:d4:4d:f5:d4:67:49:52:f9
-# SHA256 Fingerprint: 73:c1:76:43:4f:1b:c6:d5:ad:f4:5b:0e:76:e7:27:28:7c:8d:e5:76:16:c1:e6:e6:14:1a:2b:2c:bc:7d:8e:4c
------BEGIN CERTIFICATE-----
-MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMC
-VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0
-Lm5ldC9DUFMgaXMgaW5jb3Jwb3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMW
-KGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsGA1UEAxMkRW50cnVzdCBSb290IENl
-cnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0MloXDTI2MTEyNzIw
-NTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMTkw
-NwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSBy
-ZWZlcmVuY2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNV
-BAMTJEVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJ
-KoZIhvcNAQEBBQADggEPADCCAQoCggEBALaVtkNC+sZtKm9I35RMOVcF7sN5EUFo
-Nu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYszA9u3g3s+IIRe7bJWKKf4
-4LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOwwCj0Yzfv9
-KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGI
-rb68j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi
-94DkZfs0Nw4pgHBNrziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOB
-sDCBrTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAi
-gA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1MzQyWjAfBgNVHSMEGDAWgBRo
-kORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DHhmak8fdLQ/uE
-vW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA
-A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9t
-O1KzKtvn1ISMY/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6Zua
-AGAT/3B+XxFNSRuzFVJ7yVTav52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP
-9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTSW3iDVuycNsMm4hH2Z0kdkquM++v/
-eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0tHuu2guQOHXvgR1m
-0vdXcDazv/wor3ElhVsT/h5/WrQ8
------END CERTIFICATE-----
-
-# Issuer: CN=GeoTrust Global CA O=GeoTrust Inc.
-# Subject: CN=GeoTrust Global CA O=GeoTrust Inc.
-# Label: "GeoTrust Global CA"
-# Serial: 144470
-# MD5 Fingerprint: f7:75:ab:29:fb:51:4e:b7:77:5e:ff:05:3c:99:8e:f5
-# SHA1 Fingerprint: de:28:f4:a4:ff:e5:b9:2f:a3:c5:03:d1:a3:49:a7:f9:96:2a:82:12
-# SHA256 Fingerprint: ff:85:6a:2d:25:1d:cd:88:d3:66:56:f4:50:12:67:98:cf:ab:aa:de:40:79:9c:72:2d:e4:d2:b5:db:36:a7:3a
------BEGIN CERTIFICATE-----
-MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT
-MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i
-YWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQG
-EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UEAxMSR2VvVHJ1c3Qg
-R2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2swYYzD9
-9BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjoBbdq
-fnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDv
-iS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU
-1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+
-bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoW
-MPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTA
-ephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1l
-uMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKIn
-Z57QzxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfS
-tQWVYrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF
-PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Un
-hw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeXxx12E6nV
-5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvmMw==
------END CERTIFICATE-----
-
-# Issuer: CN=GeoTrust Global CA 2 O=GeoTrust Inc.
-# Subject: CN=GeoTrust Global CA 2 O=GeoTrust Inc.
-# Label: "GeoTrust Global CA 2"
-# Serial: 1
-# MD5 Fingerprint: 0e:40:a7:6c:de:03:5d:8f:d1:0f:e4:d1:8d:f9:6c:a9
-# SHA1 Fingerprint: a9:e9:78:08:14:37:58:88:f2:05:19:b0:6d:2b:0d:2b:60:16:90:7d
-# SHA256 Fingerprint: ca:2d:82:a0:86:77:07:2f:8a:b6:76:4f:f0:35:67:6c:fe:3e:5e:32:5e:01:21:72:df:3f:92:09:6d:b7:9b:85
------BEGIN CERTIFICATE-----
-MIIDZjCCAk6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBEMQswCQYDVQQGEwJVUzEW
-MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3QgR2xvYmFs
-IENBIDIwHhcNMDQwMzA0MDUwMDAwWhcNMTkwMzA0MDUwMDAwWjBEMQswCQYDVQQG
-EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3Qg
-R2xvYmFsIENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDvPE1A
-PRDfO1MA4Wf+lGAVPoWI8YkNkMgoI5kF6CsgncbzYEbYwbLVjDHZ3CB5JIG/NTL8
-Y2nbsSpr7iFY8gjpeMtvy/wWUsiRxP89c96xPqfCfWbB9X5SJBri1WeR0IIQ13hL
-TytCOb1kLUCgsBDTOEhGiKEMuzozKmKY+wCdE1l/bztyqu6mD4b5BWHqZ38MN5aL
-5mkWRxHCJ1kDs6ZgwiFAVvqgx306E+PsV8ez1q6diYD3Aecs9pYrEw15LNnA5IZ7
-S4wMcoKK+xfNAGw6EzywhIdLFnopsk/bHdQL82Y3vdj2V7teJHq4PIu5+pIaGoSe
-2HSPqht/XvT+RSIhAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE
-FHE4NvICMVNHK266ZUapEBVYIAUJMB8GA1UdIwQYMBaAFHE4NvICMVNHK266ZUap
-EBVYIAUJMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQUFAAOCAQEAA/e1K6td
-EPx7srJerJsOflN4WT5CBP51o62sgU7XAotexC3IUnbHLB/8gTKY0UvGkpMzNTEv
-/NgdRN3ggX+d6YvhZJFiCzkIjKx0nVnZellSlxG5FntvRdOW2TF9AjYPnDtuzywN
-A0ZF66D0f0hExghAzN4bcLUprbqLOzRldRtxIR0sFAqwlpW41uryZfspuk/qkZN0
-abby/+Ea0AzRdoXLiiW9l14sbxWZJue2Kf8i7MkCx1YAzUm5s2x7UwQa4qjJqhIF
-I8LO57sEAszAR6LkxCkvW0VXiVHuPOtSCP8HNR6fNWpHSlaY0VqFH4z1Ir+rzoPz
-4iIprn2DQKi6bA==
------END CERTIFICATE-----
-
-# Issuer: CN=GeoTrust Universal CA O=GeoTrust Inc.
-# Subject: CN=GeoTrust Universal CA O=GeoTrust Inc.
-# Label: "GeoTrust Universal CA"
-# Serial: 1
-# MD5 Fingerprint: 92:65:58:8b:a2:1a:31:72:73:68:5c:b4:a5:7a:07:48
-# SHA1 Fingerprint: e6:21:f3:35:43:79:05:9a:4b:68:30:9d:8a:2f:74:22:15:87:ec:79
-# SHA256 Fingerprint: a0:45:9b:9f:63:b2:25:59:f5:fa:5d:4c:6d:b3:f9:f7:2f:f1:93:42:03:35:78:f0:73:bf:1d:1b:46:cb:b9:12
------BEGIN CERTIFICATE-----
-MIIFaDCCA1CgAwIBAgIBATANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJVUzEW
-MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEeMBwGA1UEAxMVR2VvVHJ1c3QgVW5pdmVy
-c2FsIENBMB4XDTA0MDMwNDA1MDAwMFoXDTI5MDMwNDA1MDAwMFowRTELMAkGA1UE
-BhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xHjAcBgNVBAMTFUdlb1RydXN0
-IFVuaXZlcnNhbCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKYV
-VaCjxuAfjJ0hUNfBvitbtaSeodlyWL0AG0y/YckUHUWCq8YdgNY96xCcOq9tJPi8
-cQGeBvV8Xx7BDlXKg5pZMK4ZyzBIle0iN430SppyZj6tlcDgFgDgEB8rMQ7XlFTT
-QjOgNB0eRXbdT8oYN+yFFXoZCPzVx5zw8qkuEKmS5j1YPakWaDwvdSEYfyh3peFh
-F7em6fgemdtzbvQKoiFs7tqqhZJmr/Z6a4LauiIINQ/PQvE1+mrufislzDoR5G2v
-c7J2Ha3QsnhnGqQ5HFELZ1aD/ThdDc7d8Lsrlh/eezJS/R27tQahsiFepdaVaH/w
-mZ7cRQg+59IJDTWU3YBOU5fXtQlEIGQWFwMCTFMNaN7VqnJNk22CDtucvc+081xd
-VHppCZbW2xHBjXWotM85yM48vCR85mLK4b19p71XZQvk/iXttmkQ3CgaRr0BHdCX
-teGYO8A3ZNY9lO4L4fUorgtWv3GLIylBjobFS1J72HGrH4oVpjuDWtdYAVHGTEHZ
-f9hBZ3KiKN9gg6meyHv8U3NyWfWTehd2Ds735VzZC1U0oqpbtWpU5xPKV+yXbfRe
-Bi9Fi1jUIxaS5BZuKGNZMN9QAZxjiRqf2xeUgnA3wySemkfWWspOqGmJch+RbNt+
-nhutxx9z3SxPGWX9f5NAEC7S8O08ni4oPmkmM8V7AgMBAAGjYzBhMA8GA1UdEwEB
-/wQFMAMBAf8wHQYDVR0OBBYEFNq7LqqwDLiIJlF0XG0D08DYj3rWMB8GA1UdIwQY
-MBaAFNq7LqqwDLiIJlF0XG0D08DYj3rWMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG
-9w0BAQUFAAOCAgEAMXjmx7XfuJRAyXHEqDXsRh3ChfMoWIawC/yOsjmPRFWrZIRc
-aanQmjg8+uUfNeVE44B5lGiku8SfPeE0zTBGi1QrlaXv9z+ZhP015s8xxtxqv6fX
-IwjhmF7DWgh2qaavdy+3YL1ERmrvl/9zlcGO6JP7/TG37FcREUWbMPEaiDnBTzyn
-ANXH/KttgCJwpQzgXQQpAvvLoJHRfNbDflDVnVi+QTjruXU8FdmbyUqDWcDaU/0z
-uzYYm4UPFd3uLax2k7nZAY1IEKj79TiG8dsKxr2EoyNB3tZ3b4XUhRxQ4K5RirqN
-Pnbiucon8l+f725ZDQbYKxek0nxru18UGkiPGkzns0ccjkxFKyDuSN/n3QmOGKja
-QI2SJhFTYXNd673nxE0pN2HrrDktZy4W1vUAg4WhzH92xH3kt0tm7wNFYGm2DFKW
-koRepqO1pD4r2czYG0eq8kTaT/kD6PAUyz/zg97QwVTjt+gKN02LIFkDMBmhLMi9
-ER/frslKxfMnZmaGrGiR/9nmUxwPi1xpZQomyB40w11Re9epnAahNt3ViZS82eQt
-DF4JbAiXfKM9fJP/P6EUp8+1Xevb2xzEdt+Iub1FBZUbrvxGakyvSOPOrg/Sfuvm
-bJxPgWp6ZKy7PtXny3YuxadIwVyQD8vIP/rmMuGNG2+k5o7Y+SlIis5z/iw=
------END CERTIFICATE-----
-
-# Issuer: CN=GeoTrust Universal CA 2 O=GeoTrust Inc.
-# Subject: CN=GeoTrust Universal CA 2 O=GeoTrust Inc.
-# Label: "GeoTrust Universal CA 2"
-# Serial: 1
-# MD5 Fingerprint: 34:fc:b8:d0:36:db:9e:14:b3:c2:f2:db:8f:e4:94:c7
-# SHA1 Fingerprint: 37:9a:19:7b:41:85:45:35:0c:a6:03:69:f3:3c:2e:af:47:4f:20:79
-# SHA256 Fingerprint: a0:23:4f:3b:c8:52:7c:a5:62:8e:ec:81:ad:5d:69:89:5d:a5:68:0d:c9:1d:1c:b8:47:7f:33:f8:78:b9:5b:0b
------BEGIN CERTIFICATE-----
-MIIFbDCCA1SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBHMQswCQYDVQQGEwJVUzEW
-MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVy
-c2FsIENBIDIwHhcNMDQwMzA0MDUwMDAwWhcNMjkwMzA0MDUwMDAwWjBHMQswCQYD
-VQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1
-c3QgVW5pdmVyc2FsIENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC
-AQCzVFLByT7y2dyxUxpZKeexw0Uo5dfR7cXFS6GqdHtXr0om/Nj1XqduGdt0DE81
-WzILAePb63p3NeqqWuDW6KFXlPCQo3RWlEQwAx5cTiuFJnSCegx2oG9NzkEtoBUG
-FF+3Qs17j1hhNNwqCPkuwwGmIkQcTAeC5lvO0Ep8BNMZcyfwqph/Lq9O64ceJHdq
-XbboW0W63MOhBW9Wjo8QJqVJwy7XQYci4E+GymC16qFjwAGXEHm9ADwSbSsVsaxL
-se4YuU6W3Nx2/zu+z18DwPw76L5GG//aQMJS9/7jOvdqdzXQ2o3rXhhqMcceujwb
-KNZrVMaqW9eiLBsZzKIC9ptZvTdrhrVtgrrY6slWvKk2WP0+GfPtDCapkzj4T8Fd
-IgbQl+rhrcZV4IErKIM6+vR7IVEAvlI4zs1meaj0gVbi0IMJR1FbUGrP20gaXT73
-y/Zl92zxlfgCOzJWgjl6W70viRu/obTo/3+NjN8D8WBOWBFM66M/ECuDmgFz2ZRt
-hAAnZqzwcEAJQpKtT5MNYQlRJNiS1QuUYbKHsu3/mjX/hVTK7URDrBs8FmtISgoc
-QIgfksILAAX/8sgCSqSqqcyZlpwvWOB94b67B9xfBHJcMTTD7F8t4D1kkCLm0ey4
-Lt1ZrtmhN79UNdxzMk+MBB4zsslG8dhcyFVQyWi9qLo2CQIDAQABo2MwYTAPBgNV
-HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAfBgNV
-HSMEGDAWgBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAOBgNVHQ8BAf8EBAMCAYYwDQYJ
-KoZIhvcNAQEFBQADggIBAGbBxiPz2eAubl/oz66wsCVNK/g7WJtAJDday6sWSf+z
-dXkzoS9tcBc0kf5nfo/sm+VegqlVHy/c1FEHEv6sFj4sNcZj/NwQ6w2jqtB8zNHQ
-L1EuxBRa3ugZ4T7GzKQp5y6EqgYweHZUcyiYWTjgAA1i00J9IZ+uPTqM1fp3DRgr
-Fg5fNuH8KrUwJM/gYwx7WBr+mbpCErGR9Hxo4sjoryzqyX6uuyo9DRXcNJW2GHSo
-ag/HtPQTxORb7QrSpJdMKu0vbBKJPfEncKpqA1Ihn0CoZ1Dy81of398j9tx4TuaY
-T1U6U+Pv8vSfx3zYWK8pIpe44L2RLrB27FcRz+8pRPPphXpgY+RdM4kX2TGq2tbz
-GDVyz4crL2MjhF2EjD9XoIj8mZEoJmmZ1I+XRL6O1UixpCgp8RW04eWe3fiPpm8m
-1wk8OhwRDqZsN/etRIcsKMfYdIKz0G9KV7s1KSegi+ghp4dkNl3M2Basx7InQJJV
-OCiNUW7dFGdTbHFcJoRNdVq2fmBWqU2t+5sel/MN2dKXVHfaPRK34B7vCAas+YWH
-6aLcr34YEoP9VhdBLtUpgn2Z9DH2canPLAEnpQW5qrJITirvn5NSUZU8UnOOVkwX
-QMAJKOSLakhT2+zNVVXxxvjpoixMptEmX36vWkzaH6byHCx+rgIW0lbQL1dTR+iS
------END CERTIFICATE-----
-
-# Issuer: CN=America Online Root Certification Authority 1 O=America Online Inc.
-# Subject: CN=America Online Root Certification Authority 1 O=America Online Inc.
-# Label: "America Online Root Certification Authority 1"
-# Serial: 1
-# MD5 Fingerprint: 14:f1:08:ad:9d:fa:64:e2:89:e7:1c:cf:a8:ad:7d:5e
-# SHA1 Fingerprint: 39:21:c1:15:c1:5d:0e:ca:5c:cb:5b:c4:f0:7d:21:d8:05:0b:56:6a
-# SHA256 Fingerprint: 77:40:73:12:c6:3a:15:3d:5b:c0:0b:4e:51:75:9c:df:da:c2:37:dc:2a:33:b6:79:46:e9:8e:9b:fa:68:0a:e3
------BEGIN CERTIFICATE-----
-MIIDpDCCAoygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEc
-MBoGA1UEChMTQW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1lcmljYSBP
-bmxpbmUgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAxMB4XDTAyMDUyODA2
-MDAwMFoXDTM3MTExOTIwNDMwMFowYzELMAkGA1UEBhMCVVMxHDAaBgNVBAoTE0Ft
-ZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJpY2EgT25saW5lIFJvb3Qg
-Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMTCCASIwDQYJKoZIhvcNAQEBBQADggEP
-ADCCAQoCggEBAKgv6KRpBgNHw+kqmP8ZonCaxlCyfqXfaE0bfA+2l2h9LaaLl+lk
-hsmj76CGv2BlnEtUiMJIxUo5vxTjWVXlGbR0yLQFOVwWpeKVBeASrlmLojNoWBym
-1BW32J/X3HGrfpq/m44zDyL9Hy7nBzbvYjnF3cu6JRQj3gzGPTzOggjmZj7aUTsW
-OqMFf6Dch9Wc/HKpoH145LcxVR5lu9RhsCFg7RAycsWSJR74kEoYeEfffjA3PlAb
-2xzTa5qGUwew76wGePiEmf4hjUyAtgyC9mZweRrTT6PP8c9GsEsPPt2IYriMqQko
-O3rHl+Ee5fSfwMCuJKDIodkP1nsmgmkyPacCAwEAAaNjMGEwDwYDVR0TAQH/BAUw
-AwEB/zAdBgNVHQ4EFgQUAK3Zo/Z59m50qX8zPYEX10zPM94wHwYDVR0jBBgwFoAU
-AK3Zo/Z59m50qX8zPYEX10zPM94wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEB
-BQUAA4IBAQB8itEfGDeC4Liwo+1WlchiYZwFos3CYiZhzRAW18y0ZTTQEYqtqKkF
-Zu90821fnZmv9ov761KyBZiibyrFVL0lvV+uyIbqRizBs73B6UlwGBaXCBOMIOAb
-LjpHyx7kADCVW/RFo8AasAFOq73AI25jP4BKxQft3OJvx8Fi8eNy1gTIdGcL+oir
-oQHIb/AUr9KZzVGTfu0uOMe9zkZQPXLjeSWdm4grECDdpbgyn43gKd8hdIaC2y+C
-MMbHNYaz+ZZfRtsMRf3zUMNvxsNIrUam4SdHCh0Om7bCd39j8uB9Gr784N/Xx6ds
-sPmuujz9dLQR6FgNgLzTqIA6me11zEZ7
------END CERTIFICATE-----
-
-# Issuer: CN=America Online Root Certification Authority 2 O=America Online Inc.
-# Subject: CN=America Online Root Certification Authority 2 O=America Online Inc.
-# Label: "America Online Root Certification Authority 2"
-# Serial: 1
-# MD5 Fingerprint: d6:ed:3c:ca:e2:66:0f:af:10:43:0d:77:9b:04:09:bf
-# SHA1 Fingerprint: 85:b5:ff:67:9b:0c:79:96:1f:c8:6e:44:22:00:46:13:db:17:92:84
-# SHA256 Fingerprint: 7d:3b:46:5a:60:14:e5:26:c0:af:fc:ee:21:27:d2:31:17:27:ad:81:1c:26:84:2d:00:6a:f3:73:06:cc:80:bd
------BEGIN CERTIFICATE-----
-MIIFpDCCA4ygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEc
-MBoGA1UEChMTQW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1lcmljYSBP
-bmxpbmUgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAyMB4XDTAyMDUyODA2
-MDAwMFoXDTM3MDkyOTE0MDgwMFowYzELMAkGA1UEBhMCVVMxHDAaBgNVBAoTE0Ft
-ZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJpY2EgT25saW5lIFJvb3Qg
-Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIP
-ADCCAgoCggIBAMxBRR3pPU0Q9oyxQcngXssNt79Hc9PwVU3dxgz6sWYFas14tNwC
-206B89enfHG8dWOgXeMHDEjsJcQDIPT/DjsS/5uN4cbVG7RtIuOx238hZK+GvFci
-KtZHgVdEglZTvYYUAQv8f3SkWq7xuhG1m1hagLQ3eAkzfDJHA1zEpYNI9FdWboE2
-JxhP7JsowtS013wMPgwr38oE18aO6lhOqKSlGBxsRZijQdEt0sdtjRnxrXm3gT+9
-BoInLRBYBbV4Bbkv2wxrkJB+FFk4u5QkE+XRnRTf04JNRvCAOVIyD+OEsnpD8l7e
-Xz8d3eOyG6ChKiMDbi4BFYdcpnV1x5dhvt6G3NRI270qv0pV2uh9UPu0gBe4lL8B
-PeraunzgWGcXuVjgiIZGZ2ydEEdYMtA1fHkqkKJaEBEjNa0vzORKW6fIJ/KD3l67
-Xnfn6KVuY8INXWHQjNJsWiEOyiijzirplcdIz5ZvHZIlyMbGwcEMBawmxNJ10uEq
-Z8A9W6Wa6897GqidFEXlD6CaZd4vKL3Ob5Rmg0gp2OpljK+T2WSfVVcmv2/LNzGZ
-o2C7HK2JNDJiuEMhBnIMoVxtRsX6Kc8w3onccVvdtjc+31D1uAclJuW8tf48ArO3
-+L5DwYcRlJ4jbBeKuIonDFRH8KmzwICMoCfrHRnjB453cMor9H124HhnAgMBAAGj
-YzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFE1FwWg4u3OpaaEg5+31IqEj
-FNeeMB8GA1UdIwQYMBaAFE1FwWg4u3OpaaEg5+31IqEjFNeeMA4GA1UdDwEB/wQE
-AwIBhjANBgkqhkiG9w0BAQUFAAOCAgEAZ2sGuV9FOypLM7PmG2tZTiLMubekJcmn
-xPBUlgtk87FYT15R/LKXeydlwuXK5w0MJXti4/qftIe3RUavg6WXSIylvfEWK5t2
-LHo1YGwRgJfMqZJS5ivmae2p+DYtLHe/YUjRYwu5W1LtGLBDQiKmsXeu3mnFzccc
-obGlHBD7GL4acN3Bkku+KVqdPzW+5X1R+FXgJXUjhx5c3LqdsKyzadsXg8n33gy8
-CNyRnqjQ1xU3c6U1uPx+xURABsPr+CKAXEfOAuMRn0T//ZoyzH1kUQ7rVyZ2OuMe
-IjzCpjbdGe+n/BLzJsBZMYVMnNjP36TMzCmT/5RtdlwTCJfy7aULTd3oyWgOZtMA
-DjMSW7yV5TKQqLPGbIOtd+6Lfn6xqavT4fG2wLHqiMDn05DpKJKUe2h7lyoKZy2F
-AjgQ5ANh1NolNscIWC2hp1GvMApJ9aZphwctREZ2jirlmjvXGKL8nDgQzMY70rUX
-Om/9riW99XJZZLF0KjhfGEzfz3EEWjbUvy+ZnOjZurGV5gJLIaFb1cFPj65pbVPb
-AZO1XB4Y3WRayhgoPmMEEf0cjQAPuDffZ4qdZqkCapH/E8ovXYO8h5Ns3CRRFgQl
-Zvqz2cK6Kb6aSDiCmfS/O0oxGfm/jiEzFMpPVF/7zvuPcX/9XhmgD0uRuMRUvAaw
-RY8mkaKO/qk=
------END CERTIFICATE-----
-
-# Issuer: CN=AAA Certificate Services O=Comodo CA Limited
-# Subject: CN=AAA Certificate Services O=Comodo CA Limited
-# Label: "Comodo AAA Services root"
-# Serial: 1
-# MD5 Fingerprint: 49:79:04:b0:eb:87:19:ac:47:b0:bc:11:51:9b:74:d0
-# SHA1 Fingerprint: d1:eb:23:a4:6d:17:d6:8f:d9:25:64:c2:f1:f1:60:17:64:d8:e3:49
-# SHA256 Fingerprint: d7:a7:a0:fb:5d:7e:27:31:d7:71:e9:48:4e:bc:de:f7:1d:5f:0c:3e:0a:29:48:78:2b:c8:3e:e0:ea:69:9e:f4
------BEGIN CERTIFICATE-----
-MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEb
-MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow
-GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmlj
-YXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVowezEL
-MAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE
-BwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNVBAMM
-GEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP
-ADCCAQoCggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQua
-BtDFcCLNSS1UY8y2bmhGC1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe
-3M/vg4aijJRPn2jymJBGhCfHdr/jzDUsi14HZGWCwEiwqJH5YZ92IFCokcdmtet4
-YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszWY19zjNoFmag4qMsXeDZR
-rOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjHYpy+g8cm
-ez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQU
-oBEKIz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF
-MAMBAf8wewYDVR0fBHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20v
-QUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29t
-b2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDANBgkqhkiG9w0BAQUF
-AAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm7l3sAg9g1o1Q
-GE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz
-Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2
-G9w84FoVxp7Z8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsi
-l2D4kF501KKaU73yqWjgom7C12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3
-smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg==
------END CERTIFICATE-----
-
-# Issuer: CN=Secure Certificate Services O=Comodo CA Limited
-# Subject: CN=Secure Certificate Services O=Comodo CA Limited
-# Label: "Comodo Secure Services root"
-# Serial: 1
-# MD5 Fingerprint: d3:d9:bd:ae:9f:ac:67:24:b3:c8:1b:52:e1:b9:a9:bd
-# SHA1 Fingerprint: 4a:65:d5:f4:1d:ef:39:b8:b8:90:4a:4a:d3:64:81:33:cf:c7:a1:d1
-# SHA256 Fingerprint: bd:81:ce:3b:4f:65:91:d1:1a:67:b5:fc:7a:47:fd:ef:25:52:1b:f9:aa:4e:18:b9:e3:df:2e:34:a7:80:3b:e8
------BEGIN CERTIFICATE-----
-MIIEPzCCAyegAwIBAgIBATANBgkqhkiG9w0BAQUFADB+MQswCQYDVQQGEwJHQjEb
-MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow
-GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEkMCIGA1UEAwwbU2VjdXJlIENlcnRp
-ZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVow
-fjELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
-A1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxJDAiBgNV
-BAMMG1NlY3VyZSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEB
-BQADggEPADCCAQoCggEBAMBxM4KK0HDrc4eCQNUd5MvJDkKQ+d40uaG6EfQlhfPM
-cm3ye5drswfxdySRXyWP9nQ95IDC+DwN879A6vfIUtFyb+/Iq0G4bi4XKpVpDM3S
-HpR7LZQdqnXXs5jLrLxkU0C8j6ysNstcrbvd4JQX7NFc0L/vpZXJkMWwrPsbQ996
-CF23uPJAGysnnlDOXmWCiIxe004MeuoIkbY2qitC++rCoznl2yY4rYsK7hljxxwk
-3wN42ubqwUcaCwtGCd0C/N7Lh1/XMGNooa7cMqG6vv5Eq2i2pRcV/b3Vp6ea5EQz
-6YiO/O1R65NxTq0B50SOqy3LqP4BSUjwwN3HaNiS/j0CAwEAAaOBxzCBxDAdBgNV
-HQ4EFgQUPNiTiMLAggnMAZkGkyDpnnAJY08wDgYDVR0PAQH/BAQDAgEGMA8GA1Ud
-EwEB/wQFMAMBAf8wgYEGA1UdHwR6MHgwO6A5oDeGNWh0dHA6Ly9jcmwuY29tb2Rv
-Y2EuY29tL1NlY3VyZUNlcnRpZmljYXRlU2VydmljZXMuY3JsMDmgN6A1hjNodHRw
-Oi8vY3JsLmNvbW9kby5uZXQvU2VjdXJlQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmww
-DQYJKoZIhvcNAQEFBQADggEBAIcBbSMdflsXfcFhMs+P5/OKlFlm4J4oqF7Tt/Q0
-5qo5spcWxYJvMqTpjOev/e/C6LlLqqP05tqNZSH7uoDrJiiFGv45jN5bBAS0VPmj
-Z55B+glSzAVIqMk/IQQezkhr/IXownuvf7fM+F86/TXGDe+X3EyrEeFryzHRbPtI
-gKvcnDe4IRRLDXE97IMzbtFuMhbsmMcWi1mmNKsFVy2T96oTy9IT4rcuO81rUBcJ
-aD61JlfutuC23bkpgHl9j6PwpCikFcSF9CfUa7/lXORlAnZUtOM3ZiTTGWHIUhDl
-izeauan5Hb/qmZJhlv8BzaFfDbxxvA6sCx1HRR3B7Hzs/Sk=
------END CERTIFICATE-----
-
-# Issuer: CN=Trusted Certificate Services O=Comodo CA Limited
-# Subject: CN=Trusted Certificate Services O=Comodo CA Limited
-# Label: "Comodo Trusted Services root"
-# Serial: 1
-# MD5 Fingerprint: 91:1b:3f:6e:cd:9e:ab:ee:07:fe:1f:71:d2:b3:61:27
-# SHA1 Fingerprint: e1:9f:e3:0e:8b:84:60:9e:80:9b:17:0d:72:a8:c5:ba:6e:14:09:bd
-# SHA256 Fingerprint: 3f:06:e5:56:81:d4:96:f5:be:16:9e:b5:38:9f:9f:2b:8f:f6:1e:17:08:df:68:81:72:48:49:cd:5d:27:cb:69
------BEGIN CERTIFICATE-----
-MIIEQzCCAyugAwIBAgIBATANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJHQjEb
-MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow
-GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDElMCMGA1UEAwwcVHJ1c3RlZCBDZXJ0
-aWZpY2F0ZSBTZXJ2aWNlczAeFw0wNDAxMDEwMDAwMDBaFw0yODEyMzEyMzU5NTla
-MH8xCzAJBgNVBAYTAkdCMRswGQYDVQQIDBJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO
-BgNVBAcMB1NhbGZvcmQxGjAYBgNVBAoMEUNvbW9kbyBDQSBMaW1pdGVkMSUwIwYD
-VQQDDBxUcnVzdGVkIENlcnRpZmljYXRlIFNlcnZpY2VzMIIBIjANBgkqhkiG9w0B
-AQEFAAOCAQ8AMIIBCgKCAQEA33FvNlhTWvI2VFeAxHQIIO0Yfyod5jWaHiWsnOWW
-fnJSoBVC21ndZHoa0Lh73TkVvFVIxO06AOoxEbrycXQaZ7jPM8yoMa+j49d/vzMt
-TGo87IvDktJTdyR0nAducPy9C1t2ul/y/9c3S0pgePfw+spwtOpZqqPOSC+pw7IL
-fhdyFgymBwwbOM/JYrc/oJOlh0Hyt3BAd9i+FHzjqMB6juljatEPmsbS9Is6FARW
-1O24zG71++IsWL1/T2sr92AkWCTOJu80kTrV44HQsvAEAtdbtz6SrGsSivnkBbA7
-kUlcsutT6vifR4buv5XAwAaf0lteERv0xwQ1KdJVXOTt6wIDAQABo4HJMIHGMB0G
-A1UdDgQWBBTFe1i97doladL3WRaoszLAeydb9DAOBgNVHQ8BAf8EBAMCAQYwDwYD
-VR0TAQH/BAUwAwEB/zCBgwYDVR0fBHwwejA8oDqgOIY2aHR0cDovL2NybC5jb21v
-ZG9jYS5jb20vVHJ1c3RlZENlcnRpZmljYXRlU2VydmljZXMuY3JsMDqgOKA2hjRo
-dHRwOi8vY3JsLmNvbW9kby5uZXQvVHJ1c3RlZENlcnRpZmljYXRlU2VydmljZXMu
-Y3JsMA0GCSqGSIb3DQEBBQUAA4IBAQDIk4E7ibSvuIQSTI3S8NtwuleGFTQQuS9/
-HrCoiWChisJ3DFBKmwCL2Iv0QeLQg4pKHBQGsKNoBXAxMKdTmw7pSqBYaWcOrp32
-pSxBvzwGa+RZzG0Q8ZZvH9/0BAKkn0U+yNj6NkZEUD+Cl5EfKNsYEYwq5GWDVxIS
-jBc/lDb+XbDABHcTuPQV1T84zJQ6VdCsmPW6AF/ghhmBeC8owH7TzEIK9a5QoNE+
-xqFx7D+gIIxmOom0jtTYsU0lR+4viMi14QVFwL4Ucd56/Y57fU0IlqUSc/Atyjcn
-dBInTMu2l+nZrghtWjlA3QVHdWpaIbOjGM9O9y5Xt5hwXsjEeLBi
------END CERTIFICATE-----
-
-# Issuer: CN=UTN - DATACorp SGC O=The USERTRUST Network OU=http://www.usertrust.com
-# Subject: CN=UTN - DATACorp SGC O=The USERTRUST Network OU=http://www.usertrust.com
-# Label: "UTN DATACorp SGC Root CA"
-# Serial: 91374294542884689855167577680241077609
-# MD5 Fingerprint: b3:a5:3e:77:21:6d:ac:4a:c0:c9:fb:d5:41:3d:ca:06
-# SHA1 Fingerprint: 58:11:9f:0e:12:82:87:ea:50:fd:d9:87:45:6f:4f:78:dc:fa:d6:d4
-# SHA256 Fingerprint: 85:fb:2f:91:dd:12:27:5a:01:45:b6:36:53:4f:84:02:4a:d6:8b:69:b8:ee:88:68:4f:f7:11:37:58:05:b3:48
------BEGIN CERTIFICATE-----
-MIIEXjCCA0agAwIBAgIQRL4Mi1AAIbQR0ypoBqmtaTANBgkqhkiG9w0BAQUFADCB
-kzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug
-Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho
-dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xGzAZBgNVBAMTElVUTiAtIERBVEFDb3Jw
-IFNHQzAeFw05OTA2MjQxODU3MjFaFw0xOTA2MjQxOTA2MzBaMIGTMQswCQYDVQQG
-EwJVUzELMAkGA1UECBMCVVQxFzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4wHAYD
-VQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cu
-dXNlcnRydXN0LmNvbTEbMBkGA1UEAxMSVVROIC0gREFUQUNvcnAgU0dDMIIBIjAN
-BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3+5YEKIrblXEjr8uRgnn4AgPLit6
-E5Qbvfa2gI5lBZMAHryv4g+OGQ0SR+ysraP6LnD43m77VkIVni5c7yPeIbkFdicZ
-D0/Ww5y0vpQZY/KmEQrrU0icvvIpOxboGqBMpsn0GFlowHDyUwDAXlCCpVZvNvlK
-4ESGoE1O1kduSUrLZ9emxAW5jh70/P/N5zbgnAVssjMiFdC04MwXwLLA9P4yPykq
-lXvY8qdOD1R8oQ2AswkDwf9c3V6aPryuvEeKaq5xyh+xKrhfQgUL7EYw0XILyulW
-bfXv33i+Ybqypa4ETLyorGkVl73v67SMvzX41MPRKA5cOp9wGDMgd8SirwIDAQAB
-o4GrMIGoMAsGA1UdDwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRT
-MtGzz3/64PGgXYVOktKeRR20TzA9BgNVHR8ENjA0MDKgMKAuhixodHRwOi8vY3Js
-LnVzZXJ0cnVzdC5jb20vVVROLURBVEFDb3JwU0dDLmNybDAqBgNVHSUEIzAhBggr
-BgEFBQcDAQYKKwYBBAGCNwoDAwYJYIZIAYb4QgQBMA0GCSqGSIb3DQEBBQUAA4IB
-AQAnNZcAiosovcYzMB4p/OL31ZjUQLtgyr+rFywJNn9Q+kHcrpY6CiM+iVnJowft
-Gzet/Hy+UUla3joKVAgWRcKZsYfNjGjgaQPpxE6YsjuMFrMOoAyYUJuTqXAJyCyj
-j98C5OBxOvG0I3KgqgHf35g+FFCgMSa9KOlaMCZ1+XtgHI3zzVAmbQQnmt/VDUVH
-KWss5nbZqSl9Mt3JNjy9rjXxEZ4du5A/EkdOjtd+D2JzHVImOBwYSf0wdJrE5SIv
-2MCN7ZF6TACPcn9d2t0bi0Vr591pl6jFVkwPDPafepE39peC4N1xaf92P2BNPM/3
-mfnGV/TJVTl4uix5yaaIK/QI
------END CERTIFICATE-----
-
-# Issuer: CN=UTN-USERFirst-Hardware O=The USERTRUST Network OU=http://www.usertrust.com
-# Subject: CN=UTN-USERFirst-Hardware O=The USERTRUST Network OU=http://www.usertrust.com
-# Label: "UTN USERFirst Hardware Root CA"
-# Serial: 91374294542884704022267039221184531197
-# MD5 Fingerprint: 4c:56:41:e5:0d:bb:2b:e8:ca:a3:ed:18:08:ad:43:39
-# SHA1 Fingerprint: 04:83:ed:33:99:ac:36:08:05:87:22:ed:bc:5e:46:00:e3:be:f9:d7
-# SHA256 Fingerprint: 6e:a5:47:41:d0:04:66:7e:ed:1b:48:16:63:4a:a3:a7:9e:6e:4b:96:95:0f:82:79:da:fc:8d:9b:d8:81:21:37
------BEGIN CERTIFICATE-----
-MIIEdDCCA1ygAwIBAgIQRL4Mi1AAJLQR0zYq/mUK/TANBgkqhkiG9w0BAQUFADCB
-lzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug
-Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho
-dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3Qt
-SGFyZHdhcmUwHhcNOTkwNzA5MTgxMDQyWhcNMTkwNzA5MTgxOTIyWjCBlzELMAkG
-A1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEe
-MBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8v
-d3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdh
-cmUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCx98M4P7Sof885glFn
-0G2f0v9Y8+efK+wNiVSZuTiZFvfgIXlIwrthdBKWHTxqctU8EGc6Oe0rE81m65UJ
-M6Rsl7HoxuzBdXmcRl6Nq9Bq/bkqVRcQVLMZ8Jr28bFdtqdt++BxF2uiiPsA3/4a
-MXcMmgF6sTLjKwEHOG7DpV4jvEWbe1DByTCP2+UretNb+zNAHqDVmBe8i4fDidNd
-oI6yqqr2jmmIBsX6iSHzCJ1pLgkzmykNRg+MzEk0sGlRvfkGzWitZky8PqxhvQqI
-DsjfPe58BEydCl5rkdbux+0ojatNh4lz0G6k0B4WixThdkQDf2Os5M1JnMWS9Ksy
-oUhbAgMBAAGjgbkwgbYwCwYDVR0PBAQDAgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYD
-VR0OBBYEFKFyXyYbKJhDlV0HN9WFlp1L0sNFMEQGA1UdHwQ9MDswOaA3oDWGM2h0
-dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VVE4tVVNFUkZpcnN0LUhhcmR3YXJlLmNy
-bDAxBgNVHSUEKjAoBggrBgEFBQcDAQYIKwYBBQUHAwUGCCsGAQUFBwMGBggrBgEF
-BQcDBzANBgkqhkiG9w0BAQUFAAOCAQEARxkP3nTGmZev/K0oXnWO6y1n7k57K9cM
-//bey1WiCuFMVGWTYGufEpytXoMs61quwOQt9ABjHbjAbPLPSbtNk28Gpgoiskli
-CE7/yMgUsogWXecB5BKV5UU0s4tpvc+0hY91UZ59Ojg6FEgSxvunOxqNDYJAB+gE
-CJChicsZUN/KHAG8HQQZexB2lzvukJDKxA4fFm517zP4029bHpbj4HR3dHuKom4t
-3XbWOTCC8KucUvIqx69JXn7HaOWCgchqJ/kniCrVWFCVH/A7HFe7fRQ5YiuayZSS
-KqMiDP+JJn1fIytH1xUdqWqeUQ0qUZ6B+dQ7XnASfxAynB67nfhmqA==
------END CERTIFICATE-----
-
-# Issuer: CN=XRamp Global Certification Authority O=XRamp Security Services Inc OU=www.xrampsecurity.com
-# Subject: CN=XRamp Global Certification Authority O=XRamp Security Services Inc OU=www.xrampsecurity.com
-# Label: "XRamp Global CA Root"
-# Serial: 107108908803651509692980124233745014957
-# MD5 Fingerprint: a1:0b:44:b3:ca:10:d8:00:6e:9d:0f:d8:0f:92:0a:d1
-# SHA1 Fingerprint: b8:01:86:d1:eb:9c:86:a5:41:04:cf:30:54:f3:4c:52:b7:e5:58:c6
-# SHA256 Fingerprint: ce:cd:dc:90:50:99:d8:da:df:c5:b1:d2:09:b7:37:cb:e2:c1:8c:fb:2c:10:c0:ff:0b:cf:0d:32:86:fc:1a:a2
------BEGIN CERTIFICATE-----
-MIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUFADCB
-gjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEk
-MCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRY
-UmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQxMTAxMTcx
-NDA0WhcNMzUwMTAxMDUzNzE5WjCBgjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3
-dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2Vy
-dmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBB
-dXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYJB69FbS6
-38eMpSe2OAtp87ZOqCwuIR1cRN8hXX4jdP5efrRKt6atH67gBhbim1vZZ3RrXYCP
-KZ2GG9mcDZhtdhAoWORlsH9KmHmf4MMxfoArtYzAQDsRhtDLooY2YKTVMIJt2W7Q
-DxIEM5dfT2Fa8OT5kavnHTu86M/0ay00fOJIYRyO82FEzG+gSqmUsE3a56k0enI4
-qEHMPJQRfevIpoy3hsvKMzvZPTeL+3o+hiznc9cKV6xkmxnr9A8ECIqsAxcZZPRa
-JSKNNCyy9mgdEm3Tih4U2sSPpuIjhdV6Db1q4Ons7Be7QhtnqiXtRYMh/MHJfNVi
-PvryxS3T/dRlAgMBAAGjgZ8wgZwwEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0P
-BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMZPoj0GY4QJnM5i5ASs
-jVy16bYbMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwueHJhbXBzZWN1cml0
-eS5jb20vWEdDQS5jcmwwEAYJKwYBBAGCNxUBBAMCAQEwDQYJKoZIhvcNAQEFBQAD
-ggEBAJEVOQMBG2f7Shz5CmBbodpNl2L5JFMn14JkTpAuw0kbK5rc/Kh4ZzXxHfAR
-vbdI4xD2Dd8/0sm2qlWkSLoC295ZLhVbO50WfUfXN+pfTXYSNrsf16GBBEYgoyxt
-qZ4Bfj8pzgCT3/3JknOJiWSe5yvkHJEs0rnOfc5vMZnT5r7SHpDwCRR5XCOrTdLa
-IR9NmXmd4c8nnxCbHIgNsIpkQTG4DmyQJKSbXHGPurt+HBvbaoAPIbzp26a3QPSy
-i6mx5O+aGtA9aZnuqCij4Tyz8LIRnM98QObd50N9otg6tamN8jSZxNQQ4Qb9CYQQ
-O+7ETPTsJ3xCwnR8gooJybQDJbw=
------END CERTIFICATE-----
-
-# Issuer: O=The Go Daddy Group, Inc. OU=Go Daddy Class 2 Certification Authority
-# Subject: O=The Go Daddy Group, Inc. OU=Go Daddy Class 2 Certification Authority
-# Label: "Go Daddy Class 2 CA"
-# Serial: 0
-# MD5 Fingerprint: 91:de:06:25:ab:da:fd:32:17:0c:bb:25:17:2a:84:67
-# SHA1 Fingerprint: 27:96:ba:e6:3f:18:01:e2:77:26:1b:a0:d7:77:70:02:8f:20:ee:e4
-# SHA256 Fingerprint: c3:84:6b:f2:4b:9e:93:ca:64:27:4c:0e:c6:7c:1e:cc:5e:02:4f:fc:ac:d2:d7:40:19:35:0e:81:fe:54:6a:e4
------BEGIN CERTIFICATE-----
-MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEh
-MB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBE
-YWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3
-MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRo
-ZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3Mg
-MiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggEN
-ADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCA
-PVYYYwhv2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6w
-wdhFJ2+qN1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXi
-EqITLdiOr18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMY
-avx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+
-YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0OBBYEFNLE
-sNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h
-/t2oatTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5
-IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmlj
-YXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD
-ggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wimPQoZ+YeAEW5p5JYXMP80kWNy
-OO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKtI3lpjbi2Tc7P
-TMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ
-HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mER
-dEr/VxqHD3VILs9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5Cuf
-ReYNnyicsbkqWletNw+vHX/bvZ8=
------END CERTIFICATE-----
-
-# Issuer: O=Starfield Technologies, Inc. OU=Starfield Class 2 Certification Authority
-# Subject: O=Starfield Technologies, Inc. OU=Starfield Class 2 Certification Authority
-# Label: "Starfield Class 2 CA"
-# Serial: 0
-# MD5 Fingerprint: 32:4a:4b:bb:c8:63:69:9b:be:74:9a:c6:dd:1d:46:24
-# SHA1 Fingerprint: ad:7e:1c:28:b0:64:ef:8f:60:03:40:20:14:c3:d0:e3:37:0e:b5:8a
-# SHA256 Fingerprint: 14:65:fa:20:53:97:b8:76:fa:a6:f0:a9:95:8e:55:90:e4:0f:cc:7f:aa:4f:b7:c2:c8:67:75:21:fb:5f:b6:58
------BEGIN CERTIFICATE-----
-MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzEl
-MCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMp
-U3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQw
-NjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBoMQswCQYDVQQGEwJVUzElMCMGA1UE
-ChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZp
-ZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqGSIb3
-DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf
-8MOh2tTYbitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN
-+lq2cwQlZut3f+dZxkqZJRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0
-X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVmepsZGD3/cVE8MC5fvj13c7JdBmzDI1aa
-K4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSNF4Azbl5KXZnJHoe0nRrA
-1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HFMIHCMB0G
-A1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fR
-zt0fhvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0
-YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBD
-bGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8w
-DQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGsafPzWdqbAYcaT1epoXkJKtv3
-L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLMPUxA2IGvd56D
-eruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl
-xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynp
-VSJYACPq4xJDKVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEY
-WQPJIrSPnNVeKtelttQKbfi3QBFGmh95DmK/D5fs4C8fF5Q=
------END CERTIFICATE-----
-
-# Issuer: CN=StartCom Certification Authority O=StartCom Ltd. OU=Secure Digital Certificate Signing
-# Subject: CN=StartCom Certification Authority O=StartCom Ltd. OU=Secure Digital Certificate Signing
-# Label: "StartCom Certification Authority"
-# Serial: 1
-# MD5 Fingerprint: 22:4d:8f:8a:fc:f7:35:c2:bb:57:34:90:7b:8b:22:16
-# SHA1 Fingerprint: 3e:2b:f7:f2:03:1b:96:f3:8c:e6:c4:d8:a8:5d:3e:2d:58:47:6a:0f
-# SHA256 Fingerprint: c7:66:a9:be:f2:d4:07:1c:86:3a:31:aa:49:20:e8:13:b2:d1:98:60:8c:b7:b7:cf:e2:11:43:b8:36:df:09:ea
------BEGIN CERTIFICATE-----
-MIIHyTCCBbGgAwIBAgIBATANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJJTDEW
-MBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwg
-Q2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNh
-dGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0NjM2WhcNMzYwOTE3MTk0NjM2WjB9
-MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMi
-U2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3Rh
-cnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUA
-A4ICDwAwggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZk
-pMyONvg45iPwbm2xPN1yo4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rf
-OQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/C
-Ji/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/deMotHweXMAEtcnn6RtYT
-Kqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt2PZE4XNi
-HzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMM
-Av+Z6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w
-+2OqqGwaVLRcJXrJosmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+
-Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3
-Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVcUjyJthkqcwEKDwOzEmDyei+B
-26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT37uMdBNSSwID
-AQABo4ICUjCCAk4wDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAa4wHQYDVR0OBBYE
-FE4L7xqkQFulF2mHMMo0aEPQQa7yMGQGA1UdHwRdMFswLKAqoCiGJmh0dHA6Ly9j
-ZXJ0LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMCugKaAnhiVodHRwOi8vY3Js
-LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMIIBXQYDVR0gBIIBVDCCAVAwggFM
-BgsrBgEEAYG1NwEBATCCATswLwYIKwYBBQUHAgEWI2h0dHA6Ly9jZXJ0LnN0YXJ0
-Y29tLm9yZy9wb2xpY3kucGRmMDUGCCsGAQUFBwIBFilodHRwOi8vY2VydC5zdGFy
-dGNvbS5vcmcvaW50ZXJtZWRpYXRlLnBkZjCB0AYIKwYBBQUHAgIwgcMwJxYgU3Rh
-cnQgQ29tbWVyY2lhbCAoU3RhcnRDb20pIEx0ZC4wAwIBARqBl0xpbWl0ZWQgTGlh
-YmlsaXR5LCByZWFkIHRoZSBzZWN0aW9uICpMZWdhbCBMaW1pdGF0aW9ucyogb2Yg
-dGhlIFN0YXJ0Q29tIENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFBvbGljeSBhdmFp
-bGFibGUgYXQgaHR0cDovL2NlcnQuc3RhcnRjb20ub3JnL3BvbGljeS5wZGYwEQYJ
-YIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilTdGFydENvbSBGcmVlIFNT
-TCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQUFAAOCAgEAFmyZ
-9GYMNPXQhV59CuzaEE44HF7fpiUFS5Eyweg78T3dRAlbB0mKKctmArexmvclmAk8
-jhvh3TaHK0u7aNM5Zj2gJsfyOZEdUauCe37Vzlrk4gNXcGmXCPleWKYK34wGmkUW
-FjgKXlf2Ysd6AgXmvB618p70qSmD+LIU424oh0TDkBreOKk8rENNZEXO3SipXPJz
-ewT4F+irsfMuXGRuczE6Eri8sxHkfY+BUZo7jYn0TZNmezwD7dOaHZrzZVD1oNB1
-ny+v8OqCQ5j4aZyJecRDjkZy42Q2Eq/3JR44iZB3fsNrarnDy0RLrHiQi+fHLB5L
-EUTINFInzQpdn4XBidUaePKVEFMy3YCEZnXZtWgo+2EuvoSoOMCZEoalHmdkrQYu
-L6lwhceWD3yJZfWOQ1QOq92lgDmUYMA0yZZwLKMS9R9Ie70cfmu3nZD0Ijuu+Pwq
-yvqCUqDvr0tVk+vBtfAii6w0TiYiBKGHLHVKt+V9E9e4DGTANtLJL4YSjCMJwRuC
-O3NJo2pXh5Tl1njFmUNj403gdy3hZZlyaQQaRwnmDwFWJPsfvw55qVguucQJAX6V
-um0ABj6y6koQOdjQK/W/7HW/lwLFCRsI3FU34oH7N4RDYiDK51ZLZer+bMEkkySh
-NOsF/5oirpt9P/FlUQqmMGqz9IgcgA38corog14=
------END CERTIFICATE-----
-
-# Issuer: CN=DigiCert Assured ID Root CA O=DigiCert Inc OU=www.digicert.com
-# Subject: CN=DigiCert Assured ID Root CA O=DigiCert Inc OU=www.digicert.com
-# Label: "DigiCert Assured ID Root CA"
-# Serial: 17154717934120587862167794914071425081
-# MD5 Fingerprint: 87:ce:0b:7b:2a:0e:49:00:e1:58:71:9b:37:a8:93:72
-# SHA1 Fingerprint: 05:63:b8:63:0d:62:d7:5a:bb:c8:ab:1e:4b:df:b5:a8:99:b2:4d:43
-# SHA256 Fingerprint: 3e:90:99:b5:01:5e:8f:48:6c:00:bc:ea:9d:11:1e:e7:21:fa:ba:35:5a:89:bc:f1:df:69:56:1e:3d:c6:32:5c
------BEGIN CERTIFICATE-----
-MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBl
-MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
-d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv
-b3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzExMTEwMDAwMDAwWjBlMQswCQYDVQQG
-EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl
-cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwggEi
-MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7c
-JpSIqvTO9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYP
-mDI2dsze3Tyoou9q+yHyUmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+
-wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4
-VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpyoeb6pNnVFzF1roV9Iq4/
-AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whfGHdPAgMB
-AAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW
-BBRF66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYun
-pyGd823IDzANBgkqhkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRC
-dWKuh+vy1dneVrOfzM4UKLkNl2BcEkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTf
-fwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38FnSbNd67IJKusm7Xi+fT8r87cm
-NW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i8b5QZ7dsvfPx
-H2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe
-+o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g==
------END CERTIFICATE-----
-
-# Issuer: CN=DigiCert Global Root CA O=DigiCert Inc OU=www.digicert.com
-# Subject: CN=DigiCert Global Root CA O=DigiCert Inc OU=www.digicert.com
-# Label: "DigiCert Global Root CA"
-# Serial: 10944719598952040374951832963794454346
-# MD5 Fingerprint: 79:e4:a9:84:0d:7d:3a:96:d7:c0:4f:e2:43:4c:89:2e
-# SHA1 Fingerprint: a8:98:5d:3a:65:e5:e5:c4:b2:d7:d6:6d:40:c6:dd:2f:b1:9c:54:36
-# SHA256 Fingerprint: 43:48:a0:e9:44:4c:78:cb:26:5e:05:8d:5e:89:44:b4:d8:4f:96:62:bd:26:db:25:7f:89:34:a4:43:c7:01:61
------BEGIN CERTIFICATE-----
-MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh
-MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
-d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
-QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT
-MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
-b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG
-9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB
-CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97
-nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt
-43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P
-T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4
-gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO
-BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR
-TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw
-DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr
-hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg
-06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF
-PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls
-YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
-CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
------END CERTIFICATE-----
-
-# Issuer: CN=DigiCert High Assurance EV Root CA O=DigiCert Inc OU=www.digicert.com
-# Subject: CN=DigiCert High Assurance EV Root CA O=DigiCert Inc OU=www.digicert.com
-# Label: "DigiCert High Assurance EV Root CA"
-# Serial: 3553400076410547919724730734378100087
-# MD5 Fingerprint: d4:74:de:57:5c:39:b2:d3:9c:85:83:c5:c0:65:49:8a
-# SHA1 Fingerprint: 5f:b7:ee:06:33:e2:59:db:ad:0c:4c:9a:e6:d3:8f:1a:61:c7:dc:25
-# SHA256 Fingerprint: 74:31:e5:f4:c3:c1:ce:46:90:77:4f:0b:61:e0:54:40:88:3b:a9:a0:1e:d0:0b:a6:ab:d7:80:6e:d3:b1:18:cf
------BEGIN CERTIFICATE-----
-MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs
-MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
-d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j
-ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL
-MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3
-LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug
-RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm
-+9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW
-PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM
-xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB
-Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3
-hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg
-EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF
-MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA
-FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec
-nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z
-eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF
-hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2
-Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe
-vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep
-+OkuE6N36B9K
------END CERTIFICATE-----
-
-# Issuer: CN=GeoTrust Primary Certification Authority O=GeoTrust Inc.
-# Subject: CN=GeoTrust Primary Certification Authority O=GeoTrust Inc.
-# Label: "GeoTrust Primary Certification Authority"
-# Serial: 32798226551256963324313806436981982369
-# MD5 Fingerprint: 02:26:c3:01:5e:08:30:37:43:a9:d0:7d:cf:37:e6:bf
-# SHA1 Fingerprint: 32:3c:11:8e:1b:f7:b8:b6:52:54:e2:e2:10:0d:d6:02:90:37:f0:96
-# SHA256 Fingerprint: 37:d5:10:06:c5:12:ea:ab:62:64:21:f1:ec:8c:92:01:3f:c5:f8:2a:e9:8e:e5:33:eb:46:19:b8:de:b4:d0:6c
------BEGIN CERTIFICATE-----
-MIIDfDCCAmSgAwIBAgIQGKy1av1pthU6Y2yv2vrEoTANBgkqhkiG9w0BAQUFADBY
-MQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjExMC8GA1UEAxMo
-R2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEx
-MjcwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMFgxCzAJBgNVBAYTAlVTMRYwFAYDVQQK
-Ew1HZW9UcnVzdCBJbmMuMTEwLwYDVQQDEyhHZW9UcnVzdCBQcmltYXJ5IENlcnRp
-ZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
-AQEAvrgVe//UfH1nrYNke8hCUy3f9oQIIGHWAVlqnEQRr+92/ZV+zmEwu3qDXwK9
-AWbK7hWNb6EwnL2hhZ6UOvNWiAAxz9juapYC2e0DjPt1befquFUWBRaa9OBesYjA
-ZIVcFU2Ix7e64HXprQU9nceJSOC7KMgD4TCTZF5SwFlwIjVXiIrxlQqD17wxcwE0
-7e9GceBrAqg1cmuXm2bgyxx5X9gaBGgeRwLmnWDiNpcB3841kt++Z8dtd1k7j53W
-kBWUvEI0EME5+bEnPn7WinXFsq+W06Lem+SYvn3h6YGttm/81w7a4DSwDRp35+MI
-mO9Y+pyEtzavwt+s0vQQBnBxNQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4G
-A1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQULNVQQZcVi/CPNmFbSvtr2ZnJM5IwDQYJ
-KoZIhvcNAQEFBQADggEBAFpwfyzdtzRP9YZRqSa+S7iq8XEN3GHHoOo0Hnp3DwQ1
-6CePbJC/kRYkRj5KTs4rFtULUh38H2eiAkUxT87z+gOneZ1TatnaYzr4gNfTmeGl
-4b7UVXGYNTq+k+qurUKykG/g/CFNNWMziUnWm07Kx+dOCQD32sfvmWKZd7aVIl6K
-oKv0uHiYyjgZmclynnjNS6yvGaBzEi38wkG6gZHaFloxt/m0cYASSJlyc1pZU8Fj
-UjPtp8nSOQJw+uCxQmYpqptR7TBUIhRf2asdweSU8Pj1K/fqynhG1riR/aYNKxoU
-AT6A8EKglQdebc3MS6RFjasS6LPeWuWgfOgPIh1a6Vk=
------END CERTIFICATE-----
-
-# Issuer: CN=thawte Primary Root CA O=thawte, Inc. OU=Certification Services Division/(c) 2006 thawte, Inc. - For authorized use only
-# Subject: CN=thawte Primary Root CA O=thawte, Inc. OU=Certification Services Division/(c) 2006 thawte, Inc. - For authorized use only
-# Label: "thawte Primary Root CA"
-# Serial: 69529181992039203566298953787712940909
-# MD5 Fingerprint: 8c:ca:dc:0b:22:ce:f5:be:72:ac:41:1a:11:a8:d8:12
-# SHA1 Fingerprint: 91:c6:d6:ee:3e:8a:c8:63:84:e5:48:c2:99:29:5c:75:6c:81:7b:81
-# SHA256 Fingerprint: 8d:72:2f:81:a9:c1:13:c0:79:1d:f1:36:a2:96:6d:b2:6c:95:0a:97:1d:b4:6b:41:99:f4:ea:54:b7:8b:fb:9f
------BEGIN CERTIFICATE-----
-MIIEIDCCAwigAwIBAgIQNE7VVyDV7exJ9C/ON9srbTANBgkqhkiG9w0BAQUFADCB
-qTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf
-Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw
-MDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNV
-BAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMDYxMTE3MDAwMDAwWhcNMzYw
-NzE2MjM1OTU5WjCBqTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5j
-LjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYG
-A1UECxMvKGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl
-IG9ubHkxHzAdBgNVBAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwggEiMA0GCSqG
-SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCsoPD7gFnUnMekz52hWXMJEEUMDSxuaPFs
-W0hoSVk3/AszGcJ3f8wQLZU0HObrTQmnHNK4yZc2AreJ1CRfBsDMRJSUjQJib+ta
-3RGNKJpchJAQeg29dGYvajig4tVUROsdB58Hum/u6f1OCyn1PoSgAfGcq/gcfomk
-6KHYcWUNo1F77rzSImANuVud37r8UVsLr5iy6S7pBOhih94ryNdOwUxkHt3Ph1i6
-Sk/KaAcdHJ1KxtUvkcx8cXIcxcBn6zL9yZJclNqFwJu/U30rCfSMnZEfl2pSy94J
-NqR32HuHUETVPm4pafs5SSYeCaWAe0At6+gnhcn+Yf1+5nyXHdWdAgMBAAGjQjBA
-MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBR7W0XP
-r87Lev0xkhpqtvNG61dIUDANBgkqhkiG9w0BAQUFAAOCAQEAeRHAS7ORtvzw6WfU
-DW5FvlXok9LOAz/t2iWwHVfLHjp2oEzsUHboZHIMpKnxuIvW1oeEuzLlQRHAd9mz
-YJ3rG9XRbkREqaYB7FViHXe4XI5ISXycO1cRrK1zN44veFyQaEfZYGDm/Ac9IiAX
-xPcW6cTYcvnIc3zfFi8VqT79aie2oetaupgf1eNNZAqdE8hhuvU5HIe6uL17In/2
-/qxAeeWsEG89jxt5dovEN7MhGITlNgDrYyCZuen+MwS7QcjBAvlEYyCegc5C09Y/
-LHbTY5xZ3Y+m4Q6gLkH3LpVHz7z9M/P2C2F+fpErgUfCJzDupxBdN49cOSvkBPB7
-jVaMaA==
------END CERTIFICATE-----
-
-# Issuer: CN=VeriSign Class 3 Public Primary Certification Authority - G5 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 2006 VeriSign, Inc. - For authorized use only
-# Subject: CN=VeriSign Class 3 Public Primary Certification Authority - G5 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 2006 VeriSign, Inc. - For authorized use only
-# Label: "VeriSign Class 3 Public Primary Certification Authority - G5"
-# Serial: 33037644167568058970164719475676101450
-# MD5 Fingerprint: cb:17:e4:31:67:3e:e2:09:fe:45:57:93:f3:0a:fa:1c
-# SHA1 Fingerprint: 4e:b6:d5:78:49:9b:1c:cf:5f:58:1e:ad:56:be:3d:9b:67:44:a5:e5
-# SHA256 Fingerprint: 9a:cf:ab:7e:43:c8:d8:80:d0:6b:26:2a:94:de:ee:e4:b4:65:99:89:c3:d0:ca:f1:9b:af:64:05:e4:1a:b7:df
------BEGIN CERTIFICATE-----
-MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCB
-yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL
-ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp
-U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW
-ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0
-aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCByjEL
-MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW
-ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2ln
-biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp
-U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y
-aXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvJAgIKXo1
-nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKzj/i5Vbex
-t0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIz
-SdhDY2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQG
-BO+QueQA5N06tRn/Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+
-rCpSx4/VBEnkjWNHiDxpg8v+R70rfk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/
-NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8E
-BAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEwHzAH
-BgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy
-aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKv
-MzEzMA0GCSqGSIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzE
-p6B4Eq1iDkVwZMXnl2YtmAl+X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y
-5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKEKQsTb47bDN0lAtukixlE0kF6BWlK
-WE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiCKm0oHw0LxOXnGiYZ
-4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vEZV8N
-hnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq
------END CERTIFICATE-----
-
-# Issuer: CN=COMODO Certification Authority O=COMODO CA Limited
-# Subject: CN=COMODO Certification Authority O=COMODO CA Limited
-# Label: "COMODO Certification Authority"
-# Serial: 104350513648249232941998508985834464573
-# MD5 Fingerprint: 5c:48:dc:f7:42:72:ec:56:94:6d:1c:cc:71:35:80:75
-# SHA1 Fingerprint: 66:31:bf:9e:f7:4f:9e:b6:c9:d5:a6:0c:ba:6a:be:d1:f7:bd:ef:7b
-# SHA256 Fingerprint: 0c:2c:d6:3d:f7:80:6f:a3:99:ed:e8:09:11:6b:57:5b:f8:79:89:f0:65:18:f9:80:8c:86:05:03:17:8b:af:66
------BEGIN CERTIFICATE-----
-MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCB
-gTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
-A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNV
-BAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEyMDEwMDAw
-MDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3Jl
-YXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01P
-RE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0
-aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3
-UcEbVASY06m/weaKXTuH+7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI
-2GqGd0S7WWaXUF601CxwRM/aN5VCaTwwxHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8
-Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV4EajcNxo2f8ESIl33rXp
-+2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA1KGzqSX+
-DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5O
-nKVIrLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW
-/zAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6g
-PKA6hjhodHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9u
-QXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOCAQEAPpiem/Yb6dc5t3iuHXIY
-SdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CPOGEIqB6BCsAv
-IC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/
-RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4
-zJVSk/BwJVmcIGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5dd
-BA6+C4OmF4O5MBKgxTMVBbkN+8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IB
-ZQ==
------END CERTIFICATE-----
-
-# Issuer: CN=Network Solutions Certificate Authority O=Network Solutions L.L.C.
-# Subject: CN=Network Solutions Certificate Authority O=Network Solutions L.L.C.
-# Label: "Network Solutions Certificate Authority"
-# Serial: 116697915152937497490437556386812487904
-# MD5 Fingerprint: d3:f3:a6:16:c0:fa:6b:1d:59:b1:2d:96:4d:0e:11:2e
-# SHA1 Fingerprint: 74:f8:a3:c3:ef:e7:b3:90:06:4b:83:90:3c:21:64:60:20:e5:df:ce
-# SHA256 Fingerprint: 15:f0:ba:00:a3:ac:7a:f3:ac:88:4c:07:2b:10:11:a0:77:bd:77:c0:97:f4:01:64:b2:f8:59:8a:bd:83:86:0c
------BEGIN CERTIFICATE-----
-MIID5jCCAs6gAwIBAgIQV8szb8JcFuZHFhfjkDFo4DANBgkqhkiG9w0BAQUFADBi
-MQswCQYDVQQGEwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMu
-MTAwLgYDVQQDEydOZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3Jp
-dHkwHhcNMDYxMjAxMDAwMDAwWhcNMjkxMjMxMjM1OTU5WjBiMQswCQYDVQQGEwJV
-UzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMuMTAwLgYDVQQDEydO
-ZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0GCSqG
-SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkvH6SMG3G2I4rC7xGzuAnlt7e+foS0zwz
-c7MEL7xxjOWftiJgPl9dzgn/ggwbmlFQGiaJ3dVhXRncEg8tCqJDXRfQNJIg6nPP
-OCwGJgl6cvf6UDL4wpPTaaIjzkGxzOTVHzbRijr4jGPiFFlp7Q3Tf2vouAPlT2rl
-mGNpSAW+Lv8ztumXWWn4Zxmuk2GWRBXTcrA/vGp97Eh/jcOrqnErU2lBUzS1sLnF
-BgrEsEX1QV1uiUV7PTsmjHTC5dLRfbIR1PtYMiKagMnc/Qzpf14Dl847ABSHJ3A4
-qY5usyd2mFHgBeMhqxrVhSI8KbWaFsWAqPS7azCPL0YCorEMIuDTAgMBAAGjgZcw
-gZQwHQYDVR0OBBYEFCEwyfsA106Y2oeqKtCnLrFAMadMMA4GA1UdDwEB/wQEAwIB
-BjAPBgNVHRMBAf8EBTADAQH/MFIGA1UdHwRLMEkwR6BFoEOGQWh0dHA6Ly9jcmwu
-bmV0c29sc3NsLmNvbS9OZXR3b3JrU29sdXRpb25zQ2VydGlmaWNhdGVBdXRob3Jp
-dHkuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQC7rkvnt1frf6ott3NHhWrB5KUd5Oc8
-6fRZZXe1eltajSU24HqXLjjAV2CDmAaDn7l2em5Q4LqILPxFzBiwmZVRDuwduIj/
-h1AcgsLj4DKAv6ALR8jDMe+ZZzKATxcheQxpXN5eNK4CtSbqUN9/GGUsyfJj4akH
-/nxxH2szJGoeBfcFaMBqEssuXmHLrijTfsK0ZpEmXzwuJF/LWA/rKOyvEZbz3Htv
-wKeI8lN3s2Berq4o2jUsbzRF0ybh3uxbTydrFny9RAQYgrOJeRcQcT16ohZO9QHN
-pGxlaKFJdlxDydi8NmdspZS11My5vWo1ViHe2MPr+8ukYEywVaCge1ey
------END CERTIFICATE-----
-
-# Issuer: CN=COMODO ECC Certification Authority O=COMODO CA Limited
-# Subject: CN=COMODO ECC Certification Authority O=COMODO CA Limited
-# Label: "COMODO ECC Certification Authority"
-# Serial: 41578283867086692638256921589707938090
-# MD5 Fingerprint: 7c:62:ff:74:9d:31:53:5e:68:4a:d5:78:aa:1e:bf:23
-# SHA1 Fingerprint: 9f:74:4e:9f:2b:4d:ba:ec:0f:31:2c:50:b6:56:3b:8e:2d:93:c3:11
-# SHA256 Fingerprint: 17:93:92:7a:06:14:54:97:89:ad:ce:2f:8f:34:f7:f0:b6:6d:0f:3a:e3:a3:b8:4d:21:ec:15:db:ba:4f:ad:c7
------BEGIN CERTIFICATE-----
-MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTEL
-MAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE
-BxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMT
-IkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwMzA2MDAw
-MDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdy
-ZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09N
-T0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlv
-biBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSR
-FtSrYpn1PlILBs5BAH+X4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0J
-cfRK9ChQtP6IHG4/bC8vCVlbpVsLM5niwz2J+Wos77LTBumjQjBAMB0GA1UdDgQW
-BBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/
-BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VGFAkK+qDm
-fQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdv
-GDeAU/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY=
------END CERTIFICATE-----
-
-# Issuer: CN=TC TrustCenter Class 2 CA II O=TC TrustCenter GmbH OU=TC TrustCenter Class 2 CA
-# Subject: CN=TC TrustCenter Class 2 CA II O=TC TrustCenter GmbH OU=TC TrustCenter Class 2 CA
-# Label: "TC TrustCenter Class 2 CA II"
-# Serial: 941389028203453866782103406992443
-# MD5 Fingerprint: ce:78:33:5c:59:78:01:6e:18:ea:b9:36:a0:b9:2e:23
-# SHA1 Fingerprint: ae:50:83:ed:7c:f4:5c:bc:8f:61:c6:21:fe:68:5d:79:42:21:15:6e
-# SHA256 Fingerprint: e6:b8:f8:76:64:85:f8:07:ae:7f:8d:ac:16:70:46:1f:07:c0:a1:3e:ef:3a:1f:f7:17:53:8d:7a:ba:d3:91:b4
------BEGIN CERTIFICATE-----
-MIIEqjCCA5KgAwIBAgIOLmoAAQACH9dSISwRXDswDQYJKoZIhvcNAQEFBQAwdjEL
-MAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxIjAgBgNV
-BAsTGVRDIFRydXN0Q2VudGVyIENsYXNzIDIgQ0ExJTAjBgNVBAMTHFRDIFRydXN0
-Q2VudGVyIENsYXNzIDIgQ0EgSUkwHhcNMDYwMTEyMTQzODQzWhcNMjUxMjMxMjI1
-OTU5WjB2MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1c3RDZW50ZXIgR21i
-SDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQTElMCMGA1UEAxMc
-VEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQSBJSTCCASIwDQYJKoZIhvcNAQEBBQAD
-ggEPADCCAQoCggEBAKuAh5uO8MN8h9foJIIRszzdQ2Lu+MNF2ujhoF/RKrLqk2jf
-tMjWQ+nEdVl//OEd+DFwIxuInie5e/060smp6RQvkL4DUsFJzfb95AhmC1eKokKg
-uNV/aVyQMrKXDcpK3EY+AlWJU+MaWss2xgdW94zPEfRMuzBwBJWl9jmM/XOBCH2J
-XjIeIqkiRUuwZi4wzJ9l/fzLganx4Duvo4bRierERXlQXa7pIXSSTYtZgo+U4+lK
-8edJsBTj9WLL1XK9H7nSn6DNqPoByNkN39r8R52zyFTfSUrxIan+GE7uSNQZu+99
-5OKdy1u2bv/jzVrndIIFuoAlOMvkaZ6vQaoahPUCAwEAAaOCATQwggEwMA8GA1Ud
-EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTjq1RMgKHbVkO3
-kUrL84J6E1wIqzCB7QYDVR0fBIHlMIHiMIHfoIHcoIHZhjVodHRwOi8vd3d3LnRy
-dXN0Y2VudGVyLmRlL2NybC92Mi90Y19jbGFzc18yX2NhX0lJLmNybIaBn2xkYXA6
-Ly93d3cudHJ1c3RjZW50ZXIuZGUvQ049VEMlMjBUcnVzdENlbnRlciUyMENsYXNz
-JTIwMiUyMENBJTIwSUksTz1UQyUyMFRydXN0Q2VudGVyJTIwR21iSCxPVT1yb290
-Y2VydHMsREM9dHJ1c3RjZW50ZXIsREM9ZGU/Y2VydGlmaWNhdGVSZXZvY2F0aW9u
-TGlzdD9iYXNlPzANBgkqhkiG9w0BAQUFAAOCAQEAjNfffu4bgBCzg/XbEeprS6iS
-GNn3Bzn1LL4GdXpoUxUc6krtXvwjshOg0wn/9vYua0Fxec3ibf2uWWuFHbhOIprt
-ZjluS5TmVfwLG4t3wVMTZonZKNaL80VKY7f9ewthXbhtvsPcW3nS7Yblok2+XnR8
-au0WOB9/WIFaGusyiC2y8zl3gK9etmF1KdsjTYjKUCjLhdLTEKJZbtOTVAB6okaV
-hgWcqRmY5TFyDADiZ9lA4CQze28suVyrZZ0srHbqNZn1l7kPJOzHdiEoZa5X6AeI
-dUpWoNIFOqTmjZKILPPy4cHGYdtBxceb9w4aUUXCYWvcZCcXjFq32nQozZfkvQ==
------END CERTIFICATE-----
-
-# Issuer: CN=TC TrustCenter Class 3 CA II O=TC TrustCenter GmbH OU=TC TrustCenter Class 3 CA
-# Subject: CN=TC TrustCenter Class 3 CA II O=TC TrustCenter GmbH OU=TC TrustCenter Class 3 CA
-# Label: "TC TrustCenter Class 3 CA II"
-# Serial: 1506523511417715638772220530020799
-# MD5 Fingerprint: 56:5f:aa:80:61:12:17:f6:67:21:e6:2b:6d:61:56:8e
-# SHA1 Fingerprint: 80:25:ef:f4:6e:70:c8:d4:72:24:65:84:fe:40:3b:8a:8d:6a:db:f5
-# SHA256 Fingerprint: 8d:a0:84:fc:f9:9c:e0:77:22:f8:9b:32:05:93:98:06:fa:5c:b8:11:e1:c8:13:f6:a1:08:c7:d3:36:b3:40:8e
------BEGIN CERTIFICATE-----
-MIIEqjCCA5KgAwIBAgIOSkcAAQAC5aBd1j8AUb8wDQYJKoZIhvcNAQEFBQAwdjEL
-MAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxIjAgBgNV
-BAsTGVRDIFRydXN0Q2VudGVyIENsYXNzIDMgQ0ExJTAjBgNVBAMTHFRDIFRydXN0
-Q2VudGVyIENsYXNzIDMgQ0EgSUkwHhcNMDYwMTEyMTQ0MTU3WhcNMjUxMjMxMjI1
-OTU5WjB2MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1c3RDZW50ZXIgR21i
-SDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMyBDQTElMCMGA1UEAxMc
-VEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMyBDQSBJSTCCASIwDQYJKoZIhvcNAQEBBQAD
-ggEPADCCAQoCggEBALTgu1G7OVyLBMVMeRwjhjEQY0NVJz/GRcekPewJDRoeIMJW
-Ht4bNwcwIi9v8Qbxq63WyKthoy9DxLCyLfzDlml7forkzMA5EpBCYMnMNWju2l+Q
-Vl/NHE1bWEnrDgFPZPosPIlY2C8u4rBo6SI7dYnWRBpl8huXJh0obazovVkdKyT2
-1oQDZogkAHhg8fir/gKya/si+zXmFtGt9i4S5Po1auUZuV3bOx4a+9P/FRQI2Alq
-ukWdFHlgfa9Aigdzs5OW03Q0jTo3Kd5c7PXuLjHCINy+8U9/I1LZW+Jk2ZyqBwi1
-Rb3R0DHBq1SfqdLDYmAD8bs5SpJKPQq5ncWg/jcCAwEAAaOCATQwggEwMA8GA1Ud
-EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTUovyfs8PYA9NX
-XAek0CSnwPIA1DCB7QYDVR0fBIHlMIHiMIHfoIHcoIHZhjVodHRwOi8vd3d3LnRy
-dXN0Y2VudGVyLmRlL2NybC92Mi90Y19jbGFzc18zX2NhX0lJLmNybIaBn2xkYXA6
-Ly93d3cudHJ1c3RjZW50ZXIuZGUvQ049VEMlMjBUcnVzdENlbnRlciUyMENsYXNz
-JTIwMyUyMENBJTIwSUksTz1UQyUyMFRydXN0Q2VudGVyJTIwR21iSCxPVT1yb290
-Y2VydHMsREM9dHJ1c3RjZW50ZXIsREM9ZGU/Y2VydGlmaWNhdGVSZXZvY2F0aW9u
-TGlzdD9iYXNlPzANBgkqhkiG9w0BAQUFAAOCAQEANmDkcPcGIEPZIxpC8vijsrlN
-irTzwppVMXzEO2eatN9NDoqTSheLG43KieHPOh6sHfGcMrSOWXaiQYUlN6AT0PV8
-TtXqluJucsG7Kv5sbviRmEb8yRtXW+rIGjs/sFGYPAfaLFkB2otE6OF0/ado3VS6
-g0bsyEa1+K+XwDsJHI/OcpY9M1ZwvJbL2NV9IJqDnxrcOfHFcqMRA/07QlIp2+gB
-95tejNaNhk4Z+rwcvsUhpYeeeC422wlxo3I0+GzjBgnyXlal092Y+tTmBvTwtiBj
-S+opvaqCZh77gaqnN60TGOaSw4HBM7uIHqHn4rS9MWwOUT1v+5ZWgOI2F9Hc5A==
------END CERTIFICATE-----
-
-# Issuer: CN=TC TrustCenter Universal CA I O=TC TrustCenter GmbH OU=TC TrustCenter Universal CA
-# Subject: CN=TC TrustCenter Universal CA I O=TC TrustCenter GmbH OU=TC TrustCenter Universal CA
-# Label: "TC TrustCenter Universal CA I"
-# Serial: 601024842042189035295619584734726
-# MD5 Fingerprint: 45:e1:a5:72:c5:a9:36:64:40:9e:f5:e4:58:84:67:8c
-# SHA1 Fingerprint: 6b:2f:34:ad:89:58:be:62:fd:b0:6b:5c:ce:bb:9d:d9:4f:4e:39:f3
-# SHA256 Fingerprint: eb:f3:c0:2a:87:89:b1:fb:7d:51:19:95:d6:63:b7:29:06:d9:13:ce:0d:5e:10:56:8a:8a:77:e2:58:61:67:e7
------BEGIN CERTIFICATE-----
-MIID3TCCAsWgAwIBAgIOHaIAAQAC7LdggHiNtgYwDQYJKoZIhvcNAQEFBQAweTEL
-MAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxJDAiBgNV
-BAsTG1RDIFRydXN0Q2VudGVyIFVuaXZlcnNhbCBDQTEmMCQGA1UEAxMdVEMgVHJ1
-c3RDZW50ZXIgVW5pdmVyc2FsIENBIEkwHhcNMDYwMzIyMTU1NDI4WhcNMjUxMjMx
-MjI1OTU5WjB5MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1c3RDZW50ZXIg
-R21iSDEkMCIGA1UECxMbVEMgVHJ1c3RDZW50ZXIgVW5pdmVyc2FsIENBMSYwJAYD
-VQQDEx1UQyBUcnVzdENlbnRlciBVbml2ZXJzYWwgQ0EgSTCCASIwDQYJKoZIhvcN
-AQEBBQADggEPADCCAQoCggEBAKR3I5ZEr5D0MacQ9CaHnPM42Q9e3s9B6DGtxnSR
-JJZ4Hgmgm5qVSkr1YnwCqMqs+1oEdjneX/H5s7/zA1hV0qq34wQi0fiU2iIIAI3T
-fCZdzHd55yx4Oagmcw6iXSVphU9VDprvxrlE4Vc93x9UIuVvZaozhDrzznq+VZeu
-jRIPFDPiUHDDSYcTvFHe15gSWu86gzOSBnWLknwSaHtwag+1m7Z3W0hZneTvWq3z
-wZ7U10VOylY0Ibw+F1tvdwxIAUMpsN0/lm7mlaoMwCC2/T42J5zjXM9OgdwZu5GQ
-fezmlwQek8wiSdeXhrYTCjxDI3d+8NzmzSQfO4ObNDqDNOMCAwEAAaNjMGEwHwYD
-VR0jBBgwFoAUkqR1LKSevoFE63n8isWVpesQdXMwDwYDVR0TAQH/BAUwAwEB/zAO
-BgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFJKkdSyknr6BROt5/IrFlaXrEHVzMA0G
-CSqGSIb3DQEBBQUAA4IBAQAo0uCG1eb4e/CX3CJrO5UUVg8RMKWaTzqwOuAGy2X1
-7caXJ/4l8lfmXpWMPmRgFVp/Lw0BxbFg/UU1z/CyvwbZ71q+s2IhtNerNXxTPqYn
-8aEt2hojnczd7Dwtnic0XQ/CNnm8yUpiLe1r2X1BQ3y2qsrtYbE3ghUJGooWMNjs
-ydZHcnhLEEYUjl8Or+zHL6sQ17bxbuyGssLoDZJz3KL0Dzq/YSMQiZxIQG5wALPT
-ujdEWBF6AmqI8Dc08BnprNRlc/ZpjGSUOnmFKbAWKwyCPwacx/0QK54PLLae4xW/
-2TYcuiUaUj0a7CIMHOCkoj3w6DnPgcB77V0fb8XQC9eY
------END CERTIFICATE-----
-
-# Issuer: CN=Cybertrust Global Root O=Cybertrust, Inc
-# Subject: CN=Cybertrust Global Root O=Cybertrust, Inc
-# Label: "Cybertrust Global Root"
-# Serial: 4835703278459682877484360
-# MD5 Fingerprint: 72:e4:4a:87:e3:69:40:80:77:ea:bc:e3:f4:ff:f0:e1
-# SHA1 Fingerprint: 5f:43:e5:b1:bf:f8:78:8c:ac:1c:c7:ca:4a:9a:c6:22:2b:cc:34:c6
-# SHA256 Fingerprint: 96:0a:df:00:63:e9:63:56:75:0c:29:65:dd:0a:08:67:da:0b:9c:bd:6e:77:71:4a:ea:fb:23:49:ab:39:3d:a3
------BEGIN CERTIFICATE-----
-MIIDoTCCAomgAwIBAgILBAAAAAABD4WqLUgwDQYJKoZIhvcNAQEFBQAwOzEYMBYG
-A1UEChMPQ3liZXJ0cnVzdCwgSW5jMR8wHQYDVQQDExZDeWJlcnRydXN0IEdsb2Jh
-bCBSb290MB4XDTA2MTIxNTA4MDAwMFoXDTIxMTIxNTA4MDAwMFowOzEYMBYGA1UE
-ChMPQ3liZXJ0cnVzdCwgSW5jMR8wHQYDVQQDExZDeWJlcnRydXN0IEdsb2JhbCBS
-b290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA+Mi8vRRQZhP/8NN5
-7CPytxrHjoXxEnOmGaoQ25yiZXRadz5RfVb23CO21O1fWLE3TdVJDm71aofW0ozS
-J8bi/zafmGWgE07GKmSb1ZASzxQG9Dvj1Ci+6A74q05IlG2OlTEQXO2iLb3VOm2y
-HLtgwEZLAfVJrn5GitB0jaEMAs7u/OePuGtm839EAL9mJRQr3RAwHQeWP032a7iP
-t3sMpTjr3kfb1V05/Iin89cqdPHoWqI7n1C6poxFNcJQZZXcY4Lv3b93TZxiyWNz
-FtApD0mpSPCzqrdsxacwOUBdrsTiXSZT8M4cIwhhqJQZugRiQOwfOHB3EgZxpzAY
-XSUnpQIDAQABo4GlMIGiMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/
-MB0GA1UdDgQWBBS2CHsNesysIEyGVjJez6tuhS1wVzA/BgNVHR8EODA2MDSgMqAw
-hi5odHRwOi8vd3d3Mi5wdWJsaWMtdHJ1c3QuY29tL2NybC9jdC9jdHJvb3QuY3Js
-MB8GA1UdIwQYMBaAFLYIew16zKwgTIZWMl7Pq26FLXBXMA0GCSqGSIb3DQEBBQUA
-A4IBAQBW7wojoFROlZfJ+InaRcHUowAl9B8Tq7ejhVhpwjCt2BWKLePJzYFa+HMj
-Wqd8BfP9IjsO0QbE2zZMcwSO5bAi5MXzLqXZI+O4Tkogp24CJJ8iYGd7ix1yCcUx
-XOl5n4BHPa2hCwcUPUf/A2kaDAtE52Mlp3+yybh2hO0j9n0Hq0V+09+zv+mKts2o
-omcrUtW3ZfA5TGOgkXmTUg9U3YO7n9GPp1Nzw8v/MOx8BLjYRB+TX3EJIrduPuoc
-A06dGiBh+4E37F78CkWr1+cXVdCg6mCbpvbjjFspwgZgFJ0tl0ypkxWdYcQBX0jW
-WL1WMRJOEcgh4LMRkWXbtKaIOM5V
------END CERTIFICATE-----
-
-# Issuer: CN=GeoTrust Primary Certification Authority - G3 O=GeoTrust Inc. OU=(c) 2008 GeoTrust Inc. - For authorized use only
-# Subject: CN=GeoTrust Primary Certification Authority - G3 O=GeoTrust Inc. OU=(c) 2008 GeoTrust Inc. - For authorized use only
-# Label: "GeoTrust Primary Certification Authority - G3"
-# Serial: 28809105769928564313984085209975885599
-# MD5 Fingerprint: b5:e8:34:36:c9:10:44:58:48:70:6d:2e:83:d4:b8:05
-# SHA1 Fingerprint: 03:9e:ed:b8:0b:e7:a0:3c:69:53:89:3b:20:d2:d9:32:3a:4c:2a:fd
-# SHA256 Fingerprint: b4:78:b8:12:25:0d:f8:78:63:5c:2a:a7:ec:7d:15:5e:aa:62:5e:e8:29:16:e2:cd:29:43:61:88:6c:d1:fb:d4
------BEGIN CERTIFICATE-----
-MIID/jCCAuagAwIBAgIQFaxulBmyeUtB9iepwxgPHzANBgkqhkiG9w0BAQsFADCB
-mDELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsT
-MChjKSAyMDA4IEdlb1RydXN0IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25s
-eTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhv
-cml0eSAtIEczMB4XDTA4MDQwMjAwMDAwMFoXDTM3MTIwMTIzNTk1OVowgZgxCzAJ
-BgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykg
-MjAwOCBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0
-BgNVBAMTLUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg
-LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANziXmJYHTNXOTIz
-+uvLh4yn1ErdBojqZI4xmKU4kB6Yzy5jK/BGvESyiaHAKAxJcCGVn2TAppMSAmUm
-hsalifD614SgcK9PGpc/BkTVyetyEH3kMSj7HGHmKAdEc5IiaacDiGydY8hS2pgn
-5whMcD60yRLBxWeDXTPzAxHsatBT4tG6NmCUgLthY2xbF37fQJQeqw3CIShwiP/W
-JmxsYAQlTlV+fe+/lEjetx3dcI0FX4ilm/LC7urRQEFtYjgdVgbFA0dRIBn8exAL
-DmKudlW/X3e+PkkBUz2YJQN2JFodtNuJ6nnltrM7P7pMKEF/BqxqjsHQ9gUdfeZC
-huOl1UcCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw
-HQYDVR0OBBYEFMR5yo6hTgMdHNxr2zFblD4/MH8tMA0GCSqGSIb3DQEBCwUAA4IB
-AQAtxRPPVoB7eni9n64smefv2t+UXglpp+duaIy9cr5HqQ6XErhK8WTTOd8lNNTB
-zU6B8A8ExCSzNJbGpqow32hhc9f5joWJ7w5elShKKiePEI4ufIbEAp7aDHdlDkQN
-kv39sxY2+hENHYwOB4lqKVb3cvTdFZx3NWZXqxNT2I7BQMXXExZacse3aQHEerGD
-AWh9jUGhlBjBJVz88P6DAod8DQ3PLghcSkANPuyBYeYk28rgDi0Hsj5W3I31QYUH
-SJsMC8tJP33st/3LjWeJGqvtux6jAAgIFyqCXDFdRootD4abdNlF+9RAsXqqaC2G
-spki4cErx5z481+oghLrGREt
------END CERTIFICATE-----
-
-# Issuer: CN=thawte Primary Root CA - G2 O=thawte, Inc. OU=(c) 2007 thawte, Inc. - For authorized use only
-# Subject: CN=thawte Primary Root CA - G2 O=thawte, Inc. OU=(c) 2007 thawte, Inc. - For authorized use only
-# Label: "thawte Primary Root CA - G2"
-# Serial: 71758320672825410020661621085256472406
-# MD5 Fingerprint: 74:9d:ea:60:24:c4:fd:22:53:3e:cc:3a:72:d9:29:4f
-# SHA1 Fingerprint: aa:db:bc:22:23:8f:c4:01:a1:27:bb:38:dd:f4:1d:db:08:9e:f0:12
-# SHA256 Fingerprint: a4:31:0d:50:af:18:a6:44:71:90:37:2a:86:af:af:8b:95:1f:fb:43:1d:83:7f:1e:56:88:b4:59:71:ed:15:57
------BEGIN CERTIFICATE-----
-MIICiDCCAg2gAwIBAgIQNfwmXNmET8k9Jj1Xm67XVjAKBggqhkjOPQQDAzCBhDEL
-MAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjE4MDYGA1UECxMvKGMp
-IDIwMDcgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAi
-BgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMjAeFw0wNzExMDUwMDAw
-MDBaFw0zODAxMTgyMzU5NTlaMIGEMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhh
-d3RlLCBJbmMuMTgwNgYDVQQLEy8oYykgMjAwNyB0aGF3dGUsIEluYy4gLSBGb3Ig
-YXV0aG9yaXplZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9v
-dCBDQSAtIEcyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEotWcgnuVnfFSeIf+iha/
-BebfowJPDQfGAFG6DAJSLSKkQjnE/o/qycG+1E3/n3qe4rF8mq2nhglzh9HnmuN6
-papu+7qzcMBniKI11KOasf2twu8x+qi58/sIxpHR+ymVo0IwQDAPBgNVHRMBAf8E
-BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUmtgAMADna3+FGO6Lts6K
-DPgR4bswCgYIKoZIzj0EAwMDaQAwZgIxAN344FdHW6fmCsO99YCKlzUNG4k8VIZ3
-KMqh9HneteY4sPBlcIx/AlTCv//YoT7ZzwIxAMSNlPzcU9LcnXgWHxUzI1NS41ox
-XZ3Krr0TKUQNJ1uo52icEvdYPy5yAlejj6EULg==
------END CERTIFICATE-----
-
-# Issuer: CN=thawte Primary Root CA - G3 O=thawte, Inc. OU=Certification Services Division/(c) 2008 thawte, Inc. - For authorized use only
-# Subject: CN=thawte Primary Root CA - G3 O=thawte, Inc. OU=Certification Services Division/(c) 2008 thawte, Inc. - For authorized use only
-# Label: "thawte Primary Root CA - G3"
-# Serial: 127614157056681299805556476275995414779
-# MD5 Fingerprint: fb:1b:5d:43:8a:94:cd:44:c6:76:f2:43:4b:47:e7:31
-# SHA1 Fingerprint: f1:8b:53:8d:1b:e9:03:b6:a6:f0:56:43:5b:17:15:89:ca:f3:6b:f2
-# SHA256 Fingerprint: 4b:03:f4:58:07:ad:70:f2:1b:fc:2c:ae:71:c9:fd:e4:60:4c:06:4c:f5:ff:b6:86:ba:e5:db:aa:d7:fd:d3:4c
------BEGIN CERTIFICATE-----
-MIIEKjCCAxKgAwIBAgIQYAGXt0an6rS0mtZLL/eQ+zANBgkqhkiG9w0BAQsFADCB
-rjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf
-Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw
-MDggdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAiBgNV
-BAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMzAeFw0wODA0MDIwMDAwMDBa
-Fw0zNzEyMDEyMzU5NTlaMIGuMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhhd3Rl
-LCBJbmMuMSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9uIFNlcnZpY2VzIERpdmlzaW9u
-MTgwNgYDVQQLEy8oYykgMjAwOCB0aGF3dGUsIEluYy4gLSBGb3IgYXV0aG9yaXpl
-ZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAtIEcz
-MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsr8nLPvb2FvdeHsbnndm
-gcs+vHyu86YnmjSjaDFxODNi5PNxZnmxqWWjpYvVj2AtP0LMqmsywCPLLEHd5N/8
-YZzic7IilRFDGF/Eth9XbAoFWCLINkw6fKXRz4aviKdEAhN0cXMKQlkC+BsUa0Lf
-b1+6a4KinVvnSr0eAXLbS3ToO39/fR8EtCab4LRarEc9VbjXsCZSKAExQGbY2SS9
-9irY7CFJXJv2eul/VTV+lmuNk5Mny5K76qxAwJ/C+IDPXfRa3M50hqY+bAtTyr2S
-zhkGcuYMXDhpxwTWvGzOW/b3aJzcJRVIiKHpqfiYnODz1TEoYRFsZ5aNOZnLwkUk
-OQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNV
-HQ4EFgQUrWyqlGCc7eT/+j4KdCtjA/e2Wb8wDQYJKoZIhvcNAQELBQADggEBABpA
-2JVlrAmSicY59BDlqQ5mU1143vokkbvnRFHfxhY0Cu9qRFHqKweKA3rD6z8KLFIW
-oCtDuSWQP3CpMyVtRRooOyfPqsMpQhvfO0zAMzRbQYi/aytlryjvsvXDqmbOe1bu
-t8jLZ8HJnBoYuMTDSQPxYA5QzUbF83d597YV4Djbxy8ooAw/dyZ02SUS2jHaGh7c
-KUGRIjxpp7sC8rZcJwOJ9Abqm+RyguOhCcHpABnTPtRwa7pxpqpYrvS76Wy274fM
-m7v/OeZWYdMKp8RcTGB7BXcmer/YB1IsYvdwY9k5vG8cwnncdimvzsUsZAReiDZu
-MdRAGmI0Nj81Aa6sY6A=
------END CERTIFICATE-----
-
-# Issuer: CN=GeoTrust Primary Certification Authority - G2 O=GeoTrust Inc. OU=(c) 2007 GeoTrust Inc. - For authorized use only
-# Subject: CN=GeoTrust Primary Certification Authority - G2 O=GeoTrust Inc. OU=(c) 2007 GeoTrust Inc. - For authorized use only
-# Label: "GeoTrust Primary Certification Authority - G2"
-# Serial: 80682863203381065782177908751794619243
-# MD5 Fingerprint: 01:5e:d8:6b:bd:6f:3d:8e:a1:31:f8:12:e0:98:73:6a
-# SHA1 Fingerprint: 8d:17:84:d5:37:f3:03:7d:ec:70:fe:57:8b:51:9a:99:e6:10:d7:b0
-# SHA256 Fingerprint: 5e:db:7a:c4:3b:82:a0:6a:87:61:e8:d7:be:49:79:eb:f2:61:1f:7d:d7:9b:f9:1c:1c:6b:56:6a:21:9e:d7:66
------BEGIN CERTIFICATE-----
-MIICrjCCAjWgAwIBAgIQPLL0SAoA4v7rJDteYD7DazAKBggqhkjOPQQDAzCBmDEL
-MAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChj
-KSAyMDA3IEdlb1RydXN0IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2
-MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0
-eSAtIEcyMB4XDTA3MTEwNTAwMDAwMFoXDTM4MDExODIzNTk1OVowgZgxCzAJBgNV
-BAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykgMjAw
-NyBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNV
-BAMTLUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBH
-MjB2MBAGByqGSM49AgEGBSuBBAAiA2IABBWx6P0DFUPlrOuHNxFi79KDNlJ9RVcL
-So17VDs6bl8VAsBQps8lL33KSLjHUGMcKiEIfJo22Av+0SbFWDEwKCXzXV2juLal
-tJLtbCyf691DiaI8S0iRHVDsJt/WYC69IaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO
-BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBVfNVdRVfslsq0DafwBo/q+EVXVMAoG
-CCqGSM49BAMDA2cAMGQCMGSWWaboCd6LuvpaiIjwH5HTRqjySkwCY/tsXzjbLkGT
-qQ7mndwxHLKgpxgceeHHNgIwOlavmnRs9vuD4DPTCF+hnMJbn0bWtsuRBmOiBucz
-rD6ogRLQy7rQkgu2npaqBA+K
------END CERTIFICATE-----
-
-# Issuer: CN=VeriSign Universal Root Certification Authority O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 2008 VeriSign, Inc. - For authorized use only
-# Subject: CN=VeriSign Universal Root Certification Authority O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 2008 VeriSign, Inc. - For authorized use only
-# Label: "VeriSign Universal Root Certification Authority"
-# Serial: 85209574734084581917763752644031726877
-# MD5 Fingerprint: 8e:ad:b5:01:aa:4d:81:e4:8c:1d:d1:e1:14:00:95:19
-# SHA1 Fingerprint: 36:79:ca:35:66:87:72:30:4d:30:a5:fb:87:3b:0f:a7:7b:b7:0d:54
-# SHA256 Fingerprint: 23:99:56:11:27:a5:71:25:de:8c:ef:ea:61:0d:df:2f:a0:78:b5:c8:06:7f:4e:82:82:90:bf:b8:60:e8:4b:3c
------BEGIN CERTIFICATE-----
-MIIEuTCCA6GgAwIBAgIQQBrEZCGzEyEDDrvkEhrFHTANBgkqhkiG9w0BAQsFADCB
-vTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL
-ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwOCBWZXJp
-U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MTgwNgYDVQQDEy9W
-ZXJpU2lnbiBVbml2ZXJzYWwgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe
-Fw0wODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIG9MQswCQYDVQQGEwJVUzEX
-MBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0
-IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAyMDA4IFZlcmlTaWduLCBJbmMuIC0gRm9y
-IGF1dGhvcml6ZWQgdXNlIG9ubHkxODA2BgNVBAMTL1ZlcmlTaWduIFVuaXZlcnNh
-bCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEF
-AAOCAQ8AMIIBCgKCAQEAx2E3XrEBNNti1xWb/1hajCMj1mCOkdeQmIN65lgZOIzF
-9uVkhbSicfvtvbnazU0AtMgtc6XHaXGVHzk8skQHnOgO+k1KxCHfKWGPMiJhgsWH
-H26MfF8WIFFE0XBPV+rjHOPMee5Y2A7Cs0WTwCznmhcrewA3ekEzeOEz4vMQGn+H
-LL729fdC4uW/h2KJXwBL38Xd5HVEMkE6HnFuacsLdUYI0crSK5XQz/u5QGtkjFdN
-/BMReYTtXlT2NJ8IAfMQJQYXStrxHXpma5hgZqTZ79IugvHw7wnqRMkVauIDbjPT
-rJ9VAMf2CGqUuV/c4DPxhGD5WycRtPwW8rtWaoAljQIDAQABo4GyMIGvMA8GA1Ud
-EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMG0GCCsGAQUFBwEMBGEwX6FdoFsw
-WTBXMFUWCWltYWdlL2dpZjAhMB8wBwYFKw4DAhoEFI/l0xqGrI2Oa8PPgGrUSBgs
-exkuMCUWI2h0dHA6Ly9sb2dvLnZlcmlzaWduLmNvbS92c2xvZ28uZ2lmMB0GA1Ud
-DgQWBBS2d/ppSEefUxLVwuoHMnYH0ZcHGTANBgkqhkiG9w0BAQsFAAOCAQEASvj4
-sAPmLGd75JR3Y8xuTPl9Dg3cyLk1uXBPY/ok+myDjEedO2Pzmvl2MpWRsXe8rJq+
-seQxIcaBlVZaDrHC1LGmWazxY8u4TB1ZkErvkBYoH1quEPuBUDgMbMzxPcP1Y+Oz
-4yHJJDnp/RVmRvQbEdBNc6N9Rvk97ahfYtTxP/jgdFcrGJ2BtMQo2pSXpXDrrB2+
-BxHw1dvd5Yzw1TKwg+ZX4o+/vqGqvz0dtdQ46tewXDpPaj+PwGZsY6rp2aQW9IHR
-lRQOfc2VNNnSj3BzgXucfr2YYdhFh5iQxeuGMMY1v/D/w1WIg0vvBZIGcfK4mJO3
-7M2CYfE45k+XmCpajQ==
------END CERTIFICATE-----
-
-# Issuer: CN=VeriSign Class 3 Public Primary Certification Authority - G4 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 2007 VeriSign, Inc. - For authorized use only
-# Subject: CN=VeriSign Class 3 Public Primary Certification Authority - G4 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 2007 VeriSign, Inc. - For authorized use only
-# Label: "VeriSign Class 3 Public Primary Certification Authority - G4"
-# Serial: 63143484348153506665311985501458640051
-# MD5 Fingerprint: 3a:52:e1:e7:fd:6f:3a:e3:6f:f3:6f:99:1b:f9:22:41
-# SHA1 Fingerprint: 22:d5:d8:df:8f:02:31:d1:8d:f7:9d:b7:cf:8a:2d:64:c9:3f:6c:3a
-# SHA256 Fingerprint: 69:dd:d7:ea:90:bb:57:c9:3e:13:5d:c8:5e:a6:fc:d5:48:0b:60:32:39:bd:c4:54:fc:75:8b:2a:26:cf:7f:79
------BEGIN CERTIFICATE-----
-MIIDhDCCAwqgAwIBAgIQL4D+I4wOIg9IZxIokYesszAKBggqhkjOPQQDAzCByjEL
-MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW
-ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2ln
-biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp
-U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y
-aXR5IC0gRzQwHhcNMDcxMTA1MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCByjELMAkG
-A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJp
-U2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwg
-SW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2ln
-biBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5
-IC0gRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASnVnp8Utpkmw4tXNherJI9/gHm
-GUo9FANL+mAnINmDiWn6VMaaGF5VKmTeBvaNSjutEDxlPZCIBIngMGGzrl0Bp3ve
-fLK+ymVhAIau2o970ImtTR1ZmkGxvEeA3J5iw/mjgbIwga8wDwYDVR0TAQH/BAUw
-AwEB/zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJ
-aW1hZ2UvZ2lmMCEwHzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYj
-aHR0cDovL2xvZ28udmVyaXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFLMW
-kf3upm7ktS5Jj4d4gYDs5bG1MAoGCCqGSM49BAMDA2gAMGUCMGYhDBgmYFo4e1ZC
-4Kf8NoRRkSAsdk1DPcQdhCPQrNZ8NQbOzWm9kA3bbEhCHQ6qQgIxAJw9SDkjOVga
-FRJZap7v1VmyHVIsmXHNxynfGyphe3HR3vPA5Q06Sqotp9iGKt0uEA==
------END CERTIFICATE-----
-
-# Issuer: O=VeriSign, Inc. OU=Class 3 Public Primary Certification Authority
-# Subject: O=VeriSign, Inc. OU=Class 3 Public Primary Certification Authority
-# Label: "Verisign Class 3 Public Primary Certification Authority"
-# Serial: 80507572722862485515306429940691309246
-# MD5 Fingerprint: ef:5a:f1:33:ef:f1:cd:bb:51:02:ee:12:14:4b:96:c4
-# SHA1 Fingerprint: a1:db:63:93:91:6f:17:e4:18:55:09:40:04:15:c7:02:40:b0:ae:6b
-# SHA256 Fingerprint: a4:b6:b3:99:6f:c2:f3:06:b3:fd:86:81:bd:63:41:3d:8c:50:09:cc:4f:a3:29:c2:cc:f0:e2:fa:1b:14:03:05
------BEGIN CERTIFICATE-----
-MIICPDCCAaUCEDyRMcsf9tAbDpq40ES/Er4wDQYJKoZIhvcNAQEFBQAwXzELMAkG
-A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz
-cyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2
-MDEyOTAwMDAwMFoXDTI4MDgwMjIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV
-BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmlt
-YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN
-ADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhE
-BarsAx94f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/is
-I19wKTakyYbnsZogy1Olhec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0G
-CSqGSIb3DQEBBQUAA4GBABByUqkFFBkyCEHwxWsKzH4PIRnN5GfcX6kb5sroc50i
-2JhucwNhkcV8sEVAbkSdjbCxlnRhLQ2pRdKkkirWmnWXbj9T/UWZYB2oK0z5XqcJ
-2HUw19JlYD1n1khVdWk/kfVIC0dpImmClr7JyDiGSnoscxlIaU5rfGW/D/xwzoiQ
------END CERTIFICATE-----
-
-# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R3
-# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R3
-# Label: "GlobalSign Root CA - R3"
-# Serial: 4835703278459759426209954
-# MD5 Fingerprint: c5:df:b8:49:ca:05:13:55:ee:2d:ba:1a:c3:3e:b0:28
-# SHA1 Fingerprint: d6:9b:56:11:48:f0:1c:77:c5:45:78:c1:09:26:df:5b:85:69:76:ad
-# SHA256 Fingerprint: cb:b5:22:d7:b7:f1:27:ad:6a:01:13:86:5b:df:1c:d4:10:2e:7d:07:59:af:63:5a:7c:f4:72:0d:c9:63:c5:3b
------BEGIN CERTIFICATE-----
-MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G
-A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp
-Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4
-MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEG
-A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI
-hvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8
-RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsT
-gHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmm
-KPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zd
-QQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZ
-XriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAw
-DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+o
-LkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZU
-RUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMp
-jjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK
-6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQX
-mcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecs
-Mx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH
-WD9f
------END CERTIFICATE-----
-
-# Issuer: CN=TC TrustCenter Universal CA III O=TC TrustCenter GmbH OU=TC TrustCenter Universal CA
-# Subject: CN=TC TrustCenter Universal CA III O=TC TrustCenter GmbH OU=TC TrustCenter Universal CA
-# Label: "TC TrustCenter Universal CA III"
-# Serial: 2010889993983507346460533407902964
-# MD5 Fingerprint: 9f:dd:db:ab:ff:8e:ff:45:21:5f:f0:6c:9d:8f:fe:2b
-# SHA1 Fingerprint: 96:56:cd:7b:57:96:98:95:d0:e1:41:46:68:06:fb:b8:c6:11:06:87
-# SHA256 Fingerprint: 30:9b:4a:87:f6:ca:56:c9:31:69:aa:a9:9c:6d:98:88:54:d7:89:2b:d5:43:7e:2d:07:b2:9c:be:da:55:d3:5d
------BEGIN CERTIFICATE-----
-MIID4TCCAsmgAwIBAgIOYyUAAQACFI0zFQLkbPQwDQYJKoZIhvcNAQEFBQAwezEL
-MAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxJDAiBgNV
-BAsTG1RDIFRydXN0Q2VudGVyIFVuaXZlcnNhbCBDQTEoMCYGA1UEAxMfVEMgVHJ1
-c3RDZW50ZXIgVW5pdmVyc2FsIENBIElJSTAeFw0wOTA5MDkwODE1MjdaFw0yOTEy
-MzEyMzU5NTlaMHsxCzAJBgNVBAYTAkRFMRwwGgYDVQQKExNUQyBUcnVzdENlbnRl
-ciBHbWJIMSQwIgYDVQQLExtUQyBUcnVzdENlbnRlciBVbml2ZXJzYWwgQ0ExKDAm
-BgNVBAMTH1RDIFRydXN0Q2VudGVyIFVuaXZlcnNhbCBDQSBJSUkwggEiMA0GCSqG
-SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDC2pxisLlxErALyBpXsq6DFJmzNEubkKLF
-5+cvAqBNLaT6hdqbJYUtQCggbergvbFIgyIpRJ9Og+41URNzdNW88jBmlFPAQDYv
-DIRlzg9uwliT6CwLOunBjvvya8o84pxOjuT5fdMnnxvVZ3iHLX8LR7PH6MlIfK8v
-zArZQe+f/prhsq75U7Xl6UafYOPfjdN/+5Z+s7Vy+EutCHnNaYlAJ/Uqwa1D7KRT
-yGG299J5KmcYdkhtWyUB0SbFt1dpIxVbYYqt8Bst2a9c8SaQaanVDED1M4BDj5yj
-dipFtK+/fz6HP3bFzSreIMUWWMv5G/UPyw0RUmS40nZid4PxWJ//AgMBAAGjYzBh
-MB8GA1UdIwQYMBaAFFbn4VslQ4Dg9ozhcbyO5YAvxEjiMA8GA1UdEwEB/wQFMAMB
-Af8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRW5+FbJUOA4PaM4XG8juWAL8RI
-4jANBgkqhkiG9w0BAQUFAAOCAQEAg8ev6n9NCjw5sWi+e22JLumzCecYV42Fmhfz
-dkJQEw/HkG8zrcVJYCtsSVgZ1OK+t7+rSbyUyKu+KGwWaODIl0YgoGhnYIg5IFHY
-aAERzqf2EQf27OysGh+yZm5WZ2B6dF7AbZc2rrUNXWZzwCUyRdhKBgePxLcHsU0G
-DeGl6/R1yrqc0L2z0zIkTO5+4nYES0lT2PLpVDP85XEfPRRclkvxOvIAu2y0+pZV
-CIgJwcyRGSmwIC3/yzikQOEXvnlhgP8HA4ZMTnsGnxGGjYnuJ8Tb4rwZjgvDwxPH
-LQNjO9Po5KIqwoIIlBZU8O8fJ5AluA0OKBtHd0e9HKgl8ZS0Zg==
------END CERTIFICATE-----
-
-# Issuer: CN=Go Daddy Root Certificate Authority - G2 O=GoDaddy.com, Inc.
-# Subject: CN=Go Daddy Root Certificate Authority - G2 O=GoDaddy.com, Inc.
-# Label: "Go Daddy Root Certificate Authority - G2"
-# Serial: 0
-# MD5 Fingerprint: 80:3a:bc:22:c1:e6:fb:8d:9b:3b:27:4a:32:1b:9a:01
-# SHA1 Fingerprint: 47:be:ab:c9:22:ea:e8:0e:78:78:34:62:a7:9f:45:c2:54:fd:e6:8b
-# SHA256 Fingerprint: 45:14:0b:32:47:eb:9c:c8:c5:b4:f0:d7:b5:30:91:f7:32:92:08:9e:6e:5a:63:e2:74:9d:d3:ac:a9:19:8e:da
------BEGIN CERTIFICATE-----
-MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMx
-EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoT
-EUdvRGFkZHkuY29tLCBJbmMuMTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRp
-ZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIz
-NTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQH
-EwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8GA1UE
-AxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIw
-DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKD
-E6bFIEMBO4Tx5oVJnyfq9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH
-/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD+qK+ihVqf94Lw7YZFAXK6sOoBJQ7Rnwy
-DfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutdfMh8+7ArU6SSYmlRJQVh
-GkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMlNAJWJwGR
-tDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEA
-AaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE
-FDqahQcQZyi27/a9BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmX
-WWcDYfF+OwYxdS2hII5PZYe096acvNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu
-9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r5N9ss4UXnT3ZJE95kTXWXwTr
-gIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYVN8Gb5DKj7Tjo
-2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO
-LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI
-4uJEvlz36hz1
------END CERTIFICATE-----
-
-# Issuer: CN=Starfield Root Certificate Authority - G2 O=Starfield Technologies, Inc.
-# Subject: CN=Starfield Root Certificate Authority - G2 O=Starfield Technologies, Inc.
-# Label: "Starfield Root Certificate Authority - G2"
-# Serial: 0
-# MD5 Fingerprint: d6:39:81:c6:52:7e:96:69:fc:fc:ca:66:ed:05:f2:96
-# SHA1 Fingerprint: b5:1c:06:7c:ee:2b:0c:3d:f8:55:ab:2d:92:f4:fe:39:d4:e7:0f:0e
-# SHA256 Fingerprint: 2c:e1:cb:0b:f9:d2:f9:e1:02:99:3f:be:21:51:52:c3:b2:dd:0c:ab:de:1c:68:e5:31:9b:83:91:54:db:b7:f5
------BEGIN CERTIFICATE-----
-MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMx
-EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT
-HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVs
-ZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAw
-MFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6
-b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQgVGVj
-aG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZp
-Y2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
-ggEBAL3twQP89o/8ArFvW59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMg
-nLRJdzIpVv257IzdIvpy3Cdhl+72WoTsbhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1
-HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNkN3mSwOxGXn/hbVNMYq/N
-Hwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7NfZTD4p7dN
-dloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0
-HZbUJtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO
-BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0G
-CSqGSIb3DQEBCwUAA4IBAQARWfolTwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjU
-sHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx4mcujJUDJi5DnUox9g61DLu3
-4jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUwF5okxBDgBPfg
-8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K
-pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1
-mMpYjn0q7pBZc2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0
------END CERTIFICATE-----
-
-# Issuer: CN=Starfield Services Root Certificate Authority - G2 O=Starfield Technologies, Inc.
-# Subject: CN=Starfield Services Root Certificate Authority - G2 O=Starfield Technologies, Inc.
-# Label: "Starfield Services Root Certificate Authority - G2"
-# Serial: 0
-# MD5 Fingerprint: 17:35:74:af:7b:61:1c:eb:f4:f9:3c:e2:ee:40:f9:a2
-# SHA1 Fingerprint: 92:5a:8f:8d:2c:6d:04:e0:66:5f:59:6a:ff:22:d8:63:e8:25:6f:3f
-# SHA256 Fingerprint: 56:8d:69:05:a2:c8:87:08:a4:b3:02:51:90:ed:cf:ed:b1:97:4a:60:6a:13:c6:e5:29:0f:cb:2a:e6:3e:da:b5
------BEGIN CERTIFICATE-----
-MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMx
-EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT
-HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVs
-ZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5
-MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNVBAYTAlVTMRAwDgYD
-VQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFy
-ZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2Vy
-dmljZXMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI
-hvcNAQEBBQADggEPADCCAQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20p
-OsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm2
-8xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4PahHQUw2eeBGg6345AWh1K
-Ts9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLPLJGmpufe
-hRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk
-6mFBrMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAw
-DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+q
-AdcwKziIorhtSpzyEZGDMA0GCSqGSIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMI
-bw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPPE95Dz+I0swSdHynVv/heyNXB
-ve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTyxQGjhdByPq1z
-qwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd
-iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn
-0q23KXB56jzaYyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCN
-sSi6
------END CERTIFICATE-----
-
-# Issuer: CN=AffirmTrust Commercial O=AffirmTrust
-# Subject: CN=AffirmTrust Commercial O=AffirmTrust
-# Label: "AffirmTrust Commercial"
-# Serial: 8608355977964138876
-# MD5 Fingerprint: 82:92:ba:5b:ef:cd:8a:6f:a6:3d:55:f9:84:f6:d6:b7
-# SHA1 Fingerprint: f9:b5:b6:32:45:5f:9c:be:ec:57:5f:80:dc:e9:6e:2c:c7:b2:78:b7
-# SHA256 Fingerprint: 03:76:ab:1d:54:c5:f9:80:3c:e4:b2:e2:01:a0:ee:7e:ef:7b:57:b6:36:e8:a9:3c:9b:8d:48:60:c9:6f:5f:a7
------BEGIN CERTIFICATE-----
-MIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UE
-BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz
-dCBDb21tZXJjaWFsMB4XDTEwMDEyOTE0MDYwNloXDTMwMTIzMTE0MDYwNlowRDEL
-MAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZp
-cm1UcnVzdCBDb21tZXJjaWFsMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
-AQEA9htPZwcroRX1BiLLHwGy43NFBkRJLLtJJRTWzsO3qyxPxkEylFf6EqdbDuKP
-Hx6GGaeqtS25Xw2Kwq+FNXkyLbscYjfysVtKPcrNcV/pQr6U6Mje+SJIZMblq8Yr
-ba0F8PrVC8+a5fBQpIs7R6UjW3p6+DM/uO+Zl+MgwdYoic+U+7lF7eNAFxHUdPAL
-MeIrJmqbTFeurCA+ukV6BfO9m2kVrn1OIGPENXY6BwLJN/3HR+7o8XYdcxXyl6S1
-yHp52UKqK39c/s4mT6NmgTWvRLpUHhwwMmWd5jyTXlBOeuM61G7MGvv50jeuJCqr
-VwMiKA1JdX+3KNp1v47j3A55MQIDAQABo0IwQDAdBgNVHQ4EFgQUnZPGU4teyq8/
-nx4P5ZmVvCT2lI8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJ
-KoZIhvcNAQELBQADggEBAFis9AQOzcAN/wr91LoWXym9e2iZWEnStB03TX8nfUYG
-XUPGhi4+c7ImfU+TqbbEKpqrIZcUsd6M06uJFdhrJNTxFq7YpFzUf1GO7RgBsZNj
-vbz4YYCanrHOQnDiqX0GJX0nof5v7LMeJNrjS1UaADs1tDvZ110w/YETifLCBivt
-Z8SOyUOyXGsViQK8YvxO8rUzqrJv0wqiUOP2O+guRMLbZjipM1ZI8W0bM40NjD9g
-N53Tym1+NH4Nn3J2ixufcv1SNUFFApYvHLKac0khsUlHRUe072o0EclNmsxZt9YC
-nlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8=
------END CERTIFICATE-----
-
-# Issuer: CN=AffirmTrust Networking O=AffirmTrust
-# Subject: CN=AffirmTrust Networking O=AffirmTrust
-# Label: "AffirmTrust Networking"
-# Serial: 8957382827206547757
-# MD5 Fingerprint: 42:65:ca:be:01:9a:9a:4c:a9:8c:41:49:cd:c0:d5:7f
-# SHA1 Fingerprint: 29:36:21:02:8b:20:ed:02:f5:66:c5:32:d1:d6:ed:90:9f:45:00:2f
-# SHA256 Fingerprint: 0a:81:ec:5a:92:97:77:f1:45:90:4a:f3:8d:5d:50:9f:66:b5:e2:c5:8f:cd:b5:31:05:8b:0e:17:f3:f0:b4:1b
------BEGIN CERTIFICATE-----
-MIIDTDCCAjSgAwIBAgIIfE8EORzUmS0wDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UE
-BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz
-dCBOZXR3b3JraW5nMB4XDTEwMDEyOTE0MDgyNFoXDTMwMTIzMTE0MDgyNFowRDEL
-MAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZp
-cm1UcnVzdCBOZXR3b3JraW5nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
-AQEAtITMMxcua5Rsa2FSoOujz3mUTOWUgJnLVWREZY9nZOIG41w3SfYvm4SEHi3y
-YJ0wTsyEheIszx6e/jarM3c1RNg1lho9Nuh6DtjVR6FqaYvZ/Ls6rnla1fTWcbua
-kCNrmreIdIcMHl+5ni36q1Mr3Lt2PpNMCAiMHqIjHNRqrSK6mQEubWXLviRmVSRL
-QESxG9fhwoXA3hA/Pe24/PHxI1Pcv2WXb9n5QHGNfb2V1M6+oF4nI979ptAmDgAp
-6zxG8D1gvz9Q0twmQVGeFDdCBKNwV6gbh+0t+nvujArjqWaJGctB+d1ENmHP4ndG
-yH329JKBNv3bNPFyfvMMFr20FQIDAQABo0IwQDAdBgNVHQ4EFgQUBx/S55zawm6i
-QLSwelAQUHTEyL0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJ
-KoZIhvcNAQEFBQADggEBAIlXshZ6qML91tmbmzTCnLQyFE2npN/svqe++EPbkTfO
-tDIuUFUaNU52Q3Eg75N3ThVwLofDwR1t3Mu1J9QsVtFSUzpE0nPIxBsFZVpikpzu
-QY0x2+c06lkh1QF612S4ZDnNye2v7UsDSKegmQGA3GWjNq5lWUhPgkvIZfFXHeVZ
-Lgo/bNjR9eUJtGxUAArgFU2HdW23WJZa3W3SAKD0m0i+wzekujbgfIeFlxoVot4u
-olu9rxj5kFDNcFn4J2dHy8egBzp90SxdbBk6ZrV9/ZFvgrG+CJPbFEfxojfHRZ48
-x3evZKiT3/Zpg4Jg8klCNO1aAFSFHBY2kgxc+qatv9s=
------END CERTIFICATE-----
-
-# Issuer: CN=AffirmTrust Premium O=AffirmTrust
-# Subject: CN=AffirmTrust Premium O=AffirmTrust
-# Label: "AffirmTrust Premium"
-# Serial: 7893706540734352110
-# MD5 Fingerprint: c4:5d:0e:48:b6:ac:28:30:4e:0a:bc:f9:38:16:87:57
-# SHA1 Fingerprint: d8:a6:33:2c:e0:03:6f:b1:85:f6:63:4f:7d:6a:06:65:26:32:28:27
-# SHA256 Fingerprint: 70:a7:3f:7f:37:6b:60:07:42:48:90:45:34:b1:14:82:d5:bf:0e:69:8e:cc:49:8d:f5:25:77:eb:f2:e9:3b:9a
------BEGIN CERTIFICATE-----
-MIIFRjCCAy6gAwIBAgIIbYwURrGmCu4wDQYJKoZIhvcNAQEMBQAwQTELMAkGA1UE
-BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVz
-dCBQcmVtaXVtMB4XDTEwMDEyOTE0MTAzNloXDTQwMTIzMTE0MTAzNlowQTELMAkG
-A1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1U
-cnVzdCBQcmVtaXVtMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxBLf
-qV/+Qd3d9Z+K4/as4Tx4mrzY8H96oDMq3I0gW64tb+eT2TZwamjPjlGjhVtnBKAQ
-JG9dKILBl1fYSCkTtuG+kU3fhQxTGJoeJKJPj/CihQvL9Cl/0qRY7iZNyaqoe5rZ
-+jjeRFcV5fiMyNlI4g0WJx0eyIOFJbe6qlVBzAMiSy2RjYvmia9mx+n/K+k8rNrS
-s8PhaJyJ+HoAVt70VZVs+7pk3WKL3wt3MutizCaam7uqYoNMtAZ6MMgpv+0GTZe5
-HMQxK9VfvFMSF5yZVylmd2EhMQcuJUmdGPLu8ytxjLW6OQdJd/zvLpKQBY0tL3d7
-70O/Nbua2Plzpyzy0FfuKE4mX4+QaAkvuPjcBukumj5Rp9EixAqnOEhss/n/fauG
-V+O61oV4d7pD6kh/9ti+I20ev9E2bFhc8e6kGVQa9QPSdubhjL08s9NIS+LI+H+S
-qHZGnEJlPqQewQcDWkYtuJfzt9WyVSHvutxMAJf7FJUnM7/oQ0dG0giZFmA7mn7S
-5u046uwBHjxIVkkJx0w3AJ6IDsBz4W9m6XJHMD4Q5QsDyZpCAGzFlH5hxIrff4Ia
-C1nEWTJ3s7xgaVY5/bQGeyzWZDbZvUjthB9+pSKPKrhC9IK31FOQeE4tGv2Bb0TX
-OwF0lkLgAOIua+rF7nKsu7/+6qqo+Nz2snmKtmcCAwEAAaNCMEAwHQYDVR0OBBYE
-FJ3AZ6YMItkm9UWrpmVSESfYRaxjMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/
-BAQDAgEGMA0GCSqGSIb3DQEBDAUAA4ICAQCzV00QYk465KzquByvMiPIs0laUZx2
-KI15qldGF9X1Uva3ROgIRL8YhNILgM3FEv0AVQVhh0HctSSePMTYyPtwni94loMg
-Nt58D2kTiKV1NpgIpsbfrM7jWNa3Pt668+s0QNiigfV4Py/VpfzZotReBA4Xrf5B
-8OWycvpEgjNC6C1Y91aMYj+6QrCcDFx+LmUmXFNPALJ4fqENmS2NuB2OosSw/WDQ
-MKSOyARiqcTtNd56l+0OOF6SL5Nwpamcb6d9Ex1+xghIsV5n61EIJenmJWtSKZGc
-0jlzCFfemQa0W50QBuHCAKi4HEoCChTQwUHK+4w1IX2COPKpVJEZNZOUbWo6xbLQ
-u4mGk+ibyQ86p3q4ofB4Rvr8Ny/lioTz3/4E2aFooC8k4gmVBtWVyuEklut89pMF
-u+1z6S3RdTnX5yTb2E5fQ4+e0BQ5v1VwSJlXMbSc7kqYA5YwH2AG7hsj/oFgIxpH
-YoWlzBk0gG+zrBrjn/B7SK3VAdlntqlyk+otZrWyuOQ9PLLvTIzq6we/qzWaVYa8
-GKa1qF60g2xraUDTn9zxw2lrueFtCfTxqlB2Cnp9ehehVZZCmTEJ3WARjQUwfuaO
-RtGdFNrHF+QFlozEJLUbzxQHskD4o55BhrwE0GuWyCqANP2/7waj3VjFhT0+j/6e
-KeC2uAloGRwYQw==
------END CERTIFICATE-----
-
-# Issuer: CN=AffirmTrust Premium ECC O=AffirmTrust
-# Subject: CN=AffirmTrust Premium ECC O=AffirmTrust
-# Label: "AffirmTrust Premium ECC"
-# Serial: 8401224907861490260
-# MD5 Fingerprint: 64:b0:09:55:cf:b1:d5:99:e2:be:13:ab:a6:5d:ea:4d
-# SHA1 Fingerprint: b8:23:6b:00:2f:1d:16:86:53:01:55:6c:11:a4:37:ca:eb:ff:c3:bb
-# SHA256 Fingerprint: bd:71:fd:f6:da:97:e4:cf:62:d1:64:7a:dd:25:81:b0:7d:79:ad:f8:39:7e:b4:ec:ba:9c:5e:84:88:82:14:23
------BEGIN CERTIFICATE-----
-MIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMC
-VVMxFDASBgNVBAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQ
-cmVtaXVtIEVDQzAeFw0xMDAxMjkxNDIwMjRaFw00MDEyMzExNDIwMjRaMEUxCzAJ
-BgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1UcnVzdDEgMB4GA1UEAwwXQWZmaXJt
-VHJ1c3QgUHJlbWl1bSBFQ0MwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQNMF4bFZ0D
-0KF5Nbc6PJJ6yhUczWLznCZcBz3lVPqj1swS6vQUX+iOGasvLkjmrBhDeKzQN8O9
-ss0s5kfiGuZjuD0uL3jET9v0D6RoTFVya5UdThhClXjMNzyR4ptlKymjQjBAMB0G
-A1UdDgQWBBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTADAQH/MA4G
-A1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/Vs
-aobgxCd05DhT1wV/GzTjxi+zygk8N53X57hG8f2h4nECMEJZh0PUUd+60wkyWs6I
-flc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKMeQ==
------END CERTIFICATE-----
-
-# Issuer: CN=StartCom Certification Authority O=StartCom Ltd. OU=Secure Digital Certificate Signing
-# Subject: CN=StartCom Certification Authority O=StartCom Ltd. OU=Secure Digital Certificate Signing
-# Label: "StartCom Certification Authority"
-# Serial: 45
-# MD5 Fingerprint: c9:3b:0d:84:41:fc:a4:76:79:23:08:57:de:10:19:16
-# SHA1 Fingerprint: a3:f1:33:3f:e2:42:bf:cf:c5:d1:4e:8f:39:42:98:40:68:10:d1:a0
-# SHA256 Fingerprint: e1:78:90:ee:09:a3:fb:f4:f4:8b:9c:41:4a:17:d6:37:b7:a5:06:47:e9:bc:75:23:22:72:7f:cc:17:42:a9:11
------BEGIN CERTIFICATE-----
-MIIHhzCCBW+gAwIBAgIBLTANBgkqhkiG9w0BAQsFADB9MQswCQYDVQQGEwJJTDEW
-MBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwg
-Q2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNh
-dGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0NjM3WhcNMzYwOTE3MTk0NjM2WjB9
-MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMi
-U2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3Rh
-cnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUA
-A4ICDwAwggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZk
-pMyONvg45iPwbm2xPN1yo4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rf
-OQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/C
-Ji/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/deMotHweXMAEtcnn6RtYT
-Kqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt2PZE4XNi
-HzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMM
-Av+Z6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w
-+2OqqGwaVLRcJXrJosmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+
-Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3
-Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVcUjyJthkqcwEKDwOzEmDyei+B
-26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT37uMdBNSSwID
-AQABo4ICEDCCAgwwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD
-VR0OBBYEFE4L7xqkQFulF2mHMMo0aEPQQa7yMB8GA1UdIwQYMBaAFE4L7xqkQFul
-F2mHMMo0aEPQQa7yMIIBWgYDVR0gBIIBUTCCAU0wggFJBgsrBgEEAYG1NwEBATCC
-ATgwLgYIKwYBBQUHAgEWImh0dHA6Ly93d3cuc3RhcnRzc2wuY29tL3BvbGljeS5w
-ZGYwNAYIKwYBBQUHAgEWKGh0dHA6Ly93d3cuc3RhcnRzc2wuY29tL2ludGVybWVk
-aWF0ZS5wZGYwgc8GCCsGAQUFBwICMIHCMCcWIFN0YXJ0IENvbW1lcmNpYWwgKFN0
-YXJ0Q29tKSBMdGQuMAMCAQEagZZMaW1pdGVkIExpYWJpbGl0eSwgcmVhZCB0aGUg
-c2VjdGlvbiAqTGVnYWwgTGltaXRhdGlvbnMqIG9mIHRoZSBTdGFydENvbSBDZXJ0
-aWZpY2F0aW9uIEF1dGhvcml0eSBQb2xpY3kgYXZhaWxhYmxlIGF0IGh0dHA6Ly93
-d3cuc3RhcnRzc2wuY29tL3BvbGljeS5wZGYwEQYJYIZIAYb4QgEBBAQDAgAHMDgG
-CWCGSAGG+EIBDQQrFilTdGFydENvbSBGcmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1
-dGhvcml0eTANBgkqhkiG9w0BAQsFAAOCAgEAjo/n3JR5fPGFf59Jb2vKXfuM/gTF
-wWLRfUKKvFO3lANmMD+x5wqnUCBVJX92ehQN6wQOQOY+2IirByeDqXWmN3PH/UvS
-Ta0XQMhGvjt/UfzDtgUx3M2FIk5xt/JxXrAaxrqTi3iSSoX4eA+D/i+tLPfkpLst
-0OcNOrg+zvZ49q5HJMqjNTbOx8aHmNrs++myziebiMMEofYLWWivydsQD032ZGNc
-pRJvkrKTlMeIFw6Ttn5ii5B/q06f/ON1FE8qMt9bDeD1e5MNq6HPh+GlBEXoPBKl
-CcWw0bdT82AUuoVpaiF8H3VhFyAXe2w7QSlc4axa0c2Mm+tgHRns9+Ww2vl5GKVF
-P0lDV9LdJNUso/2RjSe15esUBppMeyG7Oq0wBhjA2MFrLH9ZXF2RsXAiV+uKa0hK
-1Q8p7MZAwC+ITGgBF3f0JBlPvfrhsiAhS90a2Cl9qrjeVOwhVYBsHvUwyKMQ5bLm
-KhQxw4UtjJixhlpPiVktucf3HMiKf8CdBUrmQk9io20ppB+Fq9vlgcitKj1MXVuE
-JnHEhV5xJMqlG2zYYdMa4FTbzrqpMrUi9nNBCV24F10OD5mQ1kfabwo6YigUZ4LZ
-8dCAWZvLMdibD4x3TrVoivJs9iQOLWxwxXPR3hTQcY+203sC9uO41Alua551hDnm
-fyWl8kgAwKQB2j8=
------END CERTIFICATE-----
-
-# Issuer: CN=StartCom Certification Authority G2 O=StartCom Ltd.
-# Subject: CN=StartCom Certification Authority G2 O=StartCom Ltd.
-# Label: "StartCom Certification Authority G2"
-# Serial: 59
-# MD5 Fingerprint: 78:4b:fb:9e:64:82:0a:d3:b8:4c:62:f3:64:f2:90:64
-# SHA1 Fingerprint: 31:f1:fd:68:22:63:20:ee:c6:3b:3f:9d:ea:4a:3e:53:7c:7c:39:17
-# SHA256 Fingerprint: c7:ba:65:67:de:93:a7:98:ae:1f:aa:79:1e:71:2d:37:8f:ae:1f:93:c4:39:7f:ea:44:1b:b7:cb:e6:fd:59:95
------BEGIN CERTIFICATE-----
-MIIFYzCCA0ugAwIBAgIBOzANBgkqhkiG9w0BAQsFADBTMQswCQYDVQQGEwJJTDEW
-MBQGA1UEChMNU3RhcnRDb20gTHRkLjEsMCoGA1UEAxMjU3RhcnRDb20gQ2VydGlm
-aWNhdGlvbiBBdXRob3JpdHkgRzIwHhcNMTAwMTAxMDEwMDAxWhcNMzkxMjMxMjM1
-OTAxWjBTMQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjEsMCoG
-A1UEAxMjU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgRzIwggIiMA0G
-CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2iTZbB7cgNr2Cu+EWIAOVeq8Oo1XJ
-JZlKxdBWQYeQTSFgpBSHO839sj60ZwNq7eEPS8CRhXBF4EKe3ikj1AENoBB5uNsD
-vfOpL9HG4A/LnooUCri99lZi8cVytjIl2bLzvWXFDSxu1ZJvGIsAQRSCb0AgJnoo
-D/Uefyf3lLE3PbfHkffiAez9lInhzG7TNtYKGXmu1zSCZf98Qru23QumNK9LYP5/
-Q0kGi4xDuFby2X8hQxfqp0iVAXV16iulQ5XqFYSdCI0mblWbq9zSOdIxHWDirMxW
-RST1HFSr7obdljKF+ExP6JV2tgXdNiNnvP8V4so75qbsO+wmETRIjfaAKxojAuuK
-HDp2KntWFhxyKrOq42ClAJ8Em+JvHhRYW6Vsi1g8w7pOOlz34ZYrPu8HvKTlXcxN
-nw3h3Kq74W4a7I/htkxNeXJdFzULHdfBR9qWJODQcqhaX2YtENwvKhOuJv4KHBnM
-0D4LnMgJLvlblnpHnOl68wVQdJVznjAJ85eCXuaPOQgeWeU1FEIT/wCc976qUM/i
-UUjXuG+v+E5+M5iSFGI6dWPPe/regjupuznixL0sAA7IF6wT700ljtizkC+p2il9
-Ha90OrInwMEePnWjFqmveiJdnxMaz6eg6+OGCtP95paV1yPIN93EfKo2rJgaErHg
-TuixO/XWb/Ew1wIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQE
-AwIBBjAdBgNVHQ4EFgQUS8W0QGutHLOlHGVuRjaJhwUMDrYwDQYJKoZIhvcNAQEL
-BQADggIBAHNXPyzVlTJ+N9uWkusZXn5T50HsEbZH77Xe7XRcxfGOSeD8bpkTzZ+K
-2s06Ctg6Wgk/XzTQLwPSZh0avZyQN8gMjgdalEVGKua+etqhqaRpEpKwfTbURIfX
-UfEpY9Z1zRbkJ4kd+MIySP3bmdCPX1R0zKxnNBFi2QwKN4fRoxdIjtIXHfbX/dtl
-6/2o1PXWT6RbdejF0mCy2wl+JYt7ulKSnj7oxXehPOBKc2thz4bcQ///If4jXSRK
-9dNtD2IEBVeC2m6kMyV5Sy5UGYvMLD0w6dEG/+gyRr61M3Z3qAFdlsHB1b6uJcDJ
-HgoJIIihDsnzb02CVAAgp9KP5DlUFy6NHrgbuxu9mk47EDTcnIhT76IxW1hPkWLI
-wpqazRVdOKnWvvgTtZ8SafJQYqz7Fzf07rh1Z2AQ+4NQ+US1dZxAF7L+/XldblhY
-XzD8AK6vM8EOTmy6p6ahfzLbOOCxchcKK5HsamMm7YnUeMx0HgX4a/6ManY5Ka5l
-IxKVCCIcl85bBu4M4ru8H0ST9tg4RQUh7eStqxK2A6RCLi3ECToDZ2mEmuFZkIoo
-hdVddLHRDiBYmxOlsGOm7XtH/UVVMKTumtTm4ofvmMkyghEpIrwACjFeLQ/Ajulr
-so8uBtjRkcfGEvRM/TAXw8HaOFvjqermobp573PYtlNXLfbQ4ddI
------END CERTIFICATE-----
diff --git a/src/php/ext/grpc/completion_queue.h b/src/core/support/cpu_iphone.c
index 6ce1df7c8c..d412a6d7ee 100755..100644
--- a/src/php/ext/grpc/completion_queue.h
+++ b/src/core/support/cpu_iphone.c
@@ -31,32 +31,23 @@
*
*/
-#ifndef NET_GRPC_PHP_GRPC_COMPLETION_QUEUE_H_
-#define NET_GRPC_PHP_GRPC_COMPLETION_QUEUE_H_
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "php.h"
-#include "php_ini.h"
-#include "ext/standard/info.h"
-#include "php_grpc.h"
-
-#include "grpc/grpc.h"
-
-/* Class entry for the PHP CompletionQueue class */
-zend_class_entry *grpc_ce_completion_queue;
-
-/* Wrapper class for grpc_completion_queue that can be associated with a
- PHP object */
-typedef struct wrapped_grpc_completion_queue {
- zend_object std;
-
- grpc_completion_queue *wrapped;
-} wrapped_grpc_completion_queue;
-
-/* Initialize the CompletionQueue class */
-void grpc_init_completion_queue(TSRMLS_D);
-
-#endif /* NET_GRPC_PHP_GRPC_COMPLETION_QUEUE_H_ */
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_CPU_IPHONE
+
+/* Probably 2 instead of 1, but see comment on gpr_cpu_current_cpu. */
+unsigned gpr_cpu_num_cores(void) {
+ return 1;
+}
+
+/* Most code that's using this is using it to shard across work queues. So
+ unless profiling shows it's a problem or there appears a way to detect the
+ currently running CPU core, let's have it shard the default way.
+ Note that the interface in cpu.h lets gpr_cpu_num_cores return 0, but doing
+ it makes it impossible for gpr_cpu_current_cpu to satisfy its stated range,
+ and some code might be relying on it. */
+unsigned gpr_cpu_current_cpu(void) {
+ return 0;
+}
+
+#endif /* GPR_CPU_IPHONE */
diff --git a/src/core/support/cpu_posix.c b/src/core/support/cpu_posix.c
index 5f45fb0bc3..99484e37fb 100644
--- a/src/core/support/cpu_posix.c
+++ b/src/core/support/cpu_posix.c
@@ -74,4 +74,4 @@ unsigned gpr_cpu_current_cpu(void) {
return shard_ptr(&magic_thread_local);
}
-#endif /* GPR_CPU_LINUX */
+#endif /* GPR_CPU_POSIX */
diff --git a/src/core/support/env_win32.c b/src/core/support/env_win32.c
index 177cc36a30..9b4cd698ad 100644
--- a/src/core/support/env_win32.c
+++ b/src/core/support/env_win32.c
@@ -36,6 +36,7 @@
#ifdef GPR_WIN32
#include "src/core/support/env.h"
+#include "src/core/support/string.h"
#include <stdlib.h>
@@ -43,14 +44,16 @@
#include <grpc/support/log.h>
char *gpr_getenv(const char *name) {
- size_t required_size;
+ size_t size;
char *result = NULL;
+ char *duplicated;
+ errno_t err;
- getenv_s(&required_size, NULL, 0, name);
- if (required_size == 0) return NULL;
- result = gpr_malloc(required_size);
- getenv_s(&required_size, result, required_size, name);
- return result;
+ err = _dupenv_s(&result, &size, name);
+ if (err) return NULL;
+ duplicated = gpr_strdup(result);
+ free(result);
+ return duplicated;
}
void gpr_setenv(const char *name, const char *value) {
diff --git a/src/core/support/file_win32.c b/src/core/support/file_win32.c
index fe209af9b2..f59d3af397 100644
--- a/src/core/support/file_win32.c
+++ b/src/core/support/file_win32.c
@@ -72,7 +72,7 @@ FILE *gpr_tmpfile(const char *prefix, char **tmp_filename_out) {
if (_tfopen_s(&result, tmp_filename, TEXT("wb+")) != 0) goto end;
end:
- if (result && tmp_filename) {
+ if (result && tmp_filename_out) {
*tmp_filename_out = gpr_tchar_to_char(tmp_filename);
}
diff --git a/src/core/support/log_win32.c b/src/core/support/log_win32.c
index 720dc141f5..159c7e052c 100644
--- a/src/core/support/log_win32.c
+++ b/src/core/support/log_win32.c
@@ -43,6 +43,7 @@
#include <grpc/support/log.h>
#include <grpc/support/time.h>
+#include "src/core/support/string.h"
#include "src/core/support/string_win32.h"
void gpr_log(const char *file, int line, gpr_log_severity severity,
@@ -55,7 +56,7 @@ void gpr_log(const char *file, int line, gpr_log_severity severity,
va_start(args, format);
ret = _vscprintf(format, args);
va_end(args);
- if (!(0 <= ret && ret < ~(size_t)0)) {
+ if (ret < 0) {
message = NULL;
} else {
/* Allocate a new buffer, with space for the NUL terminator. */
@@ -66,7 +67,7 @@ void gpr_log(const char *file, int line, gpr_log_severity severity,
va_start(args, format);
ret = vsnprintf_s(message, strp_buflen, _TRUNCATE, format, args);
va_end(args);
- if (ret != strp_buflen - 1) {
+ if ((size_t)ret != strp_buflen - 1) {
/* This should never happen. */
gpr_free(message);
message = NULL;
@@ -90,7 +91,7 @@ void gpr_default_log(gpr_log_func_args *args) {
strcpy(time_buffer, "error:strftime");
}
- fprintf(stderr, "%s%s.%09u %5u %s:%d] %s\n",
+ fprintf(stderr, "%s%s.%09u %5lu %s:%d] %s\n",
gpr_log_severity_string(args->severity), time_buffer,
(int)(now.tv_nsec), GetCurrentThreadId(),
args->file, args->line, args->message);
@@ -105,6 +106,7 @@ char *gpr_format_message(DWORD messageid) {
NULL, messageid,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)(&tmessage), 0, NULL);
+ if (status == 0) return gpr_strdup("Unable to retreive error string");
message = gpr_tchar_to_char(tmessage);
LocalFree(tmessage);
return message;
diff --git a/src/core/support/slice_buffer.c b/src/core/support/slice_buffer.c
index 6cd51f925c..b280e4bd02 100644
--- a/src/core/support/slice_buffer.c
+++ b/src/core/support/slice_buffer.c
@@ -143,6 +143,13 @@ void gpr_slice_buffer_addn(gpr_slice_buffer *sb, gpr_slice *s, size_t n) {
}
}
+void gpr_slice_buffer_pop(gpr_slice_buffer *sb) {
+ if (sb->count != 0) {
+ size_t count = --sb->count;
+ sb->length -= GPR_SLICE_LENGTH(sb->slices[count]);
+ }
+}
+
void gpr_slice_buffer_reset_and_unref(gpr_slice_buffer *sb) {
size_t i;
diff --git a/src/core/support/string_win32.c b/src/core/support/string_win32.c
index 583abd27d8..6d1d6337a9 100644
--- a/src/core/support/string_win32.c
+++ b/src/core/support/string_win32.c
@@ -44,6 +44,8 @@
#include <grpc/support/alloc.h>
+#include "src/core/support/string.h"
+
int gpr_asprintf(char **strp, const char *format, ...) {
va_list args;
int ret;
@@ -53,7 +55,7 @@ int gpr_asprintf(char **strp, const char *format, ...) {
va_start(args, format);
ret = _vscprintf(format, args);
va_end(args);
- if (!(0 <= ret && ret < ~(size_t)0)) {
+ if (ret < 0) {
*strp = NULL;
return -1;
}
@@ -69,7 +71,7 @@ int gpr_asprintf(char **strp, const char *format, ...) {
va_start(args, format);
ret = vsnprintf_s(*strp, strp_buflen, _TRUNCATE, format, args);
va_end(args);
- if (ret == strp_buflen - 1) {
+ if ((size_t)ret == strp_buflen - 1) {
return ret;
}
diff --git a/src/core/support/sync_win32.c b/src/core/support/sync_win32.c
index c9a977cc80..cc31d9b052 100644
--- a/src/core/support/sync_win32.c
+++ b/src/core/support/sync_win32.c
@@ -37,6 +37,7 @@
#ifdef GPR_WIN32
+#undef _WIN32_WINNT
#define _WIN32_WINNT 0x0600
#include <windows.h>
#include <grpc/support/log.h>
diff --git a/src/core/support/time_win32.c b/src/core/support/time_win32.c
index 8256849655..f221cb5790 100644
--- a/src/core/support/time_win32.c
+++ b/src/core/support/time_win32.c
@@ -42,8 +42,8 @@
gpr_timespec gpr_now(void) {
gpr_timespec now_tv;
- struct __timeb32 now_tb;
- _ftime32_s(&now_tb);
+ struct _timeb now_tb;
+ _ftime_s(&now_tb);
now_tv.tv_sec = now_tb.time;
now_tv.tv_nsec = now_tb.millitm * 1000000;
return now_tv;
diff --git a/src/core/transport/chttp2_transport.c b/src/core/transport/chttp2_transport.c
index 0d01a37112..2b15b2a812 100644
--- a/src/core/transport/chttp2_transport.c
+++ b/src/core/transport/chttp2_transport.c
@@ -1655,7 +1655,15 @@ static int process_read(transport *t, gpr_slice slice) {
if (!init_frame_parser(t)) {
return 0;
}
- t->last_incoming_stream_id = t->incoming_stream_id;
+ /* t->last_incoming_stream_id is used as last-stream-id when
+ sending GOAWAY frame.
+ https://tools.ietf.org/html/draft-ietf-httpbis-http2-17#section-6.8
+ says that last-stream-id is peer-initiated stream ID. So,
+ since we don't have server pushed streams, client should send
+ GOAWAY last-stream-id=0 in this case. */
+ if (!t->is_client) {
+ t->last_incoming_stream_id = t->incoming_stream_id;
+ }
if (t->incoming_frame_size == 0) {
if (!parse_frame_slice(t, gpr_empty_slice(), 1)) {
return 0;
diff --git a/src/core/tsi/ssl_transport_security.c b/src/core/tsi/ssl_transport_security.c
index 33645ca8b8..018ddc4456 100644
--- a/src/core/tsi/ssl_transport_security.c
+++ b/src/core/tsi/ssl_transport_security.c
@@ -567,7 +567,8 @@ static tsi_result populate_ssl_context(
EC_KEY* ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
if (!SSL_CTX_set_tmp_ecdh(context, ecdh)) {
gpr_log(GPR_ERROR, "Could not set ephemeral ECDH key.");
- result = TSI_INTERNAL_ERROR;
+ EC_KEY_free(ecdh);
+ return TSI_INTERNAL_ERROR;
}
SSL_CTX_set_options(context, SSL_OP_SINGLE_ECDH_USE);
EC_KEY_free(ecdh);
@@ -604,6 +605,7 @@ static tsi_result build_alpn_protocol_name_list(
unsigned char* current;
*protocol_name_list = NULL;
*protocol_name_list_length = 0;
+ if (num_alpn_protocols == 0) return TSI_INVALID_ARGUMENT;
for (i = 0; i < num_alpn_protocols; i++) {
if (alpn_protocols_lengths[i] == 0) {
gpr_log(GPR_ERROR, "Invalid 0-length protocol name.");
diff --git a/src/cpp/client/channel.h b/src/cpp/client/channel.h
index a1de3817e6..3980eba237 100644
--- a/src/cpp/client/channel.h
+++ b/src/cpp/client/channel.h
@@ -51,16 +51,16 @@ class StreamContextInterface;
class Channel GRPC_FINAL : public ChannelInterface {
public:
- Channel(const grpc::string &target, grpc_channel *c_channel);
+ Channel(const grpc::string& target, grpc_channel* c_channel);
~Channel() GRPC_OVERRIDE;
- virtual Call CreateCall(const RpcMethod &method, ClientContext *context,
- CompletionQueue *cq) GRPC_OVERRIDE;
- virtual void PerformOpsOnCall(CallOpBuffer *ops, Call *call) GRPC_OVERRIDE;
+ virtual Call CreateCall(const RpcMethod& method, ClientContext* context,
+ CompletionQueue* cq) GRPC_OVERRIDE;
+ virtual void PerformOpsOnCall(CallOpBuffer* ops, Call* call) GRPC_OVERRIDE;
private:
const grpc::string target_;
- grpc_channel *const c_channel_; // owned
+ grpc_channel* const c_channel_; // owned
};
} // namespace grpc
diff --git a/src/cpp/client/channel_arguments.cc b/src/cpp/client/channel_arguments.cc
index abf0fc1c0a..87f8349eef 100644
--- a/src/cpp/client/channel_arguments.cc
+++ b/src/cpp/client/channel_arguments.cc
@@ -37,7 +37,7 @@
namespace grpc {
-void ChannelArguments::SetSslTargetNameOverride(const grpc::string &name) {
+void ChannelArguments::SetSslTargetNameOverride(const grpc::string& name) {
SetString(GRPC_SSL_TARGET_NAME_OVERRIDE_ARG, name);
}
@@ -50,32 +50,32 @@ grpc::string ChannelArguments::GetSslTargetNameOverride() const {
return "";
}
-void ChannelArguments::SetInt(const grpc::string &key, int value) {
+void ChannelArguments::SetInt(const grpc::string& key, int value) {
grpc_arg arg;
arg.type = GRPC_ARG_INTEGER;
strings_.push_back(key);
- arg.key = const_cast<char *>(strings_.back().c_str());
+ arg.key = const_cast<char*>(strings_.back().c_str());
arg.value.integer = value;
args_.push_back(arg);
}
-void ChannelArguments::SetString(const grpc::string &key,
- const grpc::string &value) {
+void ChannelArguments::SetString(const grpc::string& key,
+ const grpc::string& value) {
grpc_arg arg;
arg.type = GRPC_ARG_STRING;
strings_.push_back(key);
- arg.key = const_cast<char *>(strings_.back().c_str());
+ arg.key = const_cast<char*>(strings_.back().c_str());
strings_.push_back(value);
- arg.value.string = const_cast<char *>(strings_.back().c_str());
+ arg.value.string = const_cast<char*>(strings_.back().c_str());
args_.push_back(arg);
}
-void ChannelArguments::SetChannelArgs(grpc_channel_args *channel_args) const {
+void ChannelArguments::SetChannelArgs(grpc_channel_args* channel_args) const {
channel_args->num_args = args_.size();
if (channel_args->num_args > 0) {
- channel_args->args = const_cast<grpc_arg *>(&args_[0]);
+ channel_args->args = const_cast<grpc_arg*>(&args_[0]);
}
}
diff --git a/src/cpp/client/client_context.cc b/src/cpp/client/client_context.cc
index 9f99f7bcd5..de9f8c7201 100644
--- a/src/cpp/client/client_context.cc
+++ b/src/cpp/client/client_context.cc
@@ -53,7 +53,7 @@ ClientContext::~ClientContext() {
if (cq_) {
grpc_completion_queue_shutdown(cq_);
// Drain cq_.
- grpc_event *ev;
+ grpc_event* ev;
grpc_completion_type t;
do {
ev = grpc_completion_queue_next(cq_, gpr_inf_future);
@@ -65,7 +65,7 @@ ClientContext::~ClientContext() {
}
void ClientContext::set_absolute_deadline(
- const system_clock::time_point &deadline) {
+ const system_clock::time_point& deadline) {
Timepoint2Timespec(deadline, &absolute_deadline_);
}
@@ -73,8 +73,8 @@ system_clock::time_point ClientContext::absolute_deadline() {
return Timespec2Timepoint(absolute_deadline_);
}
-void ClientContext::AddMetadata(const grpc::string &meta_key,
- const grpc::string &meta_value) {
+void ClientContext::AddMetadata(const grpc::string& meta_key,
+ const grpc::string& meta_value) {
send_initial_metadata_.insert(std::make_pair(meta_key, meta_value));
}
diff --git a/src/cpp/client/client_unary_call.cc b/src/cpp/client/client_unary_call.cc
index 5c179de9d8..7e7ea78bcd 100644
--- a/src/cpp/client/client_unary_call.cc
+++ b/src/cpp/client/client_unary_call.cc
@@ -42,10 +42,10 @@
namespace grpc {
// Wrapper that performs a blocking unary call
-Status BlockingUnaryCall(ChannelInterface *channel, const RpcMethod &method,
- ClientContext *context,
- const grpc::protobuf::Message &request,
- grpc::protobuf::Message *result) {
+Status BlockingUnaryCall(ChannelInterface* channel, const RpcMethod& method,
+ ClientContext* context,
+ const grpc::protobuf::Message& request,
+ grpc::protobuf::Message* result) {
CompletionQueue cq;
Call call(channel->CreateCall(method, context, &cq));
CallOpBuffer buf;
diff --git a/src/cpp/client/create_channel.cc b/src/cpp/client/create_channel.cc
index 57d215d0f3..301430572a 100644
--- a/src/cpp/client/create_channel.cc
+++ b/src/cpp/client/create_channel.cc
@@ -41,9 +41,10 @@ namespace grpc {
class ChannelArguments;
std::shared_ptr<ChannelInterface> CreateChannel(
- const grpc::string &target, const std::unique_ptr<Credentials> &creds,
- const ChannelArguments &args) {
- return creds ? creds->CreateChannel(target, args) :
- std::shared_ptr<ChannelInterface>(new Channel(target, grpc_lame_client_channel_create()));
+ const grpc::string& target, const std::unique_ptr<Credentials>& creds,
+ const ChannelArguments& args) {
+ return creds ? creds->CreateChannel(target, args)
+ : std::shared_ptr<ChannelInterface>(
+ new Channel(target, grpc_lame_client_channel_create()));
}
} // namespace grpc
diff --git a/src/cpp/client/insecure_credentials.cc b/src/cpp/client/insecure_credentials.cc
index 2dcfe69591..8945b038de 100644
--- a/src/cpp/client/insecure_credentials.cc
+++ b/src/cpp/client/insecure_credentials.cc
@@ -31,8 +31,6 @@
*
*/
-#include <string>
-
#include <grpc/grpc.h>
#include <grpc/support/log.h>
@@ -54,7 +52,7 @@ class InsecureCredentialsImpl GRPC_FINAL : public Credentials {
target, grpc_channel_create(target.c_str(), &channel_args)));
}
- SecureCredentials* AsSecureCredentials() { return nullptr; }
+ SecureCredentials* AsSecureCredentials() GRPC_OVERRIDE { return nullptr; }
};
} // namespace
diff --git a/src/cpp/client/secure_credentials.cc b/src/cpp/client/secure_credentials.cc
index 5eb5c54794..d6f9acc675 100644
--- a/src/cpp/client/secure_credentials.cc
+++ b/src/cpp/client/secure_credentials.cc
@@ -31,8 +31,6 @@
*
*/
-#include <string>
-
#include <grpc/grpc_security.h>
#include <grpc/support/log.h>
@@ -54,11 +52,13 @@ class SecureCredentials GRPC_FINAL : public Credentials {
grpc_channel_args channel_args;
args.SetChannelArgs(&channel_args);
return std::shared_ptr<ChannelInterface>(new Channel(
- target,
+ args.GetSslTargetNameOverride().empty()
+ ? target
+ : args.GetSslTargetNameOverride(),
grpc_secure_channel_create(c_creds_, target.c_str(), &channel_args)));
}
- SecureCredentials* AsSecureCredentials() { return this; }
+ SecureCredentials* AsSecureCredentials() GRPC_OVERRIDE { return this; }
private:
grpc_credentials* const c_creds_;
@@ -97,12 +97,37 @@ std::unique_ptr<Credentials> ComputeEngineCredentials() {
std::unique_ptr<Credentials> ServiceAccountCredentials(
const grpc::string& json_key, const grpc::string& scope,
std::chrono::seconds token_lifetime) {
- gpr_timespec lifetime = gpr_time_from_seconds(
- token_lifetime.count() > 0 ? token_lifetime.count() : 0);
+ if (token_lifetime.count() <= 0) {
+ gpr_log(GPR_ERROR,
+ "Trying to create ServiceAccountCredentials "
+ "with non-positive lifetime");
+ return WrapCredentials(nullptr);
+ }
+ gpr_timespec lifetime = gpr_time_from_seconds(token_lifetime.count());
return WrapCredentials(grpc_service_account_credentials_create(
json_key.c_str(), scope.c_str(), lifetime));
}
+// Builds JWT credentials.
+std::unique_ptr<Credentials> JWTCredentials(
+ const grpc::string& json_key, std::chrono::seconds token_lifetime) {
+ if (token_lifetime.count() <= 0) {
+ gpr_log(GPR_ERROR,
+ "Trying to create JWTCredentials with non-positive lifetime");
+ return WrapCredentials(nullptr);
+ }
+ gpr_timespec lifetime = gpr_time_from_seconds(token_lifetime.count());
+ return WrapCredentials(
+ grpc_jwt_credentials_create(json_key.c_str(), lifetime));
+}
+
+// Builds refresh token credentials.
+std::unique_ptr<Credentials> RefreshTokenCredentials(
+ const grpc::string& json_refresh_token) {
+ return WrapCredentials(
+ grpc_refresh_token_credentials_create(json_refresh_token.c_str()));
+}
+
// Builds IAM credentials.
std::unique_ptr<Credentials> IAMCredentials(
const grpc::string& authorization_token,
diff --git a/src/cpp/common/call.cc b/src/cpp/common/call.cc
index 6ce1e8a7d5..311e0d01b0 100644
--- a/src/cpp/common/call.cc
+++ b/src/cpp/common/call.cc
@@ -31,8 +31,10 @@
*
*/
-#include <grpc/support/alloc.h>
#include <grpc++/impl/call.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc++/byte_buffer.h>
#include <grpc++/client_context.h>
#include <grpc++/channel_interface.h>
@@ -46,15 +48,15 @@ CallOpBuffer::CallOpBuffer()
initial_metadata_count_(0),
initial_metadata_(nullptr),
recv_initial_metadata_(nullptr),
- recv_initial_metadata_arr_{0, 0, nullptr},
send_message_(nullptr),
- send_message_buf_(nullptr),
+ send_message_buffer_(nullptr),
+ send_buf_(nullptr),
recv_message_(nullptr),
- recv_message_buf_(nullptr),
+ recv_message_buffer_(nullptr),
+ recv_buf_(nullptr),
client_send_close_(false),
recv_trailing_metadata_(nullptr),
recv_status_(nullptr),
- recv_trailing_metadata_arr_{0, 0, nullptr},
status_code_(GRPC_STATUS_OK),
status_details_(nullptr),
status_details_capacity_(0),
@@ -62,7 +64,12 @@ CallOpBuffer::CallOpBuffer()
trailing_metadata_count_(0),
trailing_metadata_(nullptr),
cancelled_buf_(0),
- recv_closed_(nullptr) {}
+ recv_closed_(nullptr) {
+ memset(&recv_trailing_metadata_arr_, 0, sizeof(recv_trailing_metadata_arr_));
+ memset(&recv_initial_metadata_arr_, 0, sizeof(recv_initial_metadata_arr_));
+ recv_trailing_metadata_arr_.metadata = nullptr;
+ recv_initial_metadata_arr_.metadata = nullptr;
+}
void CallOpBuffer::Reset(void* next_return_tag) {
return_tag_ = next_return_tag;
@@ -74,18 +81,20 @@ void CallOpBuffer::Reset(void* next_return_tag) {
recv_initial_metadata_ = nullptr;
recv_initial_metadata_arr_.count = 0;
- send_message_ = nullptr;
- if (send_message_buf_) {
- grpc_byte_buffer_destroy(send_message_buf_);
- send_message_buf_ = nullptr;
+ if (send_buf_ && send_message_) {
+ grpc_byte_buffer_destroy(send_buf_);
}
+ send_message_ = nullptr;
+ send_message_buffer_ = nullptr;
+ send_buf_ = nullptr;
- recv_message_ = nullptr;
got_message = false;
- if (recv_message_buf_) {
- grpc_byte_buffer_destroy(recv_message_buf_);
- recv_message_buf_ = nullptr;
+ if (recv_buf_ && recv_message_) {
+ grpc_byte_buffer_destroy(recv_buf_);
}
+ recv_message_ = nullptr;
+ recv_message_buffer_ = nullptr;
+ recv_buf_ = nullptr;
client_send_close_ = false;
@@ -106,11 +115,11 @@ CallOpBuffer::~CallOpBuffer() {
gpr_free(status_details_);
gpr_free(recv_initial_metadata_arr_.metadata);
gpr_free(recv_trailing_metadata_arr_.metadata);
- if (recv_message_buf_) {
- grpc_byte_buffer_destroy(recv_message_buf_);
+ if (recv_buf_ && recv_message_) {
+ grpc_byte_buffer_destroy(recv_buf_);
}
- if (send_message_buf_) {
- grpc_byte_buffer_destroy(send_message_buf_);
+ if (send_buf_ && send_message_) {
+ grpc_byte_buffer_destroy(send_buf_);
}
}
@@ -139,7 +148,7 @@ void FillMetadataMap(grpc_metadata_array* arr,
// TODO(yangg) handle duplicates?
metadata->insert(std::pair<grpc::string, grpc::string>(
arr->metadata[i].key,
- {arr->metadata[i].value, arr->metadata[i].value_length}));
+ grpc::string(arr->metadata[i].value, arr->metadata[i].value_length)));
}
grpc_metadata_array_destroy(arr);
grpc_metadata_array_init(arr);
@@ -166,11 +175,19 @@ void CallOpBuffer::AddSendMessage(const grpc::protobuf::Message& message) {
send_message_ = &message;
}
+void CallOpBuffer::AddSendMessage(const ByteBuffer& message) {
+ send_message_buffer_ = &message;
+}
+
void CallOpBuffer::AddRecvMessage(grpc::protobuf::Message* message) {
recv_message_ = message;
recv_message_->Clear();
}
+void CallOpBuffer::AddRecvMessage(ByteBuffer* message) {
+ recv_message_buffer_ = message;
+}
+
void CallOpBuffer::AddClientSendClose() { client_send_close_ = true; }
void CallOpBuffer::AddServerRecvClose(bool* cancelled) {
@@ -206,19 +223,23 @@ void CallOpBuffer::FillOps(grpc_op* ops, size_t* nops) {
ops[*nops].data.recv_initial_metadata = &recv_initial_metadata_arr_;
(*nops)++;
}
- if (send_message_) {
- bool success = SerializeProto(*send_message_, &send_message_buf_);
- if (!success) {
- abort();
- // TODO handle parse failure
+ if (send_message_ || send_message_buffer_) {
+ if (send_message_) {
+ bool success = SerializeProto(*send_message_, &send_buf_);
+ if (!success) {
+ abort();
+ // TODO handle parse failure
+ }
+ } else {
+ send_buf_ = send_message_buffer_->buffer();
}
ops[*nops].op = GRPC_OP_SEND_MESSAGE;
- ops[*nops].data.send_message = send_message_buf_;
+ ops[*nops].data.send_message = send_buf_;
(*nops)++;
}
- if (recv_message_) {
+ if (recv_message_ || recv_message_buffer_) {
ops[*nops].op = GRPC_OP_RECV_MESSAGE;
- ops[*nops].data.recv_message = &recv_message_buf_;
+ ops[*nops].data.recv_message = &recv_buf_;
(*nops)++;
}
if (client_send_close_) {
@@ -256,9 +277,11 @@ void CallOpBuffer::FillOps(grpc_op* ops, size_t* nops) {
bool CallOpBuffer::FinalizeResult(void** tag, bool* status) {
// Release send buffers.
- if (send_message_buf_) {
- grpc_byte_buffer_destroy(send_message_buf_);
- send_message_buf_ = nullptr;
+ if (send_buf_ && send_message_) {
+ if (send_message_) {
+ grpc_byte_buffer_destroy(send_buf_);
+ }
+ send_buf_ = nullptr;
}
if (initial_metadata_) {
gpr_free(initial_metadata_);
@@ -275,12 +298,16 @@ bool CallOpBuffer::FinalizeResult(void** tag, bool* status) {
FillMetadataMap(&recv_initial_metadata_arr_, recv_initial_metadata_);
}
// Parse received message if any.
- if (recv_message_) {
- if (recv_message_buf_) {
+ if (recv_message_ || recv_message_buffer_) {
+ if (recv_buf_) {
got_message = *status;
- *status = *status && DeserializeProto(recv_message_buf_, recv_message_);
- grpc_byte_buffer_destroy(recv_message_buf_);
- recv_message_buf_ = nullptr;
+ if (recv_message_) {
+ *status = *status && DeserializeProto(recv_buf_, recv_message_);
+ grpc_byte_buffer_destroy(recv_buf_);
+ } else {
+ recv_message_buffer_->set_buffer(recv_buf_);
+ }
+ recv_buf_ = nullptr;
} else {
// Read failed
got_message = false;
diff --git a/src/cpp/common/completion_queue.cc b/src/cpp/common/completion_queue.cc
index 414966c1cd..cea2d24831 100644
--- a/src/cpp/common/completion_queue.cc
+++ b/src/cpp/common/completion_queue.cc
@@ -36,7 +36,6 @@
#include <grpc/grpc.h>
#include <grpc/support/log.h>
-#include <grpc/support/time.h>
#include "src/cpp/util/time.h"
namespace grpc {
@@ -57,23 +56,34 @@ class EventDeleter {
}
};
-bool CompletionQueue::Next(void** tag, bool* ok) {
+CompletionQueue::NextStatus CompletionQueue::AsyncNextInternal(
+ void** tag, bool* ok, gpr_timespec deadline) {
std::unique_ptr<grpc_event, EventDeleter> ev;
for (;;) {
- ev.reset(grpc_completion_queue_next(cq_, gpr_inf_future));
+ ev.reset(grpc_completion_queue_next(cq_, deadline));
+ if (!ev) { /* got a NULL back because deadline passed */
+ return TIMEOUT;
+ }
if (ev->type == GRPC_QUEUE_SHUTDOWN) {
- return false;
+ return SHUTDOWN;
}
auto cq_tag = static_cast<CompletionQueueTag*>(ev->tag);
*ok = ev->data.op_complete == GRPC_OP_OK;
*tag = cq_tag;
if (cq_tag->FinalizeResult(tag, ok)) {
- return true;
+ return GOT_EVENT;
}
}
}
+CompletionQueue::NextStatus CompletionQueue::AsyncNext(
+ void** tag, bool* ok, std::chrono::system_clock::time_point deadline) {
+ gpr_timespec gpr_deadline;
+ Timepoint2Timespec(deadline, &gpr_deadline);
+ return AsyncNextInternal(tag, ok, gpr_deadline);
+}
+
bool CompletionQueue::Pluck(CompletionQueueTag* tag) {
std::unique_ptr<grpc_event, EventDeleter> ev;
diff --git a/src/cpp/proto/proto_utils.cc b/src/cpp/proto/proto_utils.cc
index 72f1bf7441..b8de2ea173 100644
--- a/src/cpp/proto/proto_utils.cc
+++ b/src/cpp/proto/proto_utils.cc
@@ -35,38 +35,132 @@
#include <grpc++/config.h>
#include <grpc/grpc.h>
+#include <grpc/byte_buffer.h>
#include <grpc/support/slice.h>
+#include <grpc/support/slice_buffer.h>
+#include <grpc/support/port_platform.h>
-namespace grpc {
+const int kMaxBufferLength = 8192;
-bool SerializeProto(const grpc::protobuf::Message &msg,
- grpc_byte_buffer **bp) {
- grpc::string msg_str;
- bool success = msg.SerializeToString(&msg_str);
- if (success) {
- gpr_slice slice =
- gpr_slice_from_copied_buffer(msg_str.data(), msg_str.length());
- *bp = grpc_byte_buffer_create(&slice, 1);
- gpr_slice_unref(slice);
+class GrpcBufferWriter GRPC_FINAL
+ : public ::grpc::protobuf::io::ZeroCopyOutputStream {
+ public:
+ explicit GrpcBufferWriter(grpc_byte_buffer** bp,
+ int block_size = kMaxBufferLength)
+ : block_size_(block_size), byte_count_(0), have_backup_(false) {
+ *bp = grpc_byte_buffer_create(NULL, 0);
+ slice_buffer_ = &(*bp)->data.slice_buffer;
+ }
+
+ ~GrpcBufferWriter() GRPC_OVERRIDE {
+ if (have_backup_) {
+ gpr_slice_unref(backup_slice_);
+ }
+ }
+
+ bool Next(void** data, int* size) GRPC_OVERRIDE {
+ if (have_backup_) {
+ slice_ = backup_slice_;
+ have_backup_ = false;
+ } else {
+ slice_ = gpr_slice_malloc(block_size_);
+ }
+ *data = GPR_SLICE_START_PTR(slice_);
+ byte_count_ += *size = GPR_SLICE_LENGTH(slice_);
+ gpr_slice_buffer_add(slice_buffer_, slice_);
+ return true;
+ }
+
+ void BackUp(int count) GRPC_OVERRIDE {
+ gpr_slice_buffer_pop(slice_buffer_);
+ if (count == block_size_) {
+ backup_slice_ = slice_;
+ } else {
+ backup_slice_ =
+ gpr_slice_split_tail(&slice_, GPR_SLICE_LENGTH(slice_) - count);
+ gpr_slice_buffer_add(slice_buffer_, slice_);
+ }
+ have_backup_ = true;
+ byte_count_ -= count;
+ }
+
+ grpc::protobuf::int64 ByteCount() const GRPC_OVERRIDE { return byte_count_; }
+
+ private:
+ const int block_size_;
+ gpr_int64 byte_count_;
+ gpr_slice_buffer* slice_buffer_;
+ bool have_backup_;
+ gpr_slice backup_slice_;
+ gpr_slice slice_;
+};
+
+class GrpcBufferReader GRPC_FINAL
+ : public ::grpc::protobuf::io::ZeroCopyInputStream {
+ public:
+ explicit GrpcBufferReader(grpc_byte_buffer* buffer)
+ : byte_count_(0), backup_count_(0) {
+ reader_ = grpc_byte_buffer_reader_create(buffer);
+ }
+ ~GrpcBufferReader() GRPC_OVERRIDE {
+ grpc_byte_buffer_reader_destroy(reader_);
+ }
+
+ bool Next(const void** data, int* size) GRPC_OVERRIDE {
+ if (backup_count_ > 0) {
+ *data = GPR_SLICE_START_PTR(slice_) + GPR_SLICE_LENGTH(slice_) -
+ backup_count_;
+ *size = backup_count_;
+ backup_count_ = 0;
+ return true;
+ }
+ if (!grpc_byte_buffer_reader_next(reader_, &slice_)) {
+ return false;
+ }
+ gpr_slice_unref(slice_);
+ *data = GPR_SLICE_START_PTR(slice_);
+ byte_count_ += *size = GPR_SLICE_LENGTH(slice_);
+ return true;
+ }
+
+ void BackUp(int count) GRPC_OVERRIDE { backup_count_ = count; }
+
+ bool Skip(int count) GRPC_OVERRIDE {
+ const void* data;
+ int size;
+ while (Next(&data, &size)) {
+ if (size >= count) {
+ BackUp(size - count);
+ return true;
+ }
+ // size < count;
+ count -= size;
+ }
+ // error or we have too large count;
+ return false;
}
- return success;
-}
-bool DeserializeProto(grpc_byte_buffer *buffer,
- grpc::protobuf::Message *msg) {
- grpc::string msg_string;
- grpc_byte_buffer_reader *reader = grpc_byte_buffer_reader_create(buffer);
- gpr_slice slice;
- while (grpc_byte_buffer_reader_next(reader, &slice)) {
- const char *data = reinterpret_cast<const char *>(
- slice.refcount ? slice.data.refcounted.bytes
- : slice.data.inlined.bytes);
- msg_string.append(data, slice.refcount ? slice.data.refcounted.length
- : slice.data.inlined.length);
- gpr_slice_unref(slice);
+ grpc::protobuf::int64 ByteCount() const GRPC_OVERRIDE {
+ return byte_count_ - backup_count_;
}
- grpc_byte_buffer_reader_destroy(reader);
- return msg->ParseFromString(msg_string);
+
+ private:
+ gpr_int64 byte_count_;
+ gpr_int64 backup_count_;
+ grpc_byte_buffer_reader* reader_;
+ gpr_slice slice_;
+};
+
+namespace grpc {
+
+bool SerializeProto(const grpc::protobuf::Message& msg, grpc_byte_buffer** bp) {
+ GrpcBufferWriter writer(bp);
+ return msg.SerializeToZeroCopyStream(&writer);
+}
+
+bool DeserializeProto(grpc_byte_buffer* buffer, grpc::protobuf::Message* msg) {
+ GrpcBufferReader reader(buffer);
+ return msg->ParseFromZeroCopyStream(&reader);
}
} // namespace grpc
diff --git a/src/cpp/proto/proto_utils.h b/src/cpp/proto/proto_utils.h
index 7a1b1f8b7c..bc60dc9929 100644
--- a/src/cpp/proto/proto_utils.h
+++ b/src/cpp/proto/proto_utils.h
@@ -43,11 +43,11 @@ namespace grpc {
// Serialize the msg into a buffer created inside the function. The caller
// should destroy the returned buffer when done with it. If serialization fails,
// false is returned and buffer is left unchanged.
-bool SerializeProto(const grpc::protobuf::Message &msg,
- grpc_byte_buffer **buffer);
+bool SerializeProto(const grpc::protobuf::Message& msg,
+ grpc_byte_buffer** buffer);
// The caller keeps ownership of buffer and msg.
-bool DeserializeProto(grpc_byte_buffer *buffer, grpc::protobuf::Message *msg);
+bool DeserializeProto(grpc_byte_buffer* buffer, grpc::protobuf::Message* msg);
} // namespace grpc
diff --git a/src/php/tests/unit_tests/CompletionQueueTest.php b/src/cpp/server/async_generic_service.cc
index 76ee61dfe8..07cb933715 100755..100644
--- a/src/php/tests/unit_tests/CompletionQueueTest.php
+++ b/src/cpp/server/async_generic_service.cc
@@ -1,4 +1,3 @@
-<?php
/*
*
* Copyright 2015, Google Inc.
@@ -31,16 +30,21 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
-class CompletionQueueTest extends PHPUnit_Framework_TestCase{
- public function testNextReturnsNullWithNoCall() {
- $cq = new Grpc\CompletionQueue();
- $event = $cq->next(Grpc\Timeval::zero());
- $this->assertNull($event);
- }
- public function testPluckReturnsNullWithNoCall() {
- $cq = new Grpc\CompletionQueue();
- $event = $cq->pluck(0, Grpc\Timeval::zero());
- $this->assertNull($event);
- }
+#include <grpc++/async_generic_service.h>
+
+#include <grpc++/server.h>
+
+namespace grpc {
+
+void AsyncGenericService::RequestCall(
+ GenericServerContext* ctx, GenericServerAsyncReaderWriter* reader_writer,
+ CompletionQueue* cq, void* tag) {
+ server_->RequestAsyncGenericCall(ctx, reader_writer, cq, tag);
}
+
+CompletionQueue* AsyncGenericService::completion_queue() {
+ return &server_->cq_;
+}
+
+} // namespace grpc
diff --git a/src/cpp/server/async_server_context.cc b/src/cpp/server/async_server_context.cc
index f21efcfb19..628822a338 100644
--- a/src/cpp/server/async_server_context.cc
+++ b/src/cpp/server/async_server_context.cc
@@ -42,7 +42,7 @@
namespace grpc {
AsyncServerContext::AsyncServerContext(
- grpc_call *call, const grpc::string &method, const grpc::string &host,
+ grpc_call* call, const grpc::string& method, const grpc::string& host,
system_clock::time_point absolute_deadline)
: method_(method),
host_(host),
@@ -52,22 +52,22 @@ AsyncServerContext::AsyncServerContext(
AsyncServerContext::~AsyncServerContext() { grpc_call_destroy(call_); }
-void AsyncServerContext::Accept(grpc_completion_queue *cq) {
+void AsyncServerContext::Accept(grpc_completion_queue* cq) {
GPR_ASSERT(grpc_call_server_accept_old(call_, cq, this) == GRPC_CALL_OK);
GPR_ASSERT(grpc_call_server_end_initial_metadata_old(
call_, GRPC_WRITE_BUFFER_HINT) == GRPC_CALL_OK);
}
-bool AsyncServerContext::StartRead(grpc::protobuf::Message *request) {
+bool AsyncServerContext::StartRead(grpc::protobuf::Message* request) {
GPR_ASSERT(request);
request_ = request;
grpc_call_error err = grpc_call_start_read_old(call_, this);
return err == GRPC_CALL_OK;
}
-bool AsyncServerContext::StartWrite(const grpc::protobuf::Message &response,
+bool AsyncServerContext::StartWrite(const grpc::protobuf::Message& response,
int flags) {
- grpc_byte_buffer *buffer = nullptr;
+ grpc_byte_buffer* buffer = nullptr;
if (!SerializeProto(response, &buffer)) {
return false;
}
@@ -76,16 +76,16 @@ bool AsyncServerContext::StartWrite(const grpc::protobuf::Message &response,
return err == GRPC_CALL_OK;
}
-bool AsyncServerContext::StartWriteStatus(const Status &status) {
+bool AsyncServerContext::StartWriteStatus(const Status& status) {
grpc_call_error err = grpc_call_start_write_status_old(
call_, static_cast<grpc_status_code>(status.code()),
status.details().empty() ? nullptr
- : const_cast<char *>(status.details().c_str()),
+ : const_cast<char*>(status.details().c_str()),
this);
return err == GRPC_CALL_OK;
}
-bool AsyncServerContext::ParseRead(grpc_byte_buffer *read_buffer) {
+bool AsyncServerContext::ParseRead(grpc_byte_buffer* read_buffer) {
GPR_ASSERT(request_);
bool success = DeserializeProto(read_buffer, request_);
request_ = nullptr;
diff --git a/src/cpp/server/insecure_server_credentials.cc b/src/cpp/server/insecure_server_credentials.cc
index f5e4732f73..55dd90d7a7 100644
--- a/src/cpp/server/insecure_server_credentials.cc
+++ b/src/cpp/server/insecure_server_credentials.cc
@@ -46,7 +46,8 @@ class InsecureServerCredentialsImpl GRPC_FINAL : public ServerCredentials {
} // namespace
std::shared_ptr<ServerCredentials> InsecureServerCredentials() {
- return std::shared_ptr<ServerCredentials>(new InsecureServerCredentialsImpl());
+ return std::shared_ptr<ServerCredentials>(
+ new InsecureServerCredentialsImpl());
}
} // namespace grpc
diff --git a/src/cpp/server/secure_server_credentials.cc b/src/cpp/server/secure_server_credentials.cc
index ff35638503..49d69a3fb9 100644
--- a/src/cpp/server/secure_server_credentials.cc
+++ b/src/cpp/server/secure_server_credentials.cc
@@ -40,7 +40,8 @@ namespace grpc {
namespace {
class SecureServerCredentials GRPC_FINAL : public ServerCredentials {
public:
- explicit SecureServerCredentials(grpc_server_credentials* creds) : creds_(creds) {}
+ explicit SecureServerCredentials(grpc_server_credentials* creds)
+ : creds_(creds) {}
~SecureServerCredentials() GRPC_OVERRIDE {
grpc_server_credentials_release(creds_);
}
@@ -56,16 +57,20 @@ class SecureServerCredentials GRPC_FINAL : public ServerCredentials {
} // namespace
std::shared_ptr<ServerCredentials> SslServerCredentials(
- const SslServerCredentialsOptions &options) {
+ const SslServerCredentialsOptions& options) {
std::vector<grpc_ssl_pem_key_cert_pair> pem_key_cert_pairs;
- for (const auto &key_cert_pair : options.pem_key_cert_pairs) {
- pem_key_cert_pairs.push_back(
- {key_cert_pair.private_key.c_str(), key_cert_pair.cert_chain.c_str()});
+ for (auto key_cert_pair = options.pem_key_cert_pairs.begin();
+ key_cert_pair != options.pem_key_cert_pairs.end();
+ key_cert_pair++) {
+ grpc_ssl_pem_key_cert_pair p = {key_cert_pair->private_key.c_str(),
+ key_cert_pair->cert_chain.c_str()};
+ pem_key_cert_pairs.push_back(p);
}
- grpc_server_credentials *c_creds = grpc_ssl_server_credentials_create(
+ grpc_server_credentials* c_creds = grpc_ssl_server_credentials_create(
options.pem_root_certs.empty() ? nullptr : options.pem_root_certs.c_str(),
&pem_key_cert_pairs[0], pem_key_cert_pairs.size());
- return std::shared_ptr<ServerCredentials>(new SecureServerCredentials(c_creds));
+ return std::shared_ptr<ServerCredentials>(
+ new SecureServerCredentials(c_creds));
}
} // namespace grpc
diff --git a/src/cpp/server/server.cc b/src/cpp/server/server.cc
index e69032a657..8e6a6cf40a 100644
--- a/src/cpp/server/server.cc
+++ b/src/cpp/server/server.cc
@@ -36,8 +36,10 @@
#include <grpc/grpc.h>
#include <grpc/grpc_security.h>
+#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc++/completion_queue.h>
+#include <grpc++/async_generic_service.h>
#include <grpc++/impl/rpc_service_method.h>
#include <grpc++/impl/service_type.h>
#include <grpc++/server_context.h>
@@ -179,12 +181,12 @@ Server::Server(ThreadPoolInterface* thread_pool, bool thread_pool_owned)
thread_pool_owned_(thread_pool_owned) {}
Server::~Server() {
- std::unique_lock<std::mutex> lock(mu_);
- if (started_ && !shutdown_) {
- lock.unlock();
- Shutdown();
- } else {
- lock.unlock();
+ {
+ std::unique_lock<std::mutex> lock(mu_);
+ if (started_ && !shutdown_) {
+ lock.unlock();
+ Shutdown();
+ }
}
grpc_server_destroy(server_);
if (thread_pool_owned_) {
@@ -226,7 +228,14 @@ bool Server::RegisterAsyncService(AsynchronousService* service) {
return true;
}
-int Server::AddPort(const grpc::string& addr, ServerCredentials* creds) {
+void Server::RegisterAsyncGenericService(AsyncGenericService* service) {
+ GPR_ASSERT(service->server_ == nullptr &&
+ "Can only register an async generic service against one server.");
+ service->server_ = this;
+}
+
+int Server::AddListeningPort(const grpc::string& addr,
+ ServerCredentials* creds) {
GPR_ASSERT(!started_);
return creds->AddPortToServer(addr, server_);
}
@@ -238,8 +247,8 @@ bool Server::Start() {
// Start processing rpcs.
if (!sync_methods_.empty()) {
- for (auto& m : sync_methods_) {
- m.Request(server_);
+ for (auto m = sync_methods_.begin(); m != sync_methods_.end(); m++) {
+ m->Request(server_);
}
ScheduleCallback();
@@ -289,13 +298,33 @@ class Server::AsyncRequest GRPC_FINAL : public CompletionQueueTag {
stream_(stream),
cq_(cq),
ctx_(ctx),
+ generic_ctx_(nullptr),
server_(server),
call_(nullptr),
payload_(nullptr) {
memset(&array_, 0, sizeof(array_));
+ grpc_call_details_init(&call_details_);
grpc_server_request_registered_call(
- server->server_, registered_method, &call_, &deadline_, &array_,
- request ? &payload_ : nullptr, cq->cq(), this);
+ server->server_, registered_method, &call_, &call_details_.deadline,
+ &array_, request ? &payload_ : nullptr, cq->cq(), this);
+ }
+
+ AsyncRequest(Server* server, GenericServerContext* ctx,
+ ServerAsyncStreamingInterface* stream, CompletionQueue* cq,
+ void* tag)
+ : tag_(tag),
+ request_(nullptr),
+ stream_(stream),
+ cq_(cq),
+ ctx_(nullptr),
+ generic_ctx_(ctx),
+ server_(server),
+ call_(nullptr),
+ payload_(nullptr) {
+ memset(&array_, 0, sizeof(array_));
+ grpc_call_details_init(&call_details_);
+ grpc_server_request_call(server->server_, &call_, &call_details_, &array_,
+ cq->cq(), this);
}
~AsyncRequest() {
@@ -315,20 +344,29 @@ class Server::AsyncRequest GRPC_FINAL : public CompletionQueueTag {
*status = false;
}
}
+ ServerContext* ctx = ctx_ ? ctx_ : generic_ctx_;
+ GPR_ASSERT(ctx);
if (*status) {
- ctx_->deadline_ = Timespec2Timepoint(deadline_);
+ ctx->deadline_ = Timespec2Timepoint(call_details_.deadline);
for (size_t i = 0; i < array_.count; i++) {
- ctx_->client_metadata_.insert(std::make_pair(
+ ctx->client_metadata_.insert(std::make_pair(
grpc::string(array_.metadata[i].key),
grpc::string(
array_.metadata[i].value,
array_.metadata[i].value + array_.metadata[i].value_length)));
}
+ if (generic_ctx_) {
+ // TODO(yangg) remove the copy here.
+ generic_ctx_->method_ = call_details_.method;
+ generic_ctx_->host_ = call_details_.host;
+ gpr_free(call_details_.method);
+ gpr_free(call_details_.host);
+ }
}
- ctx_->call_ = call_;
+ ctx->call_ = call_;
Call call(call_, server_, cq_);
if (orig_status && call_) {
- ctx_->BeginCompletionOp(&call);
+ ctx->BeginCompletionOp(&call);
}
// just the pointers inside call are copied here
stream_->BindCall(&call);
@@ -342,9 +380,10 @@ class Server::AsyncRequest GRPC_FINAL : public CompletionQueueTag {
ServerAsyncStreamingInterface* const stream_;
CompletionQueue* const cq_;
ServerContext* const ctx_;
+ GenericServerContext* const generic_ctx_;
Server* const server_;
grpc_call* call_;
- gpr_timespec deadline_;
+ grpc_call_details call_details_;
grpc_metadata_array array_;
grpc_byte_buffer* payload_;
};
@@ -356,6 +395,12 @@ void Server::RequestAsyncCall(void* registered_method, ServerContext* context,
new AsyncRequest(this, registered_method, context, request, stream, cq, tag);
}
+void Server::RequestAsyncGenericCall(GenericServerContext* context,
+ ServerAsyncStreamingInterface* stream,
+ CompletionQueue* cq, void* tag) {
+ new AsyncRequest(this, context, stream, cq, tag);
+}
+
void Server::ScheduleCallback() {
{
std::unique_lock<std::mutex> lock(mu_);
diff --git a/src/cpp/server/server_builder.cc b/src/cpp/server/server_builder.cc
index 5de592334d..c5e115f396 100644
--- a/src/cpp/server/server_builder.cc
+++ b/src/cpp/server/server_builder.cc
@@ -41,7 +41,8 @@
namespace grpc {
-ServerBuilder::ServerBuilder() : thread_pool_(nullptr) {}
+ServerBuilder::ServerBuilder()
+ : generic_service_(nullptr), thread_pool_(nullptr) {}
void ServerBuilder::RegisterService(SynchronousService* service) {
services_.push_back(service->service());
@@ -51,9 +52,20 @@ void ServerBuilder::RegisterAsyncService(AsynchronousService* service) {
async_services_.push_back(service);
}
-void ServerBuilder::AddPort(const grpc::string& addr,
- std::shared_ptr<ServerCredentials> creds,
- int* selected_port) {
+void ServerBuilder::RegisterAsyncGenericService(AsyncGenericService* service) {
+ if (generic_service_) {
+ gpr_log(GPR_ERROR,
+ "Adding multiple AsyncGenericService is unsupported for now. "
+ "Dropping the service %p",
+ service);
+ return;
+ }
+ generic_service_ = service;
+}
+
+void ServerBuilder::AddListeningPort(const grpc::string& addr,
+ std::shared_ptr<ServerCredentials> creds,
+ int* selected_port) {
ports_.push_back(Port{addr, creds, selected_port});
}
@@ -74,21 +86,26 @@ std::unique_ptr<Server> ServerBuilder::BuildAndStart() {
thread_pool_owned = true;
}
std::unique_ptr<Server> server(new Server(thread_pool_, thread_pool_owned));
- for (auto* service : services_) {
- if (!server->RegisterService(service)) {
+ for (auto service = services_.begin(); service != services_.end();
+ service++) {
+ if (!server->RegisterService(*service)) {
return nullptr;
}
}
- for (auto* service : async_services_) {
- if (!server->RegisterAsyncService(service)) {
+ for (auto service = async_services_.begin();
+ service != async_services_.end(); service++) {
+ if (!server->RegisterAsyncService(*service)) {
return nullptr;
}
}
- for (auto& port : ports_) {
- int r = server->AddPort(port.addr, port.creds.get());
+ if (generic_service_) {
+ server->RegisterAsyncGenericService(generic_service_);
+ }
+ for (auto port = ports_.begin(); port != ports_.end(); port++) {
+ int r = server->AddListeningPort(port->addr, port->creds.get());
if (!r) return nullptr;
- if (port.selected_port != nullptr) {
- *port.selected_port = r;
+ if (port->selected_port != nullptr) {
+ *port->selected_port = r;
}
}
if (!server->Start()) {
diff --git a/src/cpp/server/thread_pool.cc b/src/cpp/server/thread_pool.cc
index 5dc9bcf916..80c96111b1 100644
--- a/src/cpp/server/thread_pool.cc
+++ b/src/cpp/server/thread_pool.cc
@@ -35,28 +35,29 @@
namespace grpc {
+void ThreadPool::ThreadFunc() {
+ for (;;) {
+ // Wait until work is available or we are shutting down.
+ std::unique_lock<std::mutex> lock(mu_);
+ if (!shutdown_ && callbacks_.empty()) {
+ cv_.wait(lock);
+ }
+ // Drain callbacks before considering shutdown to ensure all work
+ // gets completed.
+ if (!callbacks_.empty()) {
+ auto cb = callbacks_.front();
+ callbacks_.pop();
+ lock.unlock();
+ cb();
+ } else if (shutdown_) {
+ return;
+ }
+ }
+}
+
ThreadPool::ThreadPool(int num_threads) : shutdown_(false) {
for (int i = 0; i < num_threads; i++) {
- threads_.push_back(std::thread([this]() {
- for (;;) {
- // Wait until work is available or we are shutting down.
- auto have_work = [this]() { return shutdown_ || !callbacks_.empty(); };
- std::unique_lock<std::mutex> lock(mu_);
- if (!have_work()) {
- cv_.wait(lock, have_work);
- }
- // Drain callbacks before considering shutdown to ensure all work
- // gets completed.
- if (!callbacks_.empty()) {
- auto cb = callbacks_.front();
- callbacks_.pop();
- lock.unlock();
- cb();
- } else if (shutdown_) {
- return;
- }
- }
- }));
+ threads_.push_back(std::thread(&ThreadPool::ThreadFunc, this));
}
}
@@ -66,12 +67,12 @@ ThreadPool::~ThreadPool() {
shutdown_ = true;
cv_.notify_all();
}
- for (auto &t : threads_) {
- t.join();
+ for (auto t = threads_.begin(); t != threads_.end(); t++) {
+ t->join();
}
}
-void ThreadPool::ScheduleCallback(const std::function<void()> &callback) {
+void ThreadPool::ScheduleCallback(const std::function<void()>& callback) {
std::lock_guard<std::mutex> lock(mu_);
callbacks_.push(callback);
cv_.notify_one();
diff --git a/src/cpp/server/thread_pool.h b/src/cpp/server/thread_pool.h
index 6157e403e9..41e2009ff1 100644
--- a/src/cpp/server/thread_pool.h
+++ b/src/cpp/server/thread_pool.h
@@ -50,7 +50,7 @@ class ThreadPool GRPC_FINAL : public ThreadPoolInterface {
explicit ThreadPool(int num_threads);
~ThreadPool();
- void ScheduleCallback(const std::function<void()> &callback) GRPC_OVERRIDE;
+ void ScheduleCallback(const std::function<void()>& callback) GRPC_OVERRIDE;
private:
std::mutex mu_;
@@ -58,6 +58,8 @@ class ThreadPool GRPC_FINAL : public ThreadPoolInterface {
bool shutdown_;
std::queue<std::function<void()>> callbacks_;
std::vector<std::thread> threads_;
+
+ void ThreadFunc();
};
} // namespace grpc
diff --git a/src/cpp/util/byte_buffer.cc b/src/cpp/util/byte_buffer.cc
new file mode 100644
index 0000000000..f8d8eec065
--- /dev/null
+++ b/src/cpp/util/byte_buffer.cc
@@ -0,0 +1,76 @@
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc++/byte_buffer.h>
+
+namespace grpc {
+
+ByteBuffer::ByteBuffer(Slice* slices, size_t nslices) {
+ // TODO(yangg) maybe expose some core API to simplify this
+ std::vector<gpr_slice> c_slices(nslices);
+ for (size_t i = 0; i < nslices; i++) {
+ c_slices[i] = slices[i].slice_;
+ }
+ buffer_ = grpc_byte_buffer_create(c_slices.data(), nslices);
+}
+
+void ByteBuffer::Clear() {
+ if (buffer_) {
+ grpc_byte_buffer_destroy(buffer_);
+ buffer_ = nullptr;
+ }
+}
+
+void ByteBuffer::Dump(std::vector<Slice>* slices) {
+ slices->clear();
+ if (!buffer_) {
+ return;
+ }
+ grpc_byte_buffer_reader* reader = grpc_byte_buffer_reader_create(buffer_);
+ gpr_slice s;
+ while (grpc_byte_buffer_reader_next(reader, &s)) {
+ slices->push_back(Slice(s, Slice::STEAL_REF));
+ gpr_slice_unref(s);
+ }
+ grpc_byte_buffer_reader_destroy(reader);
+}
+
+size_t ByteBuffer::Length() {
+ if (buffer_) {
+ return grpc_byte_buffer_length(buffer_);
+ } else {
+ return 0;
+ }
+}
+
+} // namespace grpc
diff --git a/src/php/ext/grpc/event.h b/src/cpp/util/slice.cc
index ef5846aee1..57370dabc6 100755..100644
--- a/src/php/ext/grpc/event.h
+++ b/src/cpp/util/slice.cc
@@ -31,21 +31,18 @@
*
*/
-#ifndef NET_GRPC_PHP_GRPC_EVENT_H_
-#define NET_GRPC_PHP_GRPC_EVENT_H_
+#include <grpc++/slice.h>
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
+namespace grpc {
-#include "php.h"
-#include "php_ini.h"
-#include "ext/standard/info.h"
-#include "php_grpc.h"
+Slice::Slice() : slice_(gpr_empty_slice()) {}
-#include "grpc/grpc.h"
+Slice::~Slice() { gpr_slice_unref(slice_); }
-/* Create a new Event object that wraps an existing grpc_event struct */
-zval *grpc_php_convert_event(grpc_event *event);
+Slice::Slice(gpr_slice slice, AddRef) : slice_(gpr_slice_ref(slice)) {}
-#endif /* NET_GRPC_PHP_GRPC_COMPLETION_CHANNEL_H */
+Slice::Slice(gpr_slice slice, StealRef) : slice_(slice) {}
+
+Slice::Slice(const Slice& other) : slice_(gpr_slice_ref(other.slice_)) {}
+
+} // namespace grpc
diff --git a/src/cpp/util/status.cc b/src/cpp/util/status.cc
index bbf8030668..b694a513e7 100644
--- a/src/cpp/util/status.cc
+++ b/src/cpp/util/status.cc
@@ -35,7 +35,7 @@
namespace grpc {
-const Status &Status::OK = Status();
-const Status &Status::Cancelled = Status(StatusCode::CANCELLED);
+const Status& Status::OK = Status();
+const Status& Status::Cancelled = Status(StatusCode::CANCELLED);
} // namespace grpc
diff --git a/src/cpp/util/time.cc b/src/cpp/util/time.cc
index 919e5623fa..059ea72abf 100644
--- a/src/cpp/util/time.cc
+++ b/src/cpp/util/time.cc
@@ -42,11 +42,15 @@ using std::chrono::system_clock;
namespace grpc {
-// TODO(yangg) prevent potential overflow.
-void Timepoint2Timespec(const system_clock::time_point &from,
- gpr_timespec *to) {
+void Timepoint2Timespec(const system_clock::time_point& from,
+ gpr_timespec* to) {
system_clock::duration deadline = from.time_since_epoch();
seconds secs = duration_cast<seconds>(deadline);
+ if (from == system_clock::time_point::max() ||
+ secs.count() >= gpr_inf_future.tv_sec || secs.count() < 0) {
+ *to = gpr_inf_future;
+ return;
+ }
nanoseconds nsecs = duration_cast<nanoseconds>(deadline - secs);
to->tv_sec = secs.count();
to->tv_nsec = nsecs.count();
diff --git a/src/cpp/util/time.h b/src/cpp/util/time.h
index 1994848eb2..8b7fcf55f7 100644
--- a/src/cpp/util/time.h
+++ b/src/cpp/util/time.h
@@ -41,8 +41,8 @@
namespace grpc {
// from and to should be absolute time.
-void Timepoint2Timespec(const std::chrono::system_clock::time_point &from,
- gpr_timespec *to);
+void Timepoint2Timespec(const std::chrono::system_clock::time_point& from,
+ gpr_timespec* to);
std::chrono::system_clock::time_point Timespec2Timepoint(gpr_timespec t);
diff --git a/src/csharp/Grpc.Core.Tests/ClientServerTest.cs b/src/csharp/Grpc.Core.Tests/ClientServerTest.cs
index 39be35c219..3da9e33e53 100644
--- a/src/csharp/Grpc.Core.Tests/ClientServerTest.cs
+++ b/src/csharp/Grpc.Core.Tests/ClientServerTest.cs
@@ -46,6 +46,8 @@ namespace Grpc.Core.Tests
{
string host = "localhost";
+ string serviceName = "/tests.Test";
+
Method<string, string> unaryEchoStringMethod = new Method<string, string>(
MethodType.Unary,
"/tests.Test/UnaryEchoString",
@@ -69,15 +71,15 @@ namespace Grpc.Core.Tests
{
Server server = new Server();
server.AddServiceDefinition(
- ServerServiceDefinition.CreateBuilder("someService")
+ ServerServiceDefinition.CreateBuilder(serviceName)
.AddMethod(unaryEchoStringMethod, HandleUnaryEchoString).Build());
- int port = server.AddPort(host + ":0");
+ int port = server.AddListeningPort(host + ":0");
server.Start();
using (Channel channel = new Channel(host + ":" + port))
{
- var call = new Call<string, string>(unaryEchoStringMethod, channel);
+ var call = new Call<string, string>(serviceName, unaryEchoStringMethod, channel, Metadata.Empty);
Assert.AreEqual("ABC", Calls.BlockingUnaryCall(call, "ABC", default(CancellationToken)));
@@ -92,15 +94,15 @@ namespace Grpc.Core.Tests
{
Server server = new Server();
server.AddServiceDefinition(
- ServerServiceDefinition.CreateBuilder("someService")
+ ServerServiceDefinition.CreateBuilder(serviceName)
.AddMethod(unaryEchoStringMethod, HandleUnaryEchoString).Build());
- int port = server.AddPort(host + ":0");
+ int port = server.AddListeningPort(host + ":0");
server.Start();
using (Channel channel = new Channel(host + ":" + port))
{
- var call = new Call<string, string>(unaryEchoStringMethod, channel);
+ var call = new Call<string, string>(serviceName, unaryEchoStringMethod, channel, Metadata.Empty);
BenchmarkUtil.RunBenchmark(100, 1000,
() => { Calls.BlockingUnaryCall(call, "ABC", default(CancellationToken)); });
}
@@ -113,19 +115,22 @@ namespace Grpc.Core.Tests
{
Server server = new Server();
server.AddServiceDefinition(
- ServerServiceDefinition.CreateBuilder("someService").Build());
+ ServerServiceDefinition.CreateBuilder(serviceName).Build());
- int port = server.AddPort(host + ":0");
+ int port = server.AddListeningPort(host + ":0");
server.Start();
using (Channel channel = new Channel(host + ":" + port))
{
- var call = new Call<string, string>(unaryEchoStringMethod, channel);
+ var call = new Call<string, string>(serviceName, unaryEchoStringMethod, channel, Metadata.Empty);
- try {
+ try
+ {
Calls.BlockingUnaryCall(call, "ABC", default(CancellationToken));
Assert.Fail();
- } catch(RpcException e) {
+ }
+ catch (RpcException e)
+ {
Assert.AreEqual(StatusCode.Unimplemented, e.Status.StatusCode);
}
}
@@ -140,4 +145,3 @@ namespace Grpc.Core.Tests
}
}
}
-
diff --git a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj
index a365320f05..eac8d16fb1 100644
--- a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj
+++ b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj
@@ -42,6 +42,7 @@
<Compile Include="GrpcEnvironmentTest.cs" />
<Compile Include="TimespecTest.cs" />
<Compile Include="PInvokeTest.cs" />
+ <Compile Include="Internal\MetadataArraySafeHandleTest.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>
@@ -56,4 +57,7 @@
<ItemGroup>
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
</ItemGroup>
+ <ItemGroup>
+ <Folder Include="Internal\" />
+ </ItemGroup>
</Project> \ No newline at end of file
diff --git a/src/csharp/Grpc.Core.Tests/GrpcEnvironmentTest.cs b/src/csharp/Grpc.Core.Tests/GrpcEnvironmentTest.cs
index 596918c231..6a132a5b22 100644
--- a/src/csharp/Grpc.Core.Tests/GrpcEnvironmentTest.cs
+++ b/src/csharp/Grpc.Core.Tests/GrpcEnvironmentTest.cs
@@ -68,7 +68,7 @@ namespace Grpc.Core.Tests
var tp2 = GrpcEnvironment.ThreadPool;
GrpcEnvironment.Shutdown();
- Assert.IsFalse(Object.ReferenceEquals(tp1, tp2));
+ Assert.IsFalse(object.ReferenceEquals(tp1, tp2));
}
}
}
diff --git a/src/csharp/Grpc.Core.Tests/Internal/MetadataArraySafeHandleTest.cs b/src/csharp/Grpc.Core.Tests/Internal/MetadataArraySafeHandleTest.cs
new file mode 100644
index 0000000000..2f6013483d
--- /dev/null
+++ b/src/csharp/Grpc.Core.Tests/Internal/MetadataArraySafeHandleTest.cs
@@ -0,0 +1,62 @@
+#region Copyright notice and license
+
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#endregion
+
+using System;
+using Grpc.Core;
+using Grpc.Core.Internal;
+using Grpc.Core.Utils;
+using NUnit.Framework;
+
+namespace Grpc.Core.Internal.Tests
+{
+ public class MetadataArraySafeHandleTest
+ {
+ [Test]
+ public void CreateEmptyAndDestroy()
+ {
+ var metadata = Metadata.CreateBuilder().Build();
+ var nativeMetadata = MetadataArraySafeHandle.Create(metadata);
+ nativeMetadata.Dispose();
+ }
+
+ [Test]
+ public void CreateAndDestroy()
+ {
+ var metadata = Metadata.CreateBuilder()
+ .Add(new Metadata.MetadataEntry("host", "somehost"))
+ .Add(new Metadata.MetadataEntry("header2", "header value")).Build();
+ var nativeMetadata = MetadataArraySafeHandle.Create(metadata);
+ nativeMetadata.Dispose();
+ }
+ }
+}
diff --git a/src/csharp/Grpc.Core.Tests/PInvokeTest.cs b/src/csharp/Grpc.Core.Tests/PInvokeTest.cs
index 9db08d2f02..3beffc3955 100644
--- a/src/csharp/Grpc.Core.Tests/PInvokeTest.cs
+++ b/src/csharp/Grpc.Core.Tests/PInvokeTest.cs
@@ -33,13 +33,13 @@
using System;
using System.Diagnostics;
+using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using Grpc.Core;
using Grpc.Core.Internal;
using Grpc.Core.Utils;
using NUnit.Framework;
-using System.Runtime.InteropServices;
namespace Grpc.Core.Tests
{
@@ -73,14 +73,13 @@ namespace Grpc.Core.Tests
{
BenchmarkUtil.RunBenchmark(
100000, 1000000,
- () => {
+ () =>
+ {
CompletionQueueSafeHandle cq = CompletionQueueSafeHandle.Create();
cq.Dispose();
- }
- );
+ });
}
-
/// <summary>
/// Approximate results:
/// (~80ns Mono Linux)
@@ -94,10 +93,10 @@ namespace Grpc.Core.Tests
counter = 0;
BenchmarkUtil.RunBenchmark(
1000000, 10000000,
- () => {
+ () =>
+ {
grpcsharp_test_callback(handler);
- }
- );
+ });
Assert.AreNotEqual(0, counter);
}
@@ -113,10 +112,10 @@ namespace Grpc.Core.Tests
counter = 0;
BenchmarkUtil.RunBenchmark(
10000, 10000,
- () => {
- grpcsharp_test_callback(new CompletionCallbackDelegate(Handler));
- }
- );
+ () =>
+ {
+ grpcsharp_test_callback(new CompletionCallbackDelegate(Handler));
+ });
Assert.AreNotEqual(0, counter);
}
@@ -129,15 +128,15 @@ namespace Grpc.Core.Tests
{
BenchmarkUtil.RunBenchmark(
1000000, 100000000,
- () => {
+ () =>
+ {
grpcsharp_test_nop(IntPtr.Zero);
- }
- );
+ });
}
- private void Handler(GRPCOpError op, IntPtr ptr) {
- counter ++;
+ private void Handler(GRPCOpError op, IntPtr ptr)
+ {
+ counter++;
}
}
}
-
diff --git a/src/csharp/Grpc.Core.Tests/Properties/AssemblyInfo.cs b/src/csharp/Grpc.Core.Tests/Properties/AssemblyInfo.cs
index 499d931d2a..e4328806ad 100644
--- a/src/csharp/Grpc.Core.Tests/Properties/AssemblyInfo.cs
+++ b/src/csharp/Grpc.Core.Tests/Properties/AssemblyInfo.cs
@@ -1,8 +1,6 @@
using System.Reflection;
using System.Runtime.CompilerServices;
-// Information about this assembly is defined by the following attributes.
-// Change them to the values specific to your project.
[assembly: AssemblyTitle("Grpc.Core.Tests")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
@@ -11,12 +9,4 @@ using System.Runtime.CompilerServices;
[assembly: AssemblyCopyright("Google Inc. All rights reserved.")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
-// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
-// The form "{Major}.{Minor}.*" will automatically update the build and revision,
-// and "{Major}.{Minor}.{Build}.*" will update just the revision.
[assembly: AssemblyVersion("0.1.*")]
-// The following attributes are used to specify the signing key for the assembly,
-// if desired. See the Mono documentation for more information about signing.
-//[assembly: AssemblyDelaySign(false)]
-//[assembly: AssemblyKeyFile("")]
-
diff --git a/src/csharp/Grpc.Core.Tests/ServerTest.cs b/src/csharp/Grpc.Core.Tests/ServerTest.cs
index dd30366f6a..2a1855da67 100644
--- a/src/csharp/Grpc.Core.Tests/ServerTest.cs
+++ b/src/csharp/Grpc.Core.Tests/ServerTest.cs
@@ -47,12 +47,11 @@ namespace Grpc.Core.Tests
GrpcEnvironment.Initialize();
Server server = new Server();
- server.AddPort("localhost:0");
+ server.AddListeningPort("localhost:0");
server.Start();
server.ShutdownAsync().Wait();
GrpcEnvironment.Shutdown();
}
-
}
}
diff --git a/src/csharp/Grpc.Core.Tests/TimespecTest.cs b/src/csharp/Grpc.Core.Tests/TimespecTest.cs
index 0ca84ec44b..f5bae6d935 100644
--- a/src/csharp/Grpc.Core.Tests/TimespecTest.cs
+++ b/src/csharp/Grpc.Core.Tests/TimespecTest.cs
@@ -86,4 +86,3 @@ namespace Grpc.Core.Internal.Tests
}
}
}
-
diff --git a/src/csharp/Grpc.Core/Call.cs b/src/csharp/Grpc.Core/Call.cs
index 72dca68895..fe5f40f5e9 100644
--- a/src/csharp/Grpc.Core/Call.cs
+++ b/src/csharp/Grpc.Core/Call.cs
@@ -33,33 +33,25 @@
using System;
using Grpc.Core.Internal;
+using Grpc.Core.Utils;
namespace Grpc.Core
{
public class Call<TRequest, TResponse>
{
- readonly string methodName;
- readonly Func<TRequest, byte[]> requestSerializer;
- readonly Func<byte[], TResponse> responseDeserializer;
+ readonly string name;
+ readonly Marshaller<TRequest> requestMarshaller;
+ readonly Marshaller<TResponse> responseMarshaller;
readonly Channel channel;
+ readonly Metadata headers;
- public Call(string methodName,
- Func<TRequest, byte[]> requestSerializer,
- Func<byte[], TResponse> responseDeserializer,
- TimeSpan timeout,
- Channel channel) {
- this.methodName = methodName;
- this.requestSerializer = requestSerializer;
- this.responseDeserializer = responseDeserializer;
- this.channel = channel;
- }
-
- public Call(Method<TRequest, TResponse> method, Channel channel)
+ public Call(string serviceName, Method<TRequest, TResponse> method, Channel channel, Metadata headers)
{
- this.methodName = method.Name;
- this.requestSerializer = method.RequestMarshaller.Serializer;
- this.responseDeserializer = method.ResponseMarshaller.Deserializer;
- this.channel = channel;
+ this.name = Preconditions.CheckNotNull(serviceName) + "/" + method.Name;
+ this.requestMarshaller = method.RequestMarshaller;
+ this.responseMarshaller = method.ResponseMarshaller;
+ this.channel = Preconditions.CheckNotNull(channel);
+ this.headers = Preconditions.CheckNotNull(headers);
}
public Channel Channel
@@ -70,29 +62,42 @@ namespace Grpc.Core
}
}
- public string MethodName
+ /// <summary>
+ /// Full methods name including the service name.
+ /// </summary>
+ public string Name
{
get
{
- return this.methodName;
+ return name;
}
}
- public Func<TRequest, byte[]> RequestSerializer
+ /// <summary>
+ /// Headers to send at the beginning of the call.
+ /// </summary>
+ public Metadata Headers
{
get
{
- return this.requestSerializer;
+ return headers;
}
}
- public Func<byte[], TResponse> ResponseDeserializer
+ public Marshaller<TRequest> RequestMarshaller
{
get
{
- return this.responseDeserializer;
+ return requestMarshaller;
+ }
+ }
+
+ public Marshaller<TResponse> ResponseMarshaller
+ {
+ get
+ {
+ return responseMarshaller;
}
}
}
}
-
diff --git a/src/csharp/Grpc.Core/Calls.cs b/src/csharp/Grpc.Core/Calls.cs
index ee2208e5c2..280387b323 100644
--- a/src/csharp/Grpc.Core/Calls.cs
+++ b/src/csharp/Grpc.Core/Calls.cs
@@ -38,8 +38,6 @@ using Grpc.Core.Internal;
namespace Grpc.Core
{
- // NOTE: this class is work-in-progress
-
/// <summary>
/// Helper methods for generated stubs to make RPC calls.
/// </summary>
@@ -47,30 +45,29 @@ namespace Grpc.Core
{
public static TResponse BlockingUnaryCall<TRequest, TResponse>(Call<TRequest, TResponse> call, TRequest req, CancellationToken token)
{
- var asyncCall = new AsyncCall<TRequest, TResponse>(call.RequestSerializer, call.ResponseDeserializer);
- return asyncCall.UnaryCall(call.Channel, call.MethodName, req);
+ var asyncCall = new AsyncCall<TRequest, TResponse>(call.RequestMarshaller.Serializer, call.ResponseMarshaller.Deserializer);
+ return asyncCall.UnaryCall(call.Channel, call.Name, req, call.Headers);
}
public static async Task<TResponse> AsyncUnaryCall<TRequest, TResponse>(Call<TRequest, TResponse> call, TRequest req, CancellationToken token)
{
- var asyncCall = new AsyncCall<TRequest, TResponse>(call.RequestSerializer, call.ResponseDeserializer);
- asyncCall.Initialize(call.Channel, GetCompletionQueue(), call.MethodName);
- return await asyncCall.UnaryCallAsync(req);
+ var asyncCall = new AsyncCall<TRequest, TResponse>(call.RequestMarshaller.Serializer, call.ResponseMarshaller.Deserializer);
+ asyncCall.Initialize(call.Channel, GetCompletionQueue(), call.Name);
+ return await asyncCall.UnaryCallAsync(req, call.Headers);
}
public static void AsyncServerStreamingCall<TRequest, TResponse>(Call<TRequest, TResponse> call, TRequest req, IObserver<TResponse> outputs, CancellationToken token)
{
- var asyncCall = new AsyncCall<TRequest, TResponse>(call.RequestSerializer, call.ResponseDeserializer);
-
- asyncCall.Initialize(call.Channel, GetCompletionQueue(), call.MethodName);
- asyncCall.StartServerStreamingCall(req, outputs);
+ var asyncCall = new AsyncCall<TRequest, TResponse>(call.RequestMarshaller.Serializer, call.ResponseMarshaller.Deserializer);
+ asyncCall.Initialize(call.Channel, GetCompletionQueue(), call.Name);
+ asyncCall.StartServerStreamingCall(req, outputs, call.Headers);
}
public static ClientStreamingAsyncResult<TRequest, TResponse> AsyncClientStreamingCall<TRequest, TResponse>(Call<TRequest, TResponse> call, CancellationToken token)
{
- var asyncCall = new AsyncCall<TRequest, TResponse>(call.RequestSerializer, call.ResponseDeserializer);
- asyncCall.Initialize(call.Channel, GetCompletionQueue(), call.MethodName);
- var task = asyncCall.ClientStreamingCallAsync();
+ var asyncCall = new AsyncCall<TRequest, TResponse>(call.RequestMarshaller.Serializer, call.ResponseMarshaller.Deserializer);
+ asyncCall.Initialize(call.Channel, GetCompletionQueue(), call.Name);
+ var task = asyncCall.ClientStreamingCallAsync(call.Headers);
var inputs = new ClientStreamingInputObserver<TRequest, TResponse>(asyncCall);
return new ClientStreamingAsyncResult<TRequest, TResponse>(task, inputs);
}
@@ -82,16 +79,15 @@ namespace Grpc.Core
public static IObserver<TRequest> DuplexStreamingCall<TRequest, TResponse>(Call<TRequest, TResponse> call, IObserver<TResponse> outputs, CancellationToken token)
{
- var asyncCall = new AsyncCall<TRequest, TResponse>(call.RequestSerializer, call.ResponseDeserializer);
- asyncCall.Initialize(call.Channel, GetCompletionQueue(), call.MethodName);
-
- asyncCall.StartDuplexStreamingCall(outputs);
+ var asyncCall = new AsyncCall<TRequest, TResponse>(call.RequestMarshaller.Serializer, call.ResponseMarshaller.Deserializer);
+ asyncCall.Initialize(call.Channel, GetCompletionQueue(), call.Name);
+ asyncCall.StartDuplexStreamingCall(outputs, call.Headers);
return new ClientStreamingInputObserver<TRequest, TResponse>(asyncCall);
}
- private static CompletionQueueSafeHandle GetCompletionQueue() {
+ private static CompletionQueueSafeHandle GetCompletionQueue()
+ {
return GrpcEnvironment.ThreadPool.CompletionQueue;
}
}
}
-
diff --git a/src/csharp/Grpc.Core/Channel.cs b/src/csharp/Grpc.Core/Channel.cs
index 83d965debf..3a42dac1d7 100644
--- a/src/csharp/Grpc.Core/Channel.cs
+++ b/src/csharp/Grpc.Core/Channel.cs
@@ -36,10 +36,13 @@ using Grpc.Core.Internal;
namespace Grpc.Core
{
+ /// <summary>
+ /// gRPC Channel
+ /// </summary>
public class Channel : IDisposable
{
readonly ChannelSafeHandle handle;
- readonly String target;
+ readonly string target;
/// <summary>
/// Creates a channel.
diff --git a/src/csharp/Grpc.Core/ChannelArgs.cs b/src/csharp/Grpc.Core/ChannelArgs.cs
index 298b6edf20..74ab310e44 100644
--- a/src/csharp/Grpc.Core/ChannelArgs.cs
+++ b/src/csharp/Grpc.Core/ChannelArgs.cs
@@ -30,6 +30,7 @@
#endregion
using System;
using System.Collections.Generic;
+using System.Collections.Immutable;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
@@ -37,33 +38,18 @@ using Grpc.Core.Internal;
namespace Grpc.Core
{
- // TODO: should we be using the builder pattern?
+ /// <summary>
+ /// gRPC channel options.
+ /// </summary>
public class ChannelArgs
{
public const string SslTargetNameOverrideKey = "grpc.ssl_target_name_override";
- public class Builder
- {
- Dictionary<string,string> stringArgs = new Dictionary<string,string>();
- // TODO: AddInteger not supported yet.
- public Builder AddString(string key, string value)
- {
- stringArgs.Add(key, value);
- return this;
- }
+ readonly ImmutableDictionary<string, string> stringArgs;
- public ChannelArgs Build()
- {
- return new ChannelArgs(stringArgs);
- }
- }
-
- Dictionary<string,string> stringArgs;
-
- private ChannelArgs(Dictionary<string, string> stringArgs)
+ private ChannelArgs(ImmutableDictionary<string, string> stringArgs)
{
- // TODO: use immutable dict?
- this.stringArgs = new Dictionary<string, string>(stringArgs);
+ this.stringArgs = stringArgs;
}
public string GetSslTargetNameOverride()
@@ -76,11 +62,28 @@ namespace Grpc.Core
return null;
}
- public static Builder NewBuilder()
+ public static Builder CreateBuilder()
{
return new Builder();
}
+ public class Builder
+ {
+ readonly Dictionary<string, string> stringArgs = new Dictionary<string, string>();
+
+ // TODO: AddInteger not supported yet.
+ public Builder AddString(string key, string value)
+ {
+ stringArgs.Add(key, value);
+ return this;
+ }
+
+ public ChannelArgs Build()
+ {
+ return new ChannelArgs(stringArgs.ToImmutableDictionary());
+ }
+ }
+
/// <summary>
/// Creates native object for the channel arguments.
/// </summary>
diff --git a/src/csharp/Grpc.Core/ClientStreamingAsyncResult.cs b/src/csharp/Grpc.Core/ClientStreamingAsyncResult.cs
index 44580a1154..65bedb0a33 100644
--- a/src/csharp/Grpc.Core/ClientStreamingAsyncResult.cs
+++ b/src/csharp/Grpc.Core/ClientStreamingAsyncResult.cs
@@ -67,4 +67,3 @@ namespace Grpc.Core
}
}
}
-
diff --git a/src/csharp/Grpc.Core/Credentials.cs b/src/csharp/Grpc.Core/Credentials.cs
index 5116c277f7..15dd3ef321 100644
--- a/src/csharp/Grpc.Core/Credentials.cs
+++ b/src/csharp/Grpc.Core/Credentials.cs
@@ -36,6 +36,9 @@ using Grpc.Core.Internal;
namespace Grpc.Core
{
+ /// <summary>
+ /// Client-side credentials.
+ /// </summary>
public abstract class Credentials
{
/// <summary>
@@ -74,4 +77,3 @@ namespace Grpc.Core
}
}
}
-
diff --git a/src/csharp/Grpc.Core/Grpc.Core.csproj b/src/csharp/Grpc.Core/Grpc.Core.csproj
index 78b6cdde59..78ba32b277 100644
--- a/src/csharp/Grpc.Core/Grpc.Core.csproj
+++ b/src/csharp/Grpc.Core/Grpc.Core.csproj
@@ -31,6 +31,9 @@
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
+ <Reference Include="System.Collections.Immutable">
+ <HintPath>..\packages\System.Collections.Immutable.1.1.34-rc\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll</HintPath>
+ </Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="Internal\GrpcLog.cs" />
@@ -54,7 +57,7 @@
<Compile Include="Internal\ServerSafeHandle.cs" />
<Compile Include="Method.cs" />
<Compile Include="ServerCalls.cs" />
- <Compile Include="ServerCallHandler.cs" />
+ <Compile Include="Internal\ServerCallHandler.cs" />
<Compile Include="Marshaller.cs" />
<Compile Include="ServerServiceDefinition.cs" />
<Compile Include="Utils\RecordingObserver.cs" />
@@ -74,6 +77,15 @@
<Compile Include="OperationFailedException.cs" />
<Compile Include="Internal\AsyncCall.cs" />
<Compile Include="Utils\Preconditions.cs" />
+ <Compile Include="Internal\ServerCredentialsSafeHandle.cs" />
+ <Compile Include="ServerCredentials.cs" />
+ <Compile Include="Metadata.cs" />
+ <Compile Include="Internal\MetadataArraySafeHandle.cs" />
+ <Compile Include="Stub\AbstractStub.cs" />
+ <Compile Include="Stub\StubConfiguration.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="packages.config" />
</ItemGroup>
<Choose>
<!-- Under older versions of Monodevelop, Choose is not supported and is just
@@ -88,4 +100,7 @@
<Otherwise />
</Choose>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+ <ItemGroup>
+ <Folder Include="Stub\" />
+ </ItemGroup>
</Project> \ No newline at end of file
diff --git a/src/csharp/Grpc.Core/GrpcEnvironment.cs b/src/csharp/Grpc.Core/GrpcEnvironment.cs
index d3a8da4729..9c10a42e23 100644
--- a/src/csharp/Grpc.Core/GrpcEnvironment.cs
+++ b/src/csharp/Grpc.Core/GrpcEnvironment.cs
@@ -63,8 +63,9 @@ namespace Grpc.Core
/// lifetime (and call Shutdown once you're done), for the sake of easier testing it's
/// allowed to initialize the environment again after it has been successfully shutdown.
/// </summary>
- public static void Initialize() {
- lock(staticLock)
+ public static void Initialize()
+ {
+ lock (staticLock)
{
if (instance == null)
{
@@ -79,7 +80,7 @@ namespace Grpc.Core
/// </summary>
public static void Shutdown()
{
- lock(staticLock)
+ lock (staticLock)
{
if (instance != null)
{
@@ -133,4 +134,3 @@ namespace Grpc.Core
}
}
}
-
diff --git a/src/csharp/Grpc.Core/Internal/AsyncCall.cs b/src/csharp/Grpc.Core/Internal/AsyncCall.cs
index 5ae036298b..bc72cb78de 100644
--- a/src/csharp/Grpc.Core/Internal/AsyncCall.cs
+++ b/src/csharp/Grpc.Core/Internal/AsyncCall.cs
@@ -54,7 +54,7 @@ namespace Grpc.Core.Internal
TaskCompletionSource<TResponse> unaryResponseTcs;
// Set after status is received. Only used for streaming response calls.
- Nullable<Status> finishedStatus;
+ Status? finishedStatus;
bool readObserverCompleted; // True if readObserver has already been completed.
@@ -64,7 +64,7 @@ namespace Grpc.Core.Internal
this.finishedHandler = CreateBatchCompletionCallback(HandleFinished);
}
- public void Initialize(Channel channel, CompletionQueueSafeHandle cq, String methodName)
+ public void Initialize(Channel channel, CompletionQueueSafeHandle cq, string methodName)
{
var call = CallSafeHandle.Create(channel.Handle, cq, methodName, channel.Target, Timespec.InfFuture);
InitializeInternal(call);
@@ -77,9 +77,9 @@ namespace Grpc.Core.Internal
/// <summary>
/// Blocking unary request - unary response call.
/// </summary>
- public TResponse UnaryCall(Channel channel, String methodName, TRequest msg)
+ public TResponse UnaryCall(Channel channel, string methodName, TRequest msg, Metadata headers)
{
- using(CompletionQueueSafeHandle cq = CompletionQueueSafeHandle.Create())
+ using (CompletionQueueSafeHandle cq = CompletionQueueSafeHandle.Create())
{
byte[] payload = UnsafeSerialize(msg);
@@ -92,7 +92,11 @@ namespace Grpc.Core.Internal
halfcloseRequested = true;
readingDone = true;
}
- call.BlockingUnary(cq, payload, unaryResponseHandler);
+
+ using (var metadataArray = MetadataArraySafeHandle.Create(headers))
+ {
+ call.BlockingUnary(cq, payload, unaryResponseHandler, metadataArray);
+ }
try
{
@@ -109,7 +113,7 @@ namespace Grpc.Core.Internal
/// <summary>
/// Starts a unary request - unary response call.
/// </summary>
- public Task<TResponse> UnaryCallAsync(TRequest msg)
+ public Task<TResponse> UnaryCallAsync(TRequest msg, Metadata headers)
{
lock (myLock)
{
@@ -122,8 +126,10 @@ namespace Grpc.Core.Internal
byte[] payload = UnsafeSerialize(msg);
unaryResponseTcs = new TaskCompletionSource<TResponse>();
- call.StartUnary(payload, unaryResponseHandler);
-
+ using (var metadataArray = MetadataArraySafeHandle.Create(headers))
+ {
+ call.StartUnary(payload, unaryResponseHandler, metadataArray);
+ }
return unaryResponseTcs.Task;
}
}
@@ -132,7 +138,7 @@ namespace Grpc.Core.Internal
/// Starts a streamed request - unary response call.
/// Use StartSendMessage and StartSendCloseFromClient to stream requests.
/// </summary>
- public Task<TResponse> ClientStreamingCallAsync()
+ public Task<TResponse> ClientStreamingCallAsync(Metadata headers)
{
lock (myLock)
{
@@ -142,7 +148,10 @@ namespace Grpc.Core.Internal
readingDone = true;
unaryResponseTcs = new TaskCompletionSource<TResponse>();
- call.StartClientStreaming(unaryResponseHandler);
+ using (var metadataArray = MetadataArraySafeHandle.Create(headers))
+ {
+ call.StartClientStreaming(unaryResponseHandler, metadataArray);
+ }
return unaryResponseTcs.Task;
}
@@ -151,7 +160,7 @@ namespace Grpc.Core.Internal
/// <summary>
/// Starts a unary request - streamed response call.
/// </summary>
- public void StartServerStreamingCall(TRequest msg, IObserver<TResponse> readObserver)
+ public void StartServerStreamingCall(TRequest msg, IObserver<TResponse> readObserver, Metadata headers)
{
lock (myLock)
{
@@ -165,7 +174,10 @@ namespace Grpc.Core.Internal
byte[] payload = UnsafeSerialize(msg);
- call.StartServerStreaming(payload, finishedHandler);
+ using (var metadataArray = MetadataArraySafeHandle.Create(headers))
+ {
+ call.StartServerStreaming(payload, finishedHandler, metadataArray);
+ }
StartReceiveMessage();
}
@@ -175,7 +187,7 @@ namespace Grpc.Core.Internal
/// Starts a streaming request - streaming response call.
/// Use StartSendMessage and StartSendCloseFromClient to stream requests.
/// </summary>
- public void StartDuplexStreamingCall(IObserver<TResponse> readObserver)
+ public void StartDuplexStreamingCall(IObserver<TResponse> readObserver, Metadata headers)
{
lock (myLock)
{
@@ -185,7 +197,10 @@ namespace Grpc.Core.Internal
this.readObserver = readObserver;
- call.StartDuplexStreaming(finishedHandler);
+ using (var metadataArray = MetadataArraySafeHandle.Create(headers))
+ {
+ call.StartDuplexStreaming(finishedHandler, metadataArray);
+ }
StartReceiveMessage();
}
@@ -254,7 +269,7 @@ namespace Grpc.Core.Internal
/// </summary>
private void HandleUnaryResponse(bool wasError, BatchContextSafeHandleNotOwned ctx)
{
- lock(myLock)
+ lock (myLock)
{
finished = true;
halfclosed = true;
@@ -264,9 +279,7 @@ namespace Grpc.Core.Internal
if (wasError)
{
- unaryResponseTcs.SetException(new RpcException(
- new Status(StatusCode.Internal, "Internal error occured.")
- ));
+ unaryResponseTcs.SetException(new RpcException(new Status(StatusCode.Internal, "Internal error occured.")));
return;
}
diff --git a/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs b/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs
index 44d66b394c..15b0cfe249 100644
--- a/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs
+++ b/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs
@@ -225,7 +225,7 @@ namespace Grpc.Core.Internal
payload = serializer(msg);
return true;
}
- catch(Exception)
+ catch (Exception)
{
Console.WriteLine("Exception occured while trying to serialize message");
payload = null;
@@ -240,7 +240,7 @@ namespace Grpc.Core.Internal
msg = deserializer(payload);
return true;
}
- catch(Exception)
+ catch (Exception)
{
Console.WriteLine("Exception occured while trying to deserialize message");
msg = default(TRead);
@@ -254,7 +254,7 @@ namespace Grpc.Core.Internal
{
readObserver.OnNext(value);
}
- catch(Exception e)
+ catch (Exception e)
{
Console.WriteLine("Exception occured while invoking readObserver.OnNext: " + e);
}
@@ -266,7 +266,7 @@ namespace Grpc.Core.Internal
{
readObserver.OnCompleted();
}
- catch(Exception e)
+ catch (Exception e)
{
Console.WriteLine("Exception occured while invoking readObserver.OnCompleted: " + e);
}
@@ -278,7 +278,7 @@ namespace Grpc.Core.Internal
{
readObserver.OnError(error);
}
- catch(Exception e)
+ catch (Exception e)
{
Console.WriteLine("Exception occured while invoking readObserver.OnError: " + e);
}
@@ -290,7 +290,7 @@ namespace Grpc.Core.Internal
{
completionDelegate(error);
}
- catch(Exception e)
+ catch (Exception e)
{
Console.WriteLine("Exception occured while invoking completion delegate: " + e);
}
@@ -302,14 +302,15 @@ namespace Grpc.Core.Internal
/// </summary>
protected CompletionCallbackDelegate CreateBatchCompletionCallback(Action<bool, BatchContextSafeHandleNotOwned> handler)
{
- return new CompletionCallbackDelegate( (error, batchContextPtr) => {
+ return new CompletionCallbackDelegate((error, batchContextPtr) =>
+ {
try
{
var ctx = new BatchContextSafeHandleNotOwned(batchContextPtr);
bool wasError = (error != GRPCOpError.GRPC_OP_OK);
handler(wasError, ctx);
}
- catch(Exception e)
+ catch (Exception e)
{
Console.WriteLine("Caught exception in a native handler: " + e);
}
@@ -363,7 +364,6 @@ namespace Grpc.Core.Internal
{
FireCompletion(origCompletionDelegate, null);
}
-
}
/// <summary>
diff --git a/src/csharp/Grpc.Core/Internal/AsyncCompletion.cs b/src/csharp/Grpc.Core/Internal/AsyncCompletion.cs
index b78bb497fa..673b527fb2 100644
--- a/src/csharp/Grpc.Core/Internal/AsyncCompletion.cs
+++ b/src/csharp/Grpc.Core/Internal/AsyncCompletion.cs
@@ -91,5 +91,4 @@ namespace Grpc.Core.Internal
tcs.SetException(error);
}
}
-
} \ No newline at end of file
diff --git a/src/csharp/Grpc.Core/Internal/BatchContextSafeHandleNotOwned.cs b/src/csharp/Grpc.Core/Internal/BatchContextSafeHandleNotOwned.cs
index 75cd30e1a2..3c54753756 100644
--- a/src/csharp/Grpc.Core/Internal/BatchContextSafeHandleNotOwned.cs
+++ b/src/csharp/Grpc.Core/Internal/BatchContextSafeHandleNotOwned.cs
@@ -80,16 +80,18 @@ namespace Grpc.Core.Internal
{
return null;
}
- byte[] data = new byte[(int) len];
+ byte[] data = new byte[(int)len];
grpcsharp_batch_context_recv_message_to_buffer(this, data, new UIntPtr((ulong)data.Length));
return data;
}
- public CallSafeHandle GetServerRpcNewCall() {
+ public CallSafeHandle GetServerRpcNewCall()
+ {
return grpcsharp_batch_context_server_rpc_new_call(this);
}
- public string GetServerRpcNewMethod() {
+ public string GetServerRpcNewMethod()
+ {
return Marshal.PtrToStringAnsi(grpcsharp_batch_context_server_rpc_new_method(this));
}
}
diff --git a/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs b/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs
index 61566b5407..14add60c72 100644
--- a/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs
+++ b/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs
@@ -36,13 +36,14 @@ using Grpc.Core;
namespace Grpc.Core.Internal
{
- internal delegate void CompletionCallbackDelegate(GRPCOpError error,IntPtr batchContextPtr);
+ internal delegate void CompletionCallbackDelegate(GRPCOpError error, IntPtr batchContextPtr);
+
/// <summary>
/// grpc_call from <grpc/grpc.h>
/// </summary>
internal class CallSafeHandle : SafeHandleZeroIsInvalid
{
- const UInt32 GRPC_WRITE_BUFFER_HINT = 1;
+ const uint GRPC_WRITE_BUFFER_HINT = 1;
[DllImport("grpc_csharp_ext.dll")]
static extern CallSafeHandle grpcsharp_channel_create_call(ChannelSafeHandle channel, CompletionQueueSafeHandle cq, string method, string host, Timespec deadline);
@@ -56,25 +57,28 @@ namespace Grpc.Core.Internal
[DllImport("grpc_csharp_ext.dll")]
static extern GRPCCallError grpcsharp_call_start_unary(CallSafeHandle call,
[MarshalAs(UnmanagedType.FunctionPtr)] CompletionCallbackDelegate callback,
- byte[] send_buffer, UIntPtr send_buffer_len);
+ byte[] send_buffer, UIntPtr send_buffer_len, MetadataArraySafeHandle metadataArray);
[DllImport("grpc_csharp_ext.dll")]
static extern void grpcsharp_call_blocking_unary(CallSafeHandle call, CompletionQueueSafeHandle dedicatedCq,
[MarshalAs(UnmanagedType.FunctionPtr)] CompletionCallbackDelegate callback,
- byte[] send_buffer, UIntPtr send_buffer_len);
+ byte[] send_buffer, UIntPtr send_buffer_len, MetadataArraySafeHandle metadataArray);
[DllImport("grpc_csharp_ext.dll")]
static extern GRPCCallError grpcsharp_call_start_client_streaming(CallSafeHandle call,
- [MarshalAs(UnmanagedType.FunctionPtr)] CompletionCallbackDelegate callback);
+ [MarshalAs(UnmanagedType.FunctionPtr)] CompletionCallbackDelegate callback,
+ MetadataArraySafeHandle metadataArray);
[DllImport("grpc_csharp_ext.dll")]
static extern GRPCCallError grpcsharp_call_start_server_streaming(CallSafeHandle call,
[MarshalAs(UnmanagedType.FunctionPtr)] CompletionCallbackDelegate callback,
- byte[] send_buffer, UIntPtr send_buffer_len);
+ byte[] send_buffer, UIntPtr send_buffer_len,
+ MetadataArraySafeHandle metadataArray);
[DllImport("grpc_csharp_ext.dll")]
static extern GRPCCallError grpcsharp_call_start_duplex_streaming(CallSafeHandle call,
- [MarshalAs(UnmanagedType.FunctionPtr)] CompletionCallbackDelegate callback);
+ [MarshalAs(UnmanagedType.FunctionPtr)] CompletionCallbackDelegate callback,
+ MetadataArraySafeHandle metadataArray);
[DllImport("grpc_csharp_ext.dll")]
static extern GRPCCallError grpcsharp_call_send_message(CallSafeHandle call,
@@ -108,29 +112,29 @@ namespace Grpc.Core.Internal
return grpcsharp_channel_create_call(channel, cq, method, host, deadline);
}
- public void StartUnary(byte[] payload, CompletionCallbackDelegate callback)
+ public void StartUnary(byte[] payload, CompletionCallbackDelegate callback, MetadataArraySafeHandle metadataArray)
{
- AssertCallOk(grpcsharp_call_start_unary(this, callback, payload, new UIntPtr((ulong)payload.Length)));
+ AssertCallOk(grpcsharp_call_start_unary(this, callback, payload, new UIntPtr((ulong)payload.Length), metadataArray));
}
- public void BlockingUnary(CompletionQueueSafeHandle dedicatedCq, byte[] payload, CompletionCallbackDelegate callback)
+ public void BlockingUnary(CompletionQueueSafeHandle dedicatedCq, byte[] payload, CompletionCallbackDelegate callback, MetadataArraySafeHandle metadataArray)
{
- grpcsharp_call_blocking_unary(this, dedicatedCq, callback, payload, new UIntPtr((ulong)payload.Length));
+ grpcsharp_call_blocking_unary(this, dedicatedCq, callback, payload, new UIntPtr((ulong)payload.Length), metadataArray);
}
- public void StartClientStreaming(CompletionCallbackDelegate callback)
+ public void StartClientStreaming(CompletionCallbackDelegate callback, MetadataArraySafeHandle metadataArray)
{
- AssertCallOk(grpcsharp_call_start_client_streaming(this, callback));
+ AssertCallOk(grpcsharp_call_start_client_streaming(this, callback, metadataArray));
}
- public void StartServerStreaming(byte[] payload, CompletionCallbackDelegate callback)
+ public void StartServerStreaming(byte[] payload, CompletionCallbackDelegate callback, MetadataArraySafeHandle metadataArray)
{
- AssertCallOk(grpcsharp_call_start_server_streaming(this, callback, payload, new UIntPtr((ulong)payload.Length)));
+ AssertCallOk(grpcsharp_call_start_server_streaming(this, callback, payload, new UIntPtr((ulong)payload.Length), metadataArray));
}
- public void StartDuplexStreaming(CompletionCallbackDelegate callback)
+ public void StartDuplexStreaming(CompletionCallbackDelegate callback, MetadataArraySafeHandle metadataArray)
{
- AssertCallOk(grpcsharp_call_start_duplex_streaming(this, callback));
+ AssertCallOk(grpcsharp_call_start_duplex_streaming(this, callback, metadataArray));
}
public void StartSendMessage(byte[] payload, CompletionCallbackDelegate callback)
@@ -179,7 +183,7 @@ namespace Grpc.Core.Internal
Trace.Assert(callError == GRPCCallError.GRPC_CALL_OK, "Status not GRPC_CALL_OK");
}
- private static UInt32 GetFlags(bool buffered)
+ private static uint GetFlags(bool buffered)
{
return buffered ? 0 : GRPC_WRITE_BUFFER_HINT;
}
diff --git a/src/csharp/Grpc.Core/Internal/ChannelArgsSafeHandle.cs b/src/csharp/Grpc.Core/Internal/ChannelArgsSafeHandle.cs
index ca3c21d84c..c69f1a0d02 100644
--- a/src/csharp/Grpc.Core/Internal/ChannelArgsSafeHandle.cs
+++ b/src/csharp/Grpc.Core/Internal/ChannelArgsSafeHandle.cs
@@ -74,4 +74,3 @@ namespace Grpc.Core.Internal
}
}
}
-
diff --git a/src/csharp/Grpc.Core/Internal/CompletionQueueSafeHandle.cs b/src/csharp/Grpc.Core/Internal/CompletionQueueSafeHandle.cs
index 6bff923c55..600d1fc87c 100644
--- a/src/csharp/Grpc.Core/Internal/CompletionQueueSafeHandle.cs
+++ b/src/csharp/Grpc.Core/Internal/CompletionQueueSafeHandle.cs
@@ -77,4 +77,3 @@ namespace Grpc.Core.Internal
}
}
}
-
diff --git a/src/csharp/Grpc.Core/Internal/Enums.cs b/src/csharp/Grpc.Core/Internal/Enums.cs
index f363050b07..94a2fd1784 100644
--- a/src/csharp/Grpc.Core/Internal/Enums.cs
+++ b/src/csharp/Grpc.Core/Internal/Enums.cs
@@ -112,4 +112,3 @@ namespace Grpc.Core.Internal
GRPC_OP_ERROR
}
}
-
diff --git a/src/csharp/Grpc.Core/Internal/GrpcLog.cs b/src/csharp/Grpc.Core/Internal/GrpcLog.cs
index 98768d05c6..2f3c8ad71c 100644
--- a/src/csharp/Grpc.Core/Internal/GrpcLog.cs
+++ b/src/csharp/Grpc.Core/Internal/GrpcLog.cs
@@ -40,7 +40,7 @@ using System.Threading;
namespace Grpc.Core.Internal
{
- internal delegate void GprLogDelegate(IntPtr fileStringPtr, Int32 line, UInt64 threadId, IntPtr severityStringPtr, IntPtr msgPtr);
+ internal delegate void GprLogDelegate(IntPtr fileStringPtr, int line, ulong threadId, IntPtr severityStringPtr, IntPtr msgPtr);
/// <summary>
/// Logs from gRPC C core library can get lost if your application is not a console app.
@@ -73,7 +73,7 @@ namespace Grpc.Core.Internal
}
}
- private static void HandleWrite(IntPtr fileStringPtr, Int32 line, UInt64 threadId, IntPtr severityStringPtr, IntPtr msgPtr)
+ private static void HandleWrite(IntPtr fileStringPtr, int line, ulong threadId, IntPtr severityStringPtr, IntPtr msgPtr)
{
try
{
diff --git a/src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs b/src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs
index 9e69fe2f43..f4224668f1 100644
--- a/src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs
+++ b/src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs
@@ -51,12 +51,13 @@ namespace Grpc.Core.Internal
CompletionQueueSafeHandle cq;
- public GrpcThreadPool(int poolSize) {
+ public GrpcThreadPool(int poolSize)
+ {
this.poolSize = poolSize;
}
- public void Start() {
-
+ public void Start()
+ {
lock (myLock)
{
if (cq != null)
@@ -73,8 +74,8 @@ namespace Grpc.Core.Internal
}
}
- public void Stop() {
-
+ public void Stop()
+ {
lock (myLock)
{
cq.Shutdown();
@@ -86,7 +87,6 @@ namespace Grpc.Core.Internal
}
cq.Dispose();
-
}
}
@@ -116,10 +116,9 @@ namespace Grpc.Core.Internal
do
{
completionType = cq.NextWithCallback();
- } while(completionType != GRPCCompletionType.GRPC_QUEUE_SHUTDOWN);
+ }
+ while (completionType != GRPCCompletionType.GRPC_QUEUE_SHUTDOWN);
Console.WriteLine("Completion queue has shutdown successfully, thread " + Thread.CurrentThread.Name + " exiting.");
}
}
-
}
-
diff --git a/src/csharp/Grpc.Core/Internal/MetadataArraySafeHandle.cs b/src/csharp/Grpc.Core/Internal/MetadataArraySafeHandle.cs
new file mode 100644
index 0000000000..c9c4d954c9
--- /dev/null
+++ b/src/csharp/Grpc.Core/Internal/MetadataArraySafeHandle.cs
@@ -0,0 +1,72 @@
+#region Copyright notice and license
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+using System;
+using System.Runtime.InteropServices;
+using System.Threading.Tasks;
+
+namespace Grpc.Core.Internal
+{
+ /// <summary>
+ /// grpc_metadata_array from <grpc/grpc.h>
+ /// </summary>
+ internal class MetadataArraySafeHandle : SafeHandleZeroIsInvalid
+ {
+ [DllImport("grpc_csharp_ext.dll")]
+ static extern MetadataArraySafeHandle grpcsharp_metadata_array_create(UIntPtr capacity);
+
+ [DllImport("grpc_csharp_ext.dll", CharSet = CharSet.Ansi)]
+ static extern void grpcsharp_metadata_array_add(MetadataArraySafeHandle array, string key, byte[] value, UIntPtr valueLength);
+
+ [DllImport("grpc_csharp_ext.dll")]
+ static extern void grpcsharp_metadata_array_destroy_full(IntPtr array);
+
+ private MetadataArraySafeHandle()
+ {
+ }
+
+ public static MetadataArraySafeHandle Create(Metadata metadata)
+ {
+ var entries = metadata.Entries;
+ var metadataArray = grpcsharp_metadata_array_create(new UIntPtr((ulong)entries.Count));
+ for (int i = 0; i < entries.Count; i++)
+ {
+ grpcsharp_metadata_array_add(metadataArray, entries[i].Key, entries[i].ValueBytes, new UIntPtr((ulong)entries[i].ValueBytes.Length));
+ }
+ return metadataArray;
+ }
+
+ protected override bool ReleaseHandle()
+ {
+ grpcsharp_metadata_array_destroy_full(handle);
+ return true;
+ }
+ }
+}
diff --git a/src/csharp/Grpc.Core/Internal/SafeHandleZeroIsInvalid.cs b/src/csharp/Grpc.Core/Internal/SafeHandleZeroIsInvalid.cs
index aa6fce2e96..702aea2883 100644
--- a/src/csharp/Grpc.Core/Internal/SafeHandleZeroIsInvalid.cs
+++ b/src/csharp/Grpc.Core/Internal/SafeHandleZeroIsInvalid.cs
@@ -64,4 +64,3 @@ namespace Grpc.Core.Internal
}
}
}
-
diff --git a/src/csharp/Grpc.Core/ServerCallHandler.cs b/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs
index 3eb8422f57..25fd4fab8f 100644
--- a/src/csharp/Grpc.Core/ServerCallHandler.cs
+++ b/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs
@@ -36,7 +36,7 @@ using System.Linq;
using Grpc.Core.Internal;
using Grpc.Core.Utils;
-namespace Grpc.Core
+namespace Grpc.Core.Internal
{
internal interface IServerCallHandler
{
@@ -70,7 +70,6 @@ namespace Grpc.Core
handler(request, responseObserver);
finishedTask.Wait();
-
}
}
@@ -93,7 +92,7 @@ namespace Grpc.Core
asyncCall.Initialize(call);
- var responseObserver = new ServerStreamingOutputObserver<TRequest,TResponse>(asyncCall);
+ var responseObserver = new ServerStreamingOutputObserver<TRequest, TResponse>(asyncCall);
var requestObserver = handler(responseObserver);
var finishedTask = asyncCall.ServerSideCallAsync(requestObserver);
finishedTask.Wait();
@@ -113,7 +112,7 @@ namespace Grpc.Core
var finishedTask = asyncCall.ServerSideCallAsync(new NullObserver<byte[]>());
// TODO: check result of the completion status.
- asyncCall.StartSendStatusFromServer(new Status(StatusCode.Unimplemented, "No such method."), new AsyncCompletionDelegate((error) => {}));
+ asyncCall.StartSendStatusFromServer(new Status(StatusCode.Unimplemented, "No such method."), new AsyncCompletionDelegate((error) => { }));
finishedTask.Wait();
}
@@ -132,7 +131,5 @@ namespace Grpc.Core
public void OnNext(T value)
{
}
-
}
}
-
diff --git a/src/csharp/Grpc.Core/Internal/ServerCredentialsSafeHandle.cs b/src/csharp/Grpc.Core/Internal/ServerCredentialsSafeHandle.cs
new file mode 100644
index 0000000000..961180741a
--- /dev/null
+++ b/src/csharp/Grpc.Core/Internal/ServerCredentialsSafeHandle.cs
@@ -0,0 +1,68 @@
+#region Copyright notice and license
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+using System;
+using System.Runtime.InteropServices;
+using System.Threading;
+using System.Threading.Tasks;
+using Grpc.Core.Utils;
+
+namespace Grpc.Core.Internal
+{
+ /// <summary>
+ /// grpc_server_credentials from <grpc/grpc_security.h>
+ /// </summary>
+ internal class ServerCredentialsSafeHandle : SafeHandleZeroIsInvalid
+ {
+ [DllImport("grpc_csharp_ext.dll", CharSet = CharSet.Ansi)]
+ static extern ServerCredentialsSafeHandle grpcsharp_ssl_server_credentials_create(string pemRootCerts, string[] keyCertPairCertChainArray, string[] keyCertPairPrivateKeyArray, UIntPtr numKeyCertPairs);
+
+ [DllImport("grpc_csharp_ext.dll")]
+ static extern void grpcsharp_server_credentials_release(IntPtr credentials);
+
+ private ServerCredentialsSafeHandle()
+ {
+ }
+
+ public static ServerCredentialsSafeHandle CreateSslCredentials(string[] keyCertPairCertChainArray, string[] keyCertPairPrivateKeyArray)
+ {
+ Preconditions.CheckArgument(keyCertPairCertChainArray.Length == keyCertPairPrivateKeyArray.Length);
+ return grpcsharp_ssl_server_credentials_create(null,
+ keyCertPairCertChainArray, keyCertPairPrivateKeyArray,
+ new UIntPtr((ulong)keyCertPairCertChainArray.Length));
+ }
+
+ protected override bool ReleaseHandle()
+ {
+ grpcsharp_server_credentials_release(handle);
+ return true;
+ }
+ }
+}
diff --git a/src/csharp/Grpc.Core/Internal/ServerSafeHandle.cs b/src/csharp/Grpc.Core/Internal/ServerSafeHandle.cs
index de9bbaf7c1..a59da09822 100644
--- a/src/csharp/Grpc.Core/Internal/ServerSafeHandle.cs
+++ b/src/csharp/Grpc.Core/Internal/ServerSafeHandle.cs
@@ -53,7 +53,10 @@ namespace Grpc.Core.Internal
static extern ServerSafeHandle grpcsharp_server_create(CompletionQueueSafeHandle cq, IntPtr args);
[DllImport("grpc_csharp_ext.dll")]
- static extern Int32 grpcsharp_server_add_http2_port(ServerSafeHandle server, string addr);
+ static extern int grpcsharp_server_add_http2_port(ServerSafeHandle server, string addr);
+
+ [DllImport("grpc_csharp_ext.dll")]
+ static extern int grpcsharp_server_add_secure_http2_port(ServerSafeHandle server, string addr, ServerCredentialsSafeHandle creds);
[DllImport("grpc_csharp_ext.dll")]
static extern void grpcsharp_server_start(ServerSafeHandle server);
@@ -74,15 +77,19 @@ namespace Grpc.Core.Internal
public static ServerSafeHandle NewServer(CompletionQueueSafeHandle cq, IntPtr args)
{
- // TODO: also grpc_secure_server_create...
return grpcsharp_server_create(cq, args);
}
- public int AddPort(string addr)
+ public int AddListeningPort(string addr)
{
return grpcsharp_server_add_http2_port(this, addr);
}
+ public int AddListeningPort(string addr, ServerCredentialsSafeHandle credentials)
+ {
+ return grpcsharp_server_add_secure_http2_port(this, addr, credentials);
+ }
+
public void Start()
{
grpcsharp_server_start(this);
diff --git a/src/csharp/Grpc.Core/Internal/ServerStreamingOutputObserver.cs b/src/csharp/Grpc.Core/Internal/ServerStreamingOutputObserver.cs
index 9873dc9c71..97b62d0569 100644
--- a/src/csharp/Grpc.Core/Internal/ServerStreamingOutputObserver.cs
+++ b/src/csharp/Grpc.Core/Internal/ServerStreamingOutputObserver.cs
@@ -69,4 +69,3 @@ namespace Grpc.Core.Internal
}
}
}
-
diff --git a/src/csharp/Grpc.Core/Internal/Timespec.cs b/src/csharp/Grpc.Core/Internal/Timespec.cs
index e6efd66f13..94d48c2c49 100644
--- a/src/csharp/Grpc.Core/Internal/Timespec.cs
+++ b/src/csharp/Grpc.Core/Internal/Timespec.cs
@@ -40,8 +40,8 @@ namespace Grpc.Core.Internal
[StructLayout(LayoutKind.Sequential)]
internal struct Timespec
{
- const int nanosPerSecond = 1000 * 1000 * 1000;
- const int nanosPerTick = 100;
+ const int NanosPerSecond = 1000 * 1000 * 1000;
+ const int NanosPerTick = 100;
[DllImport("grpc_csharp_ext.dll")]
static extern Timespec gprsharp_now();
@@ -99,14 +99,13 @@ namespace Grpc.Core.Internal
public Timespec Add(TimeSpan timeSpan)
{
- long nanos = tv_nsec.ToInt64() + (timeSpan.Ticks % TimeSpan.TicksPerSecond) * nanosPerTick;
- long overflow_sec = (nanos > nanosPerSecond) ? 1 : 0;
+ long nanos = tv_nsec.ToInt64() + (timeSpan.Ticks % TimeSpan.TicksPerSecond) * NanosPerTick;
+ long overflow_sec = (nanos > NanosPerSecond) ? 1 : 0;
Timespec result;
- result.tv_nsec = new IntPtr(nanos % nanosPerSecond);
+ result.tv_nsec = new IntPtr(nanos % NanosPerSecond);
result.tv_sec = new IntPtr(tv_sec.ToInt64() + (timeSpan.Ticks / TimeSpan.TicksPerSecond) + overflow_sec);
return result;
}
}
}
-
diff --git a/src/csharp/Grpc.Core/Marshaller.cs b/src/csharp/Grpc.Core/Marshaller.cs
index 602e0eb824..8b1a929074 100644
--- a/src/csharp/Grpc.Core/Marshaller.cs
+++ b/src/csharp/Grpc.Core/Marshaller.cs
@@ -32,6 +32,7 @@
#endregion
using System;
+using Grpc.Core.Utils;
namespace Grpc.Core
{
@@ -40,13 +41,13 @@ namespace Grpc.Core
/// </summary>
public struct Marshaller<T>
{
- readonly Func<T,byte[]> serializer;
- readonly Func<byte[],T> deserializer;
+ readonly Func<T, byte[]> serializer;
+ readonly Func<byte[], T> deserializer;
public Marshaller(Func<T, byte[]> serializer, Func<byte[], T> deserializer)
{
- this.serializer = serializer;
- this.deserializer = deserializer;
+ this.serializer = Preconditions.CheckNotNull(serializer);
+ this.deserializer = Preconditions.CheckNotNull(deserializer);
}
public Func<T, byte[]> Serializer
@@ -66,9 +67,12 @@ namespace Grpc.Core
}
}
- public static class Marshallers {
-
- public static Marshaller<T> Create<T>(Func<T,byte[]> serializer, Func<byte[],T> deserializer)
+ /// <summary>
+ /// Utilities for creating marshallers.
+ /// </summary>
+ public static class Marshallers
+ {
+ public static Marshaller<T> Create<T>(Func<T, byte[]> serializer, Func<byte[], T> deserializer)
{
return new Marshaller<T>(serializer, deserializer);
}
@@ -81,7 +85,5 @@ namespace Grpc.Core
System.Text.Encoding.UTF8.GetString);
}
}
-
}
}
-
diff --git a/src/csharp/Grpc.Core/Metadata.cs b/src/csharp/Grpc.Core/Metadata.cs
new file mode 100644
index 0000000000..eccec26a61
--- /dev/null
+++ b/src/csharp/Grpc.Core/Metadata.cs
@@ -0,0 +1,126 @@
+#region Copyright notice and license
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.Runtime.InteropServices;
+using System.Text;
+
+namespace Grpc.Core
+{
+ /// <summary>
+ /// gRPC call metadata.
+ /// </summary>
+ public class Metadata
+ {
+ public static readonly Metadata Empty = new Metadata(ImmutableList<MetadataEntry>.Empty);
+
+ readonly ImmutableList<MetadataEntry> entries;
+
+ public Metadata(ImmutableList<MetadataEntry> entries)
+ {
+ this.entries = entries;
+ }
+
+ public ImmutableList<MetadataEntry> Entries
+ {
+ get
+ {
+ return this.entries;
+ }
+ }
+
+ public static Builder CreateBuilder()
+ {
+ return new Builder();
+ }
+
+ public struct MetadataEntry
+ {
+ readonly string key;
+ readonly byte[] valueBytes;
+
+ public MetadataEntry(string key, byte[] valueBytes)
+ {
+ this.key = key;
+ this.valueBytes = valueBytes;
+ }
+
+ public MetadataEntry(string key, string value)
+ {
+ this.key = key;
+ this.valueBytes = Encoding.ASCII.GetBytes(value);
+ }
+
+ public string Key
+ {
+ get
+ {
+ return this.key;
+ }
+ }
+
+ // TODO: using ByteString would guarantee immutability.
+ public byte[] ValueBytes
+ {
+ get
+ {
+ return this.valueBytes;
+ }
+ }
+ }
+
+ public class Builder
+ {
+ readonly List<Metadata.MetadataEntry> entries = new List<Metadata.MetadataEntry>();
+
+ public List<MetadataEntry> Entries
+ {
+ get
+ {
+ return entries;
+ }
+ }
+
+ public Builder Add(MetadataEntry entry)
+ {
+ entries.Add(entry);
+ return this;
+ }
+
+ public Metadata Build()
+ {
+ return new Metadata(entries.ToImmutableList());
+ }
+ }
+ }
+}
diff --git a/src/csharp/Grpc.Core/Method.cs b/src/csharp/Grpc.Core/Method.cs
index c94aa8161f..4f97eeef37 100644
--- a/src/csharp/Grpc.Core/Method.cs
+++ b/src/csharp/Grpc.Core/Method.cs
@@ -94,4 +94,3 @@ namespace Grpc.Core
}
}
}
-
diff --git a/src/csharp/Grpc.Core/OperationFailedException.cs b/src/csharp/Grpc.Core/OperationFailedException.cs
index 34a8c95a85..9b1c24d0c1 100644
--- a/src/csharp/Grpc.Core/OperationFailedException.cs
+++ b/src/csharp/Grpc.Core/OperationFailedException.cs
@@ -45,4 +45,3 @@ namespace Grpc.Core
}
}
}
-
diff --git a/src/csharp/Grpc.Core/Properties/AssemblyInfo.cs b/src/csharp/Grpc.Core/Properties/AssemblyInfo.cs
index 37ba1e2263..168939cf8c 100644
--- a/src/csharp/Grpc.Core/Properties/AssemblyInfo.cs
+++ b/src/csharp/Grpc.Core/Properties/AssemblyInfo.cs
@@ -1,24 +1,14 @@
using System.Reflection;
using System.Runtime.CompilerServices;
-// Information about this assembly is defined by the following attributes.
-// Change them to the values specific to your project.
-[assembly: AssemblyTitle ("Grpc.Core")]
-[assembly: AssemblyDescription ("")]
-[assembly: AssemblyConfiguration ("")]
-[assembly: AssemblyCompany ("")]
-[assembly: AssemblyProduct ("")]
-[assembly: AssemblyCopyright ("Google Inc. All rights reserved.")]
-[assembly: AssemblyTrademark ("")]
-[assembly: AssemblyCulture ("")]
-// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
-// The form "{Major}.{Minor}.*" will automatically update the build and revision,
-// and "{Major}.{Minor}.{Build}.*" will update just the revision.
-[assembly: AssemblyVersion ("0.1.*")]
-// The following attributes are used to specify the signing key for the assembly,
-// if desired. See the Mono documentation for more information about signing.
-//[assembly: AssemblyDelaySign(false)]
-//[assembly: AssemblyKeyFile("")]
+[assembly: AssemblyTitle("Grpc.Core")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("")]
+[assembly: AssemblyCopyright("Google Inc. All rights reserved.")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+[assembly: AssemblyVersion("0.1.*")]
[assembly: InternalsVisibleTo("Grpc.Core.Tests")]
-
diff --git a/src/csharp/Grpc.Core/RpcException.cs b/src/csharp/Grpc.Core/RpcException.cs
index e1cf64ca56..433d87215e 100644
--- a/src/csharp/Grpc.Core/RpcException.cs
+++ b/src/csharp/Grpc.Core/RpcException.cs
@@ -35,6 +35,9 @@ using System;
namespace Grpc.Core
{
+ /// <summary>
+ /// Thrown when remote procedure call fails.
+ /// </summary>
public class RpcException : Exception
{
private readonly Status status;
@@ -58,4 +61,3 @@ namespace Grpc.Core
}
}
}
-
diff --git a/src/csharp/Grpc.Core/Server.cs b/src/csharp/Grpc.Core/Server.cs
index 152cc2176c..f086fa8beb 100644
--- a/src/csharp/Grpc.Core/Server.cs
+++ b/src/csharp/Grpc.Core/Server.cs
@@ -67,16 +67,27 @@ namespace Grpc.Core
}
// only call this before Start()
- public void AddServiceDefinition(ServerServiceDefinition serviceDefinition) {
- foreach(var entry in serviceDefinition.CallHandlers)
+ public void AddServiceDefinition(ServerServiceDefinition serviceDefinition)
+ {
+ foreach (var entry in serviceDefinition.CallHandlers)
{
callHandlers.Add(entry.Key, entry.Value);
}
}
// only call before Start()
- public int AddPort(string addr) {
- return handle.AddPort(addr);
+ public int AddListeningPort(string addr)
+ {
+ return handle.AddListeningPort(addr);
+ }
+
+ // only call before Start()
+ public int AddListeningPort(string addr, ServerCredentials credentials)
+ {
+ using (var nativeCredentials = credentials.ToNativeCredentials())
+ {
+ return handle.AddListeningPort(addr, nativeCredentials);
+ }
}
public void Start()
@@ -98,7 +109,7 @@ namespace Grpc.Core
{
var rpcInfo = newRpcQueue.Take();
- //Console.WriteLine("Server received RPC " + rpcInfo.Method);
+ // Console.WriteLine("Server received RPC " + rpcInfo.Method);
IServerCallHandler callHandler;
if (!callHandlers.TryGetValue(rpcInfo.Method, out callHandler))
@@ -107,7 +118,7 @@ namespace Grpc.Core
}
callHandler.StartCall(rpcInfo.Method, rpcInfo.Call, GetCompletionQueue());
}
- catch(Exception e)
+ catch (Exception e)
{
Console.WriteLine("Exception while handling RPC: " + e);
}
@@ -118,7 +129,8 @@ namespace Grpc.Core
/// cleans up used resources.
/// </summary>
/// <returns>The async.</returns>
- public async Task ShutdownAsync() {
+ public async Task ShutdownAsync()
+ {
handle.ShutdownAndNotify(serverShutdownHandler);
await shutdownTcs.Task;
handle.Dispose();
@@ -135,11 +147,13 @@ namespace Grpc.Core
}
}
- public void Kill() {
+ public void Kill()
+ {
handle.Dispose();
}
- private async Task StartHandlingRpcs() {
+ private async Task StartHandlingRpcs()
+ {
while (true)
{
await Task.Factory.StartNew(RunRpc);
@@ -151,22 +165,27 @@ namespace Grpc.Core
AssertCallOk(handle.RequestCall(GetCompletionQueue(), newServerRpcHandler));
}
- private void HandleNewServerRpc(GRPCOpError error, IntPtr batchContextPtr) {
- try {
+ private void HandleNewServerRpc(GRPCOpError error, IntPtr batchContextPtr)
+ {
+ try
+ {
var ctx = new BatchContextSafeHandleNotOwned(batchContextPtr);
- if (error != GRPCOpError.GRPC_OP_OK) {
+ if (error != GRPCOpError.GRPC_OP_OK)
+ {
// TODO: handle error
}
var rpcInfo = new NewRpcInfo(ctx.GetServerRpcNewCall(), ctx.GetServerRpcNewMethod());
// after server shutdown, the callback returns with null call
- if (!rpcInfo.Call.IsInvalid) {
+ if (!rpcInfo.Call.IsInvalid)
+ {
newRpcQueue.Add(rpcInfo);
}
-
- } catch(Exception e) {
+ }
+ catch (Exception e)
+ {
Console.WriteLine("Caught exception in a native handler: " + e);
}
}
diff --git a/src/csharp/Grpc.Core/ServerCalls.cs b/src/csharp/Grpc.Core/ServerCalls.cs
index bed77796de..dcae99446f 100644
--- a/src/csharp/Grpc.Core/ServerCalls.cs
+++ b/src/csharp/Grpc.Core/ServerCalls.cs
@@ -32,17 +32,18 @@
#endregion
using System;
+using Grpc.Core.Internal;
namespace Grpc.Core
{
// TODO: perhaps add also serverSideStreaming and clientSideStreaming
- public delegate void UnaryRequestServerMethod<TRequest, TResponse> (TRequest request, IObserver<TResponse> responseObserver);
+ public delegate void UnaryRequestServerMethod<TRequest, TResponse>(TRequest request, IObserver<TResponse> responseObserver);
- public delegate IObserver<TRequest> StreamingRequestServerMethod<TRequest, TResponse> (IObserver<TResponse> responseObserver);
-
- internal static class ServerCalls {
+ public delegate IObserver<TRequest> StreamingRequestServerMethod<TRequest, TResponse>(IObserver<TResponse> responseObserver);
+ internal static class ServerCalls
+ {
public static IServerCallHandler UnaryRequestCall<TRequest, TResponse>(Method<TRequest, TResponse> method, UnaryRequestServerMethod<TRequest, TResponse> handler)
{
return new UnaryRequestServerCallHandler<TRequest, TResponse>(method, handler);
@@ -52,7 +53,5 @@ namespace Grpc.Core
{
return new StreamingRequestServerCallHandler<TRequest, TResponse>(method, handler);
}
-
}
}
-
diff --git a/src/csharp/Grpc.Core/ServerCredentials.cs b/src/csharp/Grpc.Core/ServerCredentials.cs
new file mode 100644
index 0000000000..ab7d0b4914
--- /dev/null
+++ b/src/csharp/Grpc.Core/ServerCredentials.cs
@@ -0,0 +1,109 @@
+#region Copyright notice and license
+
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using Grpc.Core.Internal;
+
+namespace Grpc.Core
+{
+ /// <summary>
+ /// Server side credentials.
+ /// </summary>
+ public abstract class ServerCredentials
+ {
+ /// <summary>
+ /// Creates native object for the credentials.
+ /// </summary>
+ /// <returns>The native credentials.</returns>
+ internal abstract ServerCredentialsSafeHandle ToNativeCredentials();
+ }
+
+ /// <summary>
+ /// Key certificate pair (in PEM encoding).
+ /// </summary>
+ public class KeyCertificatePair
+ {
+ readonly string certChain;
+ readonly string privateKey;
+
+ public KeyCertificatePair(string certChain, string privateKey)
+ {
+ this.certChain = certChain;
+ this.privateKey = privateKey;
+ }
+
+ public string CertChain
+ {
+ get
+ {
+ return certChain;
+ }
+ }
+
+ public string PrivateKey
+ {
+ get
+ {
+ return privateKey;
+ }
+ }
+ }
+
+ /// <summary>
+ /// Server-side SSL credentials.
+ /// </summary>
+ public class SslServerCredentials : ServerCredentials
+ {
+ ImmutableList<KeyCertificatePair> keyCertPairs;
+
+ public SslServerCredentials(ImmutableList<KeyCertificatePair> keyCertPairs)
+ {
+ this.keyCertPairs = keyCertPairs;
+ }
+
+ internal override ServerCredentialsSafeHandle ToNativeCredentials()
+ {
+ int count = keyCertPairs.Count;
+ string[] certChains = new string[count];
+ string[] keys = new string[count];
+ for (int i = 0; i < count; i++)
+ {
+ certChains[i] = keyCertPairs[i].CertChain;
+ keys[i] = keyCertPairs[i].PrivateKey;
+ }
+ return ServerCredentialsSafeHandle.CreateSslCredentials(certChains, keys);
+ }
+ }
+}
diff --git a/src/csharp/Grpc.Core/ServerServiceDefinition.cs b/src/csharp/Grpc.Core/ServerServiceDefinition.cs
index 231c376062..f08c7d88f3 100644
--- a/src/csharp/Grpc.Core/ServerServiceDefinition.cs
+++ b/src/csharp/Grpc.Core/ServerServiceDefinition.cs
@@ -33,22 +33,24 @@
using System;
using System.Collections.Generic;
+using System.Collections.Immutable;
+using Grpc.Core.Internal;
namespace Grpc.Core
{
+ /// <summary>
+ /// Mapping of method names to server call handlers.
+ /// </summary>
public class ServerServiceDefinition
{
- readonly string serviceName;
- // TODO: we would need an immutable dictionary here...
- readonly Dictionary<string, IServerCallHandler> callHandlers;
+ readonly ImmutableDictionary<string, IServerCallHandler> callHandlers;
- private ServerServiceDefinition(string serviceName, Dictionary<string, IServerCallHandler> callHandlers)
+ private ServerServiceDefinition(ImmutableDictionary<string, IServerCallHandler> callHandlers)
{
- this.serviceName = serviceName;
- this.callHandlers = new Dictionary<string, IServerCallHandler>(callHandlers);
+ this.callHandlers = callHandlers;
}
- internal Dictionary<string, IServerCallHandler> CallHandlers
+ internal ImmutableDictionary<string, IServerCallHandler> CallHandlers
{
get
{
@@ -56,8 +58,7 @@ namespace Grpc.Core
}
}
-
- public static Builder CreateBuilder(String serviceName)
+ public static Builder CreateBuilder(string serviceName)
{
return new Builder(serviceName);
}
@@ -65,7 +66,7 @@ namespace Grpc.Core
public class Builder
{
readonly string serviceName;
- readonly Dictionary<string, IServerCallHandler> callHandlers = new Dictionary<String, IServerCallHandler>();
+ readonly Dictionary<string, IServerCallHandler> callHandlers = new Dictionary<string, IServerCallHandler>();
public Builder(string serviceName)
{
@@ -76,7 +77,7 @@ namespace Grpc.Core
Method<TRequest, TResponse> method,
UnaryRequestServerMethod<TRequest, TResponse> handler)
{
- callHandlers.Add(method.Name, ServerCalls.UnaryRequestCall(method, handler));
+ callHandlers.Add(GetFullMethodName(serviceName, method.Name), ServerCalls.UnaryRequestCall(method, handler));
return this;
}
@@ -84,15 +85,19 @@ namespace Grpc.Core
Method<TRequest, TResponse> method,
StreamingRequestServerMethod<TRequest, TResponse> handler)
{
- callHandlers.Add(method.Name, ServerCalls.StreamingRequestCall(method, handler));
+ callHandlers.Add(GetFullMethodName(serviceName, method.Name), ServerCalls.StreamingRequestCall(method, handler));
return this;
}
public ServerServiceDefinition Build()
{
- return new ServerServiceDefinition(serviceName, callHandlers);
+ return new ServerServiceDefinition(callHandlers.ToImmutableDictionary());
+ }
+
+ private string GetFullMethodName(string serviceName, string methodName)
+ {
+ return serviceName + "/" + methodName;
}
}
}
}
-
diff --git a/src/csharp/Grpc.Core/StatusCode.cs b/src/csharp/Grpc.Core/StatusCode.cs
index 1987e52789..a9696fa469 100644
--- a/src/csharp/Grpc.Core/StatusCode.cs
+++ b/src/csharp/Grpc.Core/StatusCode.cs
@@ -35,9 +35,9 @@ using System;
namespace Grpc.Core
{
- // TODO: element names should changed to comply with C# naming conventions.
/// <summary>
- /// based on grpc_status_code from grpc/status.h
+ /// Result of a remote procedure call.
+ /// Based on grpc_status_code from grpc/status.h
/// </summary>
public enum StatusCode
{
@@ -139,4 +139,3 @@ namespace Grpc.Core
DataLoss = 15
}
}
-
diff --git a/src/csharp/Grpc.Core/Stub/AbstractStub.cs b/src/csharp/Grpc.Core/Stub/AbstractStub.cs
new file mode 100644
index 0000000000..cf5ab958c5
--- /dev/null
+++ b/src/csharp/Grpc.Core/Stub/AbstractStub.cs
@@ -0,0 +1,73 @@
+#region Copyright notice and license
+
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#endregion
+
+using System;
+using Grpc.Core.Internal;
+
+namespace Grpc.Core
+{
+ // TODO: support adding timeout to methods.
+ /// <summary>
+ /// Base for client-side stubs.
+ /// </summary>
+ public abstract class AbstractStub<TStub, TConfig>
+ where TConfig : StubConfiguration
+ {
+ readonly Channel channel;
+ readonly TConfig config;
+
+ public AbstractStub(Channel channel, TConfig config)
+ {
+ this.channel = channel;
+ this.config = config;
+ }
+
+ public Channel Channel
+ {
+ get
+ {
+ return this.channel;
+ }
+ }
+
+ /// <summary>
+ /// Creates a new call to given method.
+ /// </summary>
+ protected Call<TRequest, TResponse> CreateCall<TRequest, TResponse>(string serviceName, Method<TRequest, TResponse> method)
+ {
+ var headerBuilder = Metadata.CreateBuilder();
+ config.HeaderInterceptor(headerBuilder);
+ return new Call<TRequest, TResponse>(serviceName, method, channel, headerBuilder.Build());
+ }
+ }
+}
diff --git a/src/csharp/Grpc.Core/Stub/StubConfiguration.cs b/src/csharp/Grpc.Core/Stub/StubConfiguration.cs
new file mode 100644
index 0000000000..5bcb5b40d2
--- /dev/null
+++ b/src/csharp/Grpc.Core/Stub/StubConfiguration.cs
@@ -0,0 +1,64 @@
+#region Copyright notice and license
+
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#endregion
+
+using System;
+using Grpc.Core.Internal;
+using Grpc.Core.Utils;
+
+namespace Grpc.Core
+{
+ public delegate void HeaderInterceptorDelegate(Metadata.Builder headerBuilder);
+
+ public class StubConfiguration
+ {
+ /// <summary>
+ /// The default stub configuration.
+ /// </summary>
+ public static readonly StubConfiguration Default = new StubConfiguration((headerBuilder) => { });
+
+ readonly HeaderInterceptorDelegate headerInterceptor;
+
+ public StubConfiguration(HeaderInterceptorDelegate headerInterceptor)
+ {
+ this.headerInterceptor = Preconditions.CheckNotNull(headerInterceptor);
+ }
+
+ public HeaderInterceptorDelegate HeaderInterceptor
+ {
+ get
+ {
+ return headerInterceptor;
+ }
+ }
+ }
+}
diff --git a/src/csharp/Grpc.Core/Utils/BenchmarkUtil.cs b/src/csharp/Grpc.Core/Utils/BenchmarkUtil.cs
index 3f0dae84cf..4180d98938 100644
--- a/src/csharp/Grpc.Core/Utils/BenchmarkUtil.cs
+++ b/src/csharp/Grpc.Core/Utils/BenchmarkUtil.cs
@@ -32,10 +32,10 @@
#endregion
using System;
-using System.Threading.Tasks;
-using System.Collections.Generic;
using System.Collections.Concurrent;
+using System.Collections.Generic;
using System.Diagnostics;
+using System.Threading.Tasks;
namespace Grpc.Core.Utils
{
@@ -61,8 +61,7 @@ namespace Grpc.Core.Utils
}
stopwatch.Stop();
Console.WriteLine("Elapsed time: " + stopwatch.ElapsedMilliseconds + "ms");
- Console.WriteLine("Ops per second: " + (int) ((double) benchmarkIterations * 1000 / stopwatch.ElapsedMilliseconds));
+ Console.WriteLine("Ops per second: " + (int)((double)benchmarkIterations * 1000 / stopwatch.ElapsedMilliseconds));
}
}
}
-
diff --git a/src/csharp/Grpc.Core/Utils/ExceptionHelper.cs b/src/csharp/Grpc.Core/Utils/ExceptionHelper.cs
index 18702e1cc4..c4d6bee058 100644
--- a/src/csharp/Grpc.Core/Utils/ExceptionHelper.cs
+++ b/src/csharp/Grpc.Core/Utils/ExceptionHelper.cs
@@ -42,7 +42,8 @@ namespace Grpc.Core.Utils
/// Otherwise, rethrows the original aggregate exception.
/// Always throws, the exception return type is here only to make the.
/// </summary>
- public static Exception UnwrapRpcException(AggregateException ae) {
+ public static Exception UnwrapRpcException(AggregateException ae)
+ {
foreach (var e in ae.InnerExceptions)
{
if (e is RpcException)
@@ -54,4 +55,3 @@ namespace Grpc.Core.Utils
}
}
}
-
diff --git a/src/csharp/Grpc.Core/Utils/Preconditions.cs b/src/csharp/Grpc.Core/Utils/Preconditions.cs
index b17ce42117..aeb5d210a7 100644
--- a/src/csharp/Grpc.Core/Utils/Preconditions.cs
+++ b/src/csharp/Grpc.Core/Utils/Preconditions.cs
@@ -32,10 +32,10 @@
#endregion
using System;
-using System.Threading.Tasks;
-using System.Collections.Generic;
using System.Collections.Concurrent;
+using System.Collections.Generic;
using System.Diagnostics;
+using System.Threading.Tasks;
namespace Grpc.Core.Utils
{
@@ -66,7 +66,7 @@ namespace Grpc.Core.Utils
/// <summary>
/// Throws NullReferenceException if reference is null.
/// </summary>
- public static T CheckNotNull<T> (T reference)
+ public static T CheckNotNull<T>(T reference)
{
if (reference == null)
{
@@ -78,7 +78,7 @@ namespace Grpc.Core.Utils
/// <summary>
/// Throws NullReferenceException with given message if reference is null.
/// </summary>
- public static T CheckNotNull<T> (T reference, string errorMessage)
+ public static T CheckNotNull<T>(T reference, string errorMessage)
{
if (reference == null)
{
@@ -110,4 +110,3 @@ namespace Grpc.Core.Utils
}
}
}
-
diff --git a/src/csharp/Grpc.Core/Utils/RecordingObserver.cs b/src/csharp/Grpc.Core/Utils/RecordingObserver.cs
index 99d2725b70..7b43ab8ad5 100644
--- a/src/csharp/Grpc.Core/Utils/RecordingObserver.cs
+++ b/src/csharp/Grpc.Core/Utils/RecordingObserver.cs
@@ -57,9 +57,9 @@ namespace Grpc.Core.Utils
data.Add(value);
}
- public Task<List<T>> ToList() {
+ public Task<List<T>> ToList()
+ {
return tcs.Task;
}
}
}
-
diff --git a/src/csharp/Grpc.Core/Utils/RecordingQueue.cs b/src/csharp/Grpc.Core/Utils/RecordingQueue.cs
index 63992da6a9..9749168af0 100644
--- a/src/csharp/Grpc.Core/Utils/RecordingQueue.cs
+++ b/src/csharp/Grpc.Core/Utils/RecordingQueue.cs
@@ -32,9 +32,9 @@
#endregion
using System;
-using System.Threading.Tasks;
-using System.Collections.Generic;
using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Threading.Tasks;
namespace Grpc.Core.Utils
{
@@ -81,4 +81,3 @@ namespace Grpc.Core.Utils
}
}
}
-
diff --git a/src/csharp/Grpc.Core/packages.config b/src/csharp/Grpc.Core/packages.config
new file mode 100644
index 0000000000..cf711ac362
--- /dev/null
+++ b/src/csharp/Grpc.Core/packages.config
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+ <package id="System.Collections.Immutable" version="1.1.34-rc" targetFramework="net45" />
+</packages> \ No newline at end of file
diff --git a/src/csharp/Grpc.Examples.MathClient/Properties/AssemblyInfo.cs b/src/csharp/Grpc.Examples.MathClient/Properties/AssemblyInfo.cs
index bdd7189db2..11fc099a95 100644
--- a/src/csharp/Grpc.Examples.MathClient/Properties/AssemblyInfo.cs
+++ b/src/csharp/Grpc.Examples.MathClient/Properties/AssemblyInfo.cs
@@ -1,22 +1,12 @@
using System.Reflection;
using System.Runtime.CompilerServices;
-// Information about this assembly is defined by the following attributes.
-// Change them to the values specific to your project.
-[assembly: AssemblyTitle ("Grpc.Examples.MathClient")]
-[assembly: AssemblyDescription ("")]
-[assembly: AssemblyConfiguration ("")]
-[assembly: AssemblyCompany ("")]
-[assembly: AssemblyProduct ("")]
-[assembly: AssemblyCopyright ("Google Inc. All rights reserved.")]
-[assembly: AssemblyTrademark ("")]
-[assembly: AssemblyCulture ("")]
-// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
-// The form "{Major}.{Minor}.*" will automatically update the build and revision,
-// and "{Major}.{Minor}.{Build}.*" will update just the revision.
-[assembly: AssemblyVersion ("0.1.*")]
-// The following attributes are used to specify the signing key for the assembly,
-// if desired. See the Mono documentation for more information about signing.
-//[assembly: AssemblyDelaySign(false)]
-//[assembly: AssemblyKeyFile("")]
-
+[assembly: AssemblyTitle("Grpc.Examples.MathClient")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("")]
+[assembly: AssemblyCopyright("Google Inc. All rights reserved.")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+[assembly: AssemblyVersion("0.1.*")]
diff --git a/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs b/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs
index 767340d6f2..85f213cb39 100644
--- a/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs
+++ b/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs
@@ -58,10 +58,17 @@ namespace math.Tests
server = new Server();
server.AddServiceDefinition(MathGrpc.BindService(new MathServiceImpl()));
- int port = server.AddPort(host + ":0");
+ int port = server.AddListeningPort(host + ":0");
server.Start();
channel = new Channel(host + ":" + port);
- client = MathGrpc.NewStub(channel);
+
+ // TODO: get rid of the custom header here once we have dedicated tests
+ // for header support.
+ var stubConfig = new StubConfiguration((headerBuilder) =>
+ {
+ headerBuilder.Add(new Metadata.MetadataEntry("customHeader", "abcdef"));
+ });
+ client = MathGrpc.NewStub(channel, stubConfig);
}
[TestFixtureTearDown]
@@ -105,7 +112,7 @@ namespace math.Tests
var recorder = new RecordingObserver<Num>();
client.Fib(new FibArgs.Builder { Limit = 6 }.Build(), recorder);
- CollectionAssert.AreEqual(new List<long>{1, 1, 2, 3, 5, 8},
+ CollectionAssert.AreEqual(new List<long> { 1, 1, 2, 3, 5, 8 },
recorder.ToList().Result.ConvertAll((n) => n.Num_));
}
@@ -114,7 +121,8 @@ namespace math.Tests
public void Sum()
{
var res = client.Sum();
- foreach (var num in new long[] { 10, 20, 30 }) {
+ foreach (var num in new long[] { 10, 20, 30 })
+ {
res.Inputs.OnNext(Num.CreateBuilder().SetNum_(num).Build());
}
res.Inputs.OnCompleted();
@@ -125,7 +133,8 @@ namespace math.Tests
[Test]
public void DivMany()
{
- List<DivArgs> divArgsList = new List<DivArgs>{
+ List<DivArgs> divArgsList = new List<DivArgs>
+ {
new DivArgs.Builder { Dividend = 10, Divisor = 3 }.Build(),
new DivArgs.Builder { Dividend = 100, Divisor = 21 }.Build(),
new DivArgs.Builder { Dividend = 7, Divisor = 2 }.Build()
@@ -142,9 +151,8 @@ namespace math.Tests
var result = recorder.ToList().Result;
- CollectionAssert.AreEqual(new long[] {3, 4, 3}, result.ConvertAll((divReply) => divReply.Quotient));
- CollectionAssert.AreEqual(new long[] {1, 16, 1}, result.ConvertAll((divReply) => divReply.Remainder));
+ CollectionAssert.AreEqual(new long[] { 3, 4, 3 }, result.ConvertAll((divReply) => divReply.Quotient));
+ CollectionAssert.AreEqual(new long[] { 1, 16, 1 }, result.ConvertAll((divReply) => divReply.Remainder));
}
}
}
-
diff --git a/src/csharp/Grpc.Examples.Tests/Properties/AssemblyInfo.cs b/src/csharp/Grpc.Examples.Tests/Properties/AssemblyInfo.cs
index 44b075ac0a..43c7616ac3 100644
--- a/src/csharp/Grpc.Examples.Tests/Properties/AssemblyInfo.cs
+++ b/src/csharp/Grpc.Examples.Tests/Properties/AssemblyInfo.cs
@@ -1,8 +1,6 @@
using System.Reflection;
using System.Runtime.CompilerServices;
-// Information about this assembly is defined by the following attributes.
-// Change them to the values specific to your project.
[assembly: AssemblyTitle("Grpc.Examples.Tests")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
@@ -11,12 +9,4 @@ using System.Runtime.CompilerServices;
[assembly: AssemblyCopyright("Google Inc. All rights reserved.")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
-// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
-// The form "{Major}.{Minor}.*" will automatically update the build and revision,
-// and "{Major}.{Minor}.{Build}.*" will update just the revision.
[assembly: AssemblyVersion("0.1.*")]
-// The following attributes are used to specify the signing key for the assembly,
-// if desired. See the Mono documentation for more information about signing.
-//[assembly: AssemblyDelaySign(false)]
-//[assembly: AssemblyKeyFile("")]
-
diff --git a/src/csharp/Grpc.Examples/MathExamples.cs b/src/csharp/Grpc.Examples/MathExamples.cs
index 134270f6f7..b8bb7eacbd 100644
--- a/src/csharp/Grpc.Examples/MathExamples.cs
+++ b/src/csharp/Grpc.Examples/MathExamples.cs
@@ -71,7 +71,8 @@ namespace math
public static void SumExample(MathGrpc.IMathServiceClient stub)
{
List<Num> numbers = new List<Num>
- {new Num.Builder { Num_ = 1 }.Build(),
+ {
+ new Num.Builder { Num_ = 1 }.Build(),
new Num.Builder { Num_ = 2 }.Build(),
new Num.Builder { Num_ = 3 }.Build()
};
@@ -110,24 +111,12 @@ namespace math
public static void DependendRequestsExample(MathGrpc.IMathServiceClient stub)
{
var numberList = new List<Num>
- { new Num.Builder{ Num_ = 1 }.Build(),
- new Num.Builder{ Num_ = 2 }.Build(), new Num.Builder{ Num_ = 3 }.Build()
+ {
+ new Num.Builder { Num_ = 1 }.Build(),
+ new Num.Builder { Num_ = 2 }.Build(), new Num.Builder { Num_ = 3 }.Build()
};
numberList.ToObservable();
-
- //IObserver<Num> numbers;
- //Task<Num> call = stub.Sum(out numbers);
- //foreach (var num in numberList)
- //{
- // numbers.OnNext(num);
- //}
- //numbers.OnCompleted();
-
- //Num sum = call.Result;
-
- //DivReply result = stub.Div(new DivArgs.Builder { Dividend = sum.Num_, Divisor = numberList.Count }.Build());
}
}
}
-
diff --git a/src/csharp/Grpc.Examples/MathGrpc.cs b/src/csharp/Grpc.Examples/MathGrpc.cs
index f938a24543..24e6a1de8e 100644
--- a/src/csharp/Grpc.Examples/MathGrpc.cs
+++ b/src/csharp/Grpc.Examples/MathGrpc.cs
@@ -45,35 +45,36 @@ namespace math
/// </summary>
public class MathGrpc
{
- readonly static Marshaller<DivArgs> divArgsMarshaller = Marshallers.Create((arg) => arg.ToByteArray(), DivArgs.ParseFrom);
- readonly static Marshaller<DivReply> divReplyMarshaller = Marshallers.Create((arg) => arg.ToByteArray(), DivReply.ParseFrom);
- readonly static Marshaller<Num> numMarshaller = Marshallers.Create((arg) => arg.ToByteArray(), Num.ParseFrom);
- readonly static Marshaller<FibArgs> fibArgsMarshaller = Marshallers.Create((arg) => arg.ToByteArray(), FibArgs.ParseFrom);
+ static readonly string ServiceName = "/math.Math";
- readonly static Method<DivArgs, DivReply> divMethod = new Method<DivArgs, DivReply>(
+ static readonly Marshaller<DivArgs> DivArgsMarshaller = Marshallers.Create((arg) => arg.ToByteArray(), DivArgs.ParseFrom);
+ static readonly Marshaller<DivReply> DivReplyMarshaller = Marshallers.Create((arg) => arg.ToByteArray(), DivReply.ParseFrom);
+ static readonly Marshaller<Num> NumMarshaller = Marshallers.Create((arg) => arg.ToByteArray(), Num.ParseFrom);
+ static readonly Marshaller<FibArgs> FibArgsMarshaller = Marshallers.Create((arg) => arg.ToByteArray(), FibArgs.ParseFrom);
+
+ static readonly Method<DivArgs, DivReply> DivMethod = new Method<DivArgs, DivReply>(
MethodType.Unary,
- "/math.Math/Div",
- divArgsMarshaller,
- divReplyMarshaller
- );
- readonly static Method<FibArgs, Num> fibMethod = new Method<FibArgs, Num>(
+ "Div",
+ DivArgsMarshaller,
+ DivReplyMarshaller);
+
+ static readonly Method<FibArgs, Num> FibMethod = new Method<FibArgs, Num>(
MethodType.ServerStreaming,
- "/math.Math/Fib",
- fibArgsMarshaller,
- numMarshaller
- );
- readonly static Method<Num, Num> sumMethod = new Method<Num, Num>(
+ "Fib",
+ FibArgsMarshaller,
+ NumMarshaller);
+
+ static readonly Method<Num, Num> SumMethod = new Method<Num, Num>(
MethodType.ClientStreaming,
- "/math.Math/Sum",
- numMarshaller,
- numMarshaller
- );
- readonly static Method<DivArgs, DivReply> divManyMethod = new Method<DivArgs, DivReply>(
+ "Sum",
+ NumMarshaller,
+ NumMarshaller);
+
+ static readonly Method<DivArgs, DivReply> DivManyMethod = new Method<DivArgs, DivReply>(
MethodType.DuplexStreaming,
- "/math.Math/DivMany",
- divArgsMarshaller,
- divReplyMarshaller
- );
+ "DivMany",
+ DivArgsMarshaller,
+ DivReplyMarshaller);
public interface IMathServiceClient
{
@@ -88,42 +89,43 @@ namespace math
IObserver<DivArgs> DivMany(IObserver<DivReply> responseObserver, CancellationToken token = default(CancellationToken));
}
- public class MathServiceClientStub : IMathServiceClient
+ public class MathServiceClientStub : AbstractStub<MathServiceClientStub, StubConfiguration>, IMathServiceClient
{
- readonly Channel channel;
+ public MathServiceClientStub(Channel channel) : this(channel, StubConfiguration.Default)
+ {
+ }
- public MathServiceClientStub(Channel channel)
+ public MathServiceClientStub(Channel channel, StubConfiguration config) : base(channel, config)
{
- this.channel = channel;
}
public DivReply Div(DivArgs request, CancellationToken token = default(CancellationToken))
{
- var call = new Grpc.Core.Call<DivArgs, DivReply>(divMethod, channel);
+ var call = CreateCall(ServiceName, DivMethod);
return Calls.BlockingUnaryCall(call, request, token);
}
public Task<DivReply> DivAsync(DivArgs request, CancellationToken token = default(CancellationToken))
{
- var call = new Grpc.Core.Call<DivArgs, DivReply>(divMethod, channel);
+ var call = CreateCall(ServiceName, DivMethod);
return Calls.AsyncUnaryCall(call, request, token);
}
public void Fib(FibArgs request, IObserver<Num> responseObserver, CancellationToken token = default(CancellationToken))
{
- var call = new Grpc.Core.Call<FibArgs, Num>(fibMethod, channel);
+ var call = CreateCall(ServiceName, FibMethod);
Calls.AsyncServerStreamingCall(call, request, responseObserver, token);
}
public ClientStreamingAsyncResult<Num, Num> Sum(CancellationToken token = default(CancellationToken))
{
- var call = new Grpc.Core.Call<Num, Num>(sumMethod, channel);
+ var call = CreateCall(ServiceName, SumMethod);
return Calls.AsyncClientStreamingCall(call, token);
}
public IObserver<DivArgs> DivMany(IObserver<DivReply> responseObserver, CancellationToken token = default(CancellationToken))
{
- var call = new Grpc.Core.Call<DivArgs, DivReply>(divManyMethod, channel);
+ var call = CreateCall(ServiceName, DivManyMethod);
return Calls.DuplexStreamingCall(call, responseObserver, token);
}
}
@@ -142,16 +144,21 @@ namespace math
public static ServerServiceDefinition BindService(IMathService serviceImpl)
{
- return ServerServiceDefinition.CreateBuilder("/math.Math/")
- .AddMethod(divMethod, serviceImpl.Div)
- .AddMethod(fibMethod, serviceImpl.Fib)
- .AddMethod(sumMethod, serviceImpl.Sum)
- .AddMethod(divManyMethod, serviceImpl.DivMany).Build();
+ return ServerServiceDefinition.CreateBuilder(ServiceName)
+ .AddMethod(DivMethod, serviceImpl.Div)
+ .AddMethod(FibMethod, serviceImpl.Fib)
+ .AddMethod(SumMethod, serviceImpl.Sum)
+ .AddMethod(DivManyMethod, serviceImpl.DivMany).Build();
}
public static IMathServiceClient NewStub(Channel channel)
{
return new MathServiceClientStub(channel);
}
+
+ public static IMathServiceClient NewStub(Channel channel, StubConfiguration config)
+ {
+ return new MathServiceClientStub(channel, config);
+ }
}
}
diff --git a/src/csharp/Grpc.Examples/MathServiceImpl.cs b/src/csharp/Grpc.Examples/MathServiceImpl.cs
index 76a08ce518..0b2357e0fa 100644
--- a/src/csharp/Grpc.Examples/MathServiceImpl.cs
+++ b/src/csharp/Grpc.Examples/MathServiceImpl.cs
@@ -73,8 +73,8 @@ namespace math
public IObserver<Num> Sum(IObserver<Num> responseObserver)
{
var recorder = new RecordingObserver<Num>();
- Task.Factory.StartNew(() => {
-
+ Task.Factory.StartNew(() =>
+ {
List<Num> inputs = recorder.ToList().Result;
long sum = 0;
@@ -104,7 +104,7 @@ namespace math
static IEnumerable<Num> FibInternal(long n)
{
long a = 1;
- yield return new Num.Builder { Num_=a }.Build();
+ yield return new Num.Builder { Num_ = a }.Build();
long b = 1;
for (long i = 0; i < n - 1; i++)
@@ -112,12 +112,12 @@ namespace math
long temp = a;
a = b;
b = temp + b;
- yield return new Num.Builder { Num_=a }.Build();
+ yield return new Num.Builder { Num_ = a }.Build();
}
}
- private class DivObserver : IObserver<DivArgs> {
-
+ private class DivObserver : IObserver<DivArgs>
+ {
readonly IObserver<DivReply> responseObserver;
public DivObserver(IObserver<DivReply> responseObserver)
@@ -142,4 +142,3 @@ namespace math
}
}
}
-
diff --git a/src/csharp/Grpc.Examples/Properties/AssemblyInfo.cs b/src/csharp/Grpc.Examples/Properties/AssemblyInfo.cs
index 7603db7ffd..b55d24166c 100644
--- a/src/csharp/Grpc.Examples/Properties/AssemblyInfo.cs
+++ b/src/csharp/Grpc.Examples/Properties/AssemblyInfo.cs
@@ -1,22 +1,12 @@
using System.Reflection;
using System.Runtime.CompilerServices;
-// Information about this assembly is defined by the following attributes.
-// Change them to the values specific to your project.
-[assembly: AssemblyTitle ("Grpc.Examples")]
-[assembly: AssemblyDescription ("")]
-[assembly: AssemblyConfiguration ("")]
-[assembly: AssemblyCompany ("")]
-[assembly: AssemblyProduct ("")]
-[assembly: AssemblyCopyright ("Google Inc. All rights reserved.")]
-[assembly: AssemblyTrademark ("")]
-[assembly: AssemblyCulture ("")]
-// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
-// The form "{Major}.{Minor}.*" will automatically update the build and revision,
-// and "{Major}.{Minor}.{Build}.*" will update just the revision.
-[assembly: AssemblyVersion ("0.1.*")]
-// The following attributes are used to specify the signing key for the assembly,
-// if desired. See the Mono documentation for more information about signing.
-//[assembly: AssemblyDelaySign(false)]
-//[assembly: AssemblyKeyFile("")]
-
+[assembly: AssemblyTitle("Grpc.Examples")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("")]
+[assembly: AssemblyCopyright("Google Inc. All rights reserved.")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+[assembly: AssemblyVersion("0.1.*")]
diff --git a/src/csharp/Grpc.Examples/Settings.StyleCop b/src/csharp/Grpc.Examples/Settings.StyleCop
new file mode 100644
index 0000000000..e9b6e7172a
--- /dev/null
+++ b/src/csharp/Grpc.Examples/Settings.StyleCop
@@ -0,0 +1,10 @@
+<StyleCopSettings Version="105">
+ <SourceFileList>
+ <SourceFile>Math.cs</SourceFile>
+ <Settings>
+ <GlobalSettings>
+ <BooleanProperty Name="RulesEnabledByDefault">False</BooleanProperty>
+ </GlobalSettings>
+ </Settings>
+ </SourceFileList>
+</StyleCopSettings> \ No newline at end of file
diff --git a/src/csharp/Grpc.IntegrationTesting.Client/Properties/AssemblyInfo.cs b/src/csharp/Grpc.IntegrationTesting.Client/Properties/AssemblyInfo.cs
index d1f9e8560d..c93dd1eb2f 100644
--- a/src/csharp/Grpc.IntegrationTesting.Client/Properties/AssemblyInfo.cs
+++ b/src/csharp/Grpc.IntegrationTesting.Client/Properties/AssemblyInfo.cs
@@ -1,8 +1,6 @@
using System.Reflection;
using System.Runtime.CompilerServices;
-// Information about this assembly is defined by the following attributes.
-// Change them to the values specific to your project.
[assembly: AssemblyTitle("Grpc.IntegrationTesting.Client")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
@@ -11,12 +9,4 @@ using System.Runtime.CompilerServices;
[assembly: AssemblyCopyright("Google Inc. All rights reserved.")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
-// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
-// The form "{Major}.{Minor}.*" will automatically update the build and revision,
-// and "{Major}.{Minor}.{Build}.*" will update just the revision.
[assembly: AssemblyVersion("0.1.*")]
-// The following attributes are used to specify the signing key for the assembly,
-// if desired. See the Mono documentation for more information about signing.
-//[assembly: AssemblyDelaySign(false)]
-//[assembly: AssemblyKeyFile("")]
-
diff --git a/src/csharp/Grpc.IntegrationTesting.Server/Properties/AssemblyInfo.cs b/src/csharp/Grpc.IntegrationTesting.Server/Properties/AssemblyInfo.cs
index 4ef93f328d..f3def1aea4 100644
--- a/src/csharp/Grpc.IntegrationTesting.Server/Properties/AssemblyInfo.cs
+++ b/src/csharp/Grpc.IntegrationTesting.Server/Properties/AssemblyInfo.cs
@@ -1,8 +1,6 @@
using System.Reflection;
using System.Runtime.CompilerServices;
-// Information about this assembly is defined by the following attributes.
-// Change them to the values specific to your project.
[assembly: AssemblyTitle("Grpc.IntegrationTesting.Server")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
@@ -11,12 +9,4 @@ using System.Runtime.CompilerServices;
[assembly: AssemblyCopyright("Google Inc. All rights reserved.")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
-// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
-// The form "{Major}.{Minor}.*" will automatically update the build and revision,
-// and "{Major}.{Minor}.{Build}.*" will update just the revision.
[assembly: AssemblyVersion("0.1.*")]
-// The following attributes are used to specify the signing key for the assembly,
-// if desired. See the Mono documentation for more information about signing.
-//[assembly: AssemblyDelaySign(false)]
-//[assembly: AssemblyKeyFile("")]
-
diff --git a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
index 8f7a17efcb..c3e5f03074 100644
--- a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
+++ b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
@@ -39,6 +39,9 @@
<Reference Include="Google.ProtocolBuffers">
<HintPath>..\packages\Google.ProtocolBuffers.2.4.1.521\lib\net40\Google.ProtocolBuffers.dll</HintPath>
</Reference>
+ <Reference Include="System.Collections.Immutable">
+ <HintPath>..\packages\System.Collections.Immutable.1.1.34-rc\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll</HintPath>
+ </Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs" />
@@ -49,6 +52,7 @@
<Compile Include="TestServiceImpl.cs" />
<Compile Include="InteropServer.cs" />
<Compile Include="InteropClient.cs" />
+ <Compile Include="TestCredentials.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>
@@ -75,8 +79,5 @@
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
- <ItemGroup>
- <Folder Include="proto\" />
- <Folder Include="data\" />
- </ItemGroup>
-</Project>
+ <ItemGroup />
+</Project> \ No newline at end of file
diff --git a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs
index 30301f165b..6b92d3c660 100644
--- a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs
+++ b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs
@@ -38,10 +38,10 @@ using System.IO;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Google.ProtocolBuffers;
+using grpc.testing;
using Grpc.Core;
using Grpc.Core.Utils;
using NUnit.Framework;
-using grpc.testing;
namespace Grpc.IntegrationTesting
{
@@ -50,8 +50,8 @@ namespace Grpc.IntegrationTesting
private class ClientOptions
{
public bool help;
- public string serverHost= "127.0.0.1";
- public string serverHostOverride = "foo.test.google.fr";
+ public string serverHost = "127.0.0.1";
+ public string serverHostOverride = TestCredentials.DefaultHostOverride;
public int? serverPort;
public string testCase = "large_unary";
public bool useTls;
@@ -103,22 +103,13 @@ namespace Grpc.IntegrationTesting
Credentials credentials = null;
if (options.useTls)
{
- string caPath = "data/ca.pem"; // Default testing CA
- if (!options.useTestCa)
- {
- caPath = Environment.GetEnvironmentVariable("SSL_CERT_FILE");
- if (string.IsNullOrEmpty(caPath))
- {
- throw new ArgumentException("CA path environment variable is not set.");
- }
- }
- credentials = new SslCredentials(File.ReadAllText(caPath));
+ credentials = TestCredentials.CreateTestClientCredentials(options.useTestCa);
}
ChannelArgs channelArgs = null;
if (!string.IsNullOrEmpty(options.serverHostOverride))
{
- channelArgs = ChannelArgs.NewBuilder()
+ channelArgs = ChannelArgs.CreateBuilder()
.AddString(ChannelArgs.SslTargetNameOverrideKey, options.serverHostOverride).Build();
}
@@ -189,7 +180,7 @@ namespace Grpc.IntegrationTesting
{
Console.WriteLine("running client_streaming");
- var bodySizes = new List<int>{27182, 8, 1828, 45904};
+ var bodySizes = new List<int> { 27182, 8, 1828, 45904 };
var context = client.StreamingInputCall();
foreach (var size in bodySizes)
@@ -208,7 +199,7 @@ namespace Grpc.IntegrationTesting
{
Console.WriteLine("running server_streaming");
- var bodySizes = new List<int>{31415, 9, 2653, 58979};
+ var bodySizes = new List<int> { 31415, 9, 2653, 58979 };
var request = StreamingOutputCallRequest.CreateBuilder()
.SetResponseType(PayloadType.COMPRESSABLE)
@@ -265,7 +256,6 @@ namespace Grpc.IntegrationTesting
Assert.AreEqual(PayloadType.COMPRESSABLE, response.Payload.Type);
Assert.AreEqual(2653, response.Payload.Body.Length);
-
inputs.OnNext(StreamingOutputCallRequest.CreateBuilder()
.SetResponseType(PayloadType.COMPRESSABLE)
.AddResponseParameters(ResponseParameters.CreateBuilder().SetSize(58979))
@@ -301,17 +291,18 @@ namespace Grpc.IntegrationTesting
public static void RunBenchmarkEmptyUnary(TestServiceGrpc.ITestServiceClient client)
{
BenchmarkUtil.RunBenchmark(10000, 10000,
- () => { client.EmptyCall(Empty.DefaultInstance);});
+ () => { client.EmptyCall(Empty.DefaultInstance); });
}
- private static Payload CreateZerosPayload(int size) {
+ private static Payload CreateZerosPayload(int size)
+ {
return Payload.CreateBuilder().SetBody(ByteString.CopyFrom(new byte[size])).Build();
}
private static ClientOptions ParseArguments(string[] args)
{
var options = new ClientOptions();
- foreach(string arg in args)
+ foreach (string arg in args)
{
ParseArgument(arg, options);
if (options.help)
diff --git a/src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs b/src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs
index 4bb0b9ee51..1e76d3df21 100644
--- a/src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs
+++ b/src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs
@@ -35,10 +35,10 @@ using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
+using grpc.testing;
using Grpc.Core;
using Grpc.Core.Utils;
using NUnit.Framework;
-using grpc.testing;
namespace Grpc.IntegrationTesting
{
@@ -59,9 +59,13 @@ namespace Grpc.IntegrationTesting
server = new Server();
server.AddServiceDefinition(TestServiceGrpc.BindService(new TestServiceImpl()));
- int port = server.AddPort(host + ":0");
+ int port = server.AddListeningPort(host + ":0", TestCredentials.CreateTestServerCredentials());
server.Start();
- channel = new Channel(host + ":" + port);
+
+ var channelArgs = ChannelArgs.CreateBuilder()
+ .AddString(ChannelArgs.SslTargetNameOverrideKey, TestCredentials.DefaultHostOverride).Build();
+
+ channel = new Channel(host + ":" + port, TestCredentials.CreateTestClientCredentials(true), channelArgs);
client = TestServiceGrpc.NewStub(channel);
}
@@ -113,7 +117,5 @@ namespace Grpc.IntegrationTesting
// TODO: add cancel_after_begin
// TODO: add cancel_after_first_response
-
}
}
-
diff --git a/src/csharp/Grpc.IntegrationTesting/InteropServer.cs b/src/csharp/Grpc.IntegrationTesting/InteropServer.cs
index a25d3b3530..ad5200774f 100644
--- a/src/csharp/Grpc.IntegrationTesting/InteropServer.cs
+++ b/src/csharp/Grpc.IntegrationTesting/InteropServer.cs
@@ -34,13 +34,14 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
+using System.IO;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Google.ProtocolBuffers;
+using grpc.testing;
using Grpc.Core;
using Grpc.Core.Utils;
using NUnit.Framework;
-using grpc.testing;
namespace Grpc.IntegrationTesting
{
@@ -49,7 +50,7 @@ namespace Grpc.IntegrationTesting
private class ServerOptions
{
public bool help;
- public int? port;
+ public int? port = 8070;
public bool useTls;
}
@@ -93,7 +94,14 @@ namespace Grpc.IntegrationTesting
server.AddServiceDefinition(TestServiceGrpc.BindService(new TestServiceImpl()));
string addr = "0.0.0.0:" + options.port;
- server.AddPort(addr);
+ if (options.useTls)
+ {
+ server.AddListeningPort(addr, TestCredentials.CreateTestServerCredentials());
+ }
+ else
+ {
+ server.AddListeningPort(addr);
+ }
Console.WriteLine("Running server on " + addr);
server.Start();
@@ -105,7 +113,7 @@ namespace Grpc.IntegrationTesting
private static ServerOptions ParseArguments(string[] args)
{
var options = new ServerOptions();
- foreach(string arg in args)
+ foreach (string arg in args)
{
ParseArgument(arg, options);
if (options.help)
diff --git a/src/csharp/Grpc.IntegrationTesting/Properties/AssemblyInfo.cs b/src/csharp/Grpc.IntegrationTesting/Properties/AssemblyInfo.cs
index f633c19132..f09a448e9e 100644
--- a/src/csharp/Grpc.IntegrationTesting/Properties/AssemblyInfo.cs
+++ b/src/csharp/Grpc.IntegrationTesting/Properties/AssemblyInfo.cs
@@ -1,8 +1,6 @@
using System.Reflection;
using System.Runtime.CompilerServices;
-// Information about this assembly is defined by the following attributes.
-// Change them to the values specific to your project.
[assembly: AssemblyTitle("Grpc.IntegrationTesting")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
@@ -11,12 +9,4 @@ using System.Runtime.CompilerServices;
[assembly: AssemblyCopyright("Google Inc. All rights reserved.")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
-// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
-// The form "{Major}.{Minor}.*" will automatically update the build and revision,
-// and "{Major}.{Minor}.{Build}.*" will update just the revision.
[assembly: AssemblyVersion("0.1.*")]
-// The following attributes are used to specify the signing key for the assembly,
-// if desired. See the Mono documentation for more information about signing.
-//[assembly: AssemblyDelaySign(false)]
-//[assembly: AssemblyKeyFile("")]
-
diff --git a/src/csharp/Grpc.IntegrationTesting/Settings.StyleCop b/src/csharp/Grpc.IntegrationTesting/Settings.StyleCop
new file mode 100644
index 0000000000..fb99cd4af1
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting/Settings.StyleCop
@@ -0,0 +1,11 @@
+<StyleCopSettings Version="105">
+ <SourceFileList>
+ <SourceFile>Messages.cs</SourceFile>
+ <SourceFile>Empty.cs</SourceFile>
+ <Settings>
+ <GlobalSettings>
+ <BooleanProperty Name="RulesEnabledByDefault">False</BooleanProperty>
+ </GlobalSettings>
+ </Settings>
+ </SourceFileList>
+</StyleCopSettings> \ No newline at end of file
diff --git a/src/csharp/Grpc.IntegrationTesting/TestCredentials.cs b/src/csharp/Grpc.IntegrationTesting/TestCredentials.cs
new file mode 100644
index 0000000000..401c50b1ae
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting/TestCredentials.cs
@@ -0,0 +1,84 @@
+#region Copyright notice and license
+
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.Diagnostics;
+using System.IO;
+using System.Text.RegularExpressions;
+using System.Threading.Tasks;
+using Google.ProtocolBuffers;
+using grpc.testing;
+using Grpc.Core;
+using Grpc.Core.Utils;
+using NUnit.Framework;
+
+namespace Grpc.IntegrationTesting
+{
+ /// <summary>
+ /// SSL Credentials for testing.
+ /// </summary>
+ public static class TestCredentials
+ {
+ public const string DefaultHostOverride = "foo.test.google.fr";
+
+ public const string ClientCertAuthorityPath = "data/ca.pem";
+ public const string ClientCertAuthorityEnvName = "SSL_CERT_FILE";
+
+ public const string ServerCertChainPath = "data/server1.pem";
+ public const string ServerPrivateKeyPath = "data/server1.key";
+
+ public static SslCredentials CreateTestClientCredentials(bool useTestCa)
+ {
+ string caPath = ClientCertAuthorityPath;
+ if (!useTestCa)
+ {
+ caPath = Environment.GetEnvironmentVariable(ClientCertAuthorityEnvName);
+ if (string.IsNullOrEmpty(caPath))
+ {
+ throw new ArgumentException("CA path environment variable is not set.");
+ }
+ }
+ return new SslCredentials(File.ReadAllText(caPath));
+ }
+
+ public static SslServerCredentials CreateTestServerCredentials()
+ {
+ var keyCertPair = new KeyCertificatePair(
+ File.ReadAllText(ServerCertChainPath),
+ File.ReadAllText(ServerPrivateKeyPath));
+ return new SslServerCredentials(ImmutableList.Create(keyCertPair));
+ }
+ }
+}
diff --git a/src/csharp/Grpc.IntegrationTesting/TestServiceGrpc.cs b/src/csharp/Grpc.IntegrationTesting/TestServiceGrpc.cs
index b71704bcc7..f63e0361a4 100644
--- a/src/csharp/Grpc.IntegrationTesting/TestServiceGrpc.cs
+++ b/src/csharp/Grpc.IntegrationTesting/TestServiceGrpc.cs
@@ -44,50 +44,51 @@ namespace grpc.testing
/// </summary>
public class TestServiceGrpc
{
- readonly static Marshaller<Empty> emptyMarshaller = Marshallers.Create((arg) => arg.ToByteArray(), Empty.ParseFrom);
- readonly static Marshaller<SimpleRequest> simpleRequestMarshaller = Marshallers.Create((arg) => arg.ToByteArray(), SimpleRequest.ParseFrom);
- readonly static Marshaller<SimpleResponse> simpleResponseMarshaller = Marshallers.Create((arg) => arg.ToByteArray(), SimpleResponse.ParseFrom);
- readonly static Marshaller<StreamingOutputCallRequest> streamingOutputCallRequestMarshaller = Marshallers.Create((arg) => arg.ToByteArray(), StreamingOutputCallRequest.ParseFrom);
- readonly static Marshaller<StreamingOutputCallResponse> streamingOutputCallResponseMarshaller = Marshallers.Create((arg) => arg.ToByteArray(), StreamingOutputCallResponse.ParseFrom);
- readonly static Marshaller<StreamingInputCallRequest> streamingInputCallRequestMarshaller = Marshallers.Create((arg) => arg.ToByteArray(), StreamingInputCallRequest.ParseFrom);
- readonly static Marshaller<StreamingInputCallResponse> streamingInputCallResponseMarshaller = Marshallers.Create((arg) => arg.ToByteArray(), StreamingInputCallResponse.ParseFrom);
-
- readonly static Method<Empty, Empty> emptyCallMethod = new Method<Empty, Empty>(
+ static readonly string ServiceName = "/grpc.testing.TestService";
+
+ static readonly Marshaller<Empty> EmptyMarshaller = Marshallers.Create((arg) => arg.ToByteArray(), Empty.ParseFrom);
+ static readonly Marshaller<SimpleRequest> SimpleRequestMarshaller = Marshallers.Create((arg) => arg.ToByteArray(), SimpleRequest.ParseFrom);
+ static readonly Marshaller<SimpleResponse> SimpleResponseMarshaller = Marshallers.Create((arg) => arg.ToByteArray(), SimpleResponse.ParseFrom);
+ static readonly Marshaller<StreamingOutputCallRequest> StreamingOutputCallRequestMarshaller = Marshallers.Create((arg) => arg.ToByteArray(), StreamingOutputCallRequest.ParseFrom);
+ static readonly Marshaller<StreamingOutputCallResponse> StreamingOutputCallResponseMarshaller = Marshallers.Create((arg) => arg.ToByteArray(), StreamingOutputCallResponse.ParseFrom);
+ static readonly Marshaller<StreamingInputCallRequest> StreamingInputCallRequestMarshaller = Marshallers.Create((arg) => arg.ToByteArray(), StreamingInputCallRequest.ParseFrom);
+ static readonly Marshaller<StreamingInputCallResponse> StreamingInputCallResponseMarshaller = Marshallers.Create((arg) => arg.ToByteArray(), StreamingInputCallResponse.ParseFrom);
+
+ static readonly Method<Empty, Empty> EmptyCallMethod = new Method<Empty, Empty>(
MethodType.Unary,
- "/grpc.testing.TestService/EmptyCall",
- emptyMarshaller,
- emptyMarshaller
- );
- readonly static Method<SimpleRequest, SimpleResponse> unaryCallMethod = new Method<SimpleRequest, SimpleResponse>(
+ "EmptyCall",
+ EmptyMarshaller,
+ EmptyMarshaller);
+
+ static readonly Method<SimpleRequest, SimpleResponse> UnaryCallMethod = new Method<SimpleRequest, SimpleResponse>(
MethodType.Unary,
- "/grpc.testing.TestService/UnaryCall",
- simpleRequestMarshaller,
- simpleResponseMarshaller
- );
- readonly static Method<StreamingOutputCallRequest, StreamingOutputCallResponse> streamingOutputCallMethod = new Method<StreamingOutputCallRequest, StreamingOutputCallResponse>(
+ "UnaryCall",
+ SimpleRequestMarshaller,
+ SimpleResponseMarshaller);
+
+ static readonly Method<StreamingOutputCallRequest, StreamingOutputCallResponse> StreamingOutputCallMethod = new Method<StreamingOutputCallRequest, StreamingOutputCallResponse>(
MethodType.ServerStreaming,
- "/grpc.testing.TestService/StreamingOutputCall",
- streamingOutputCallRequestMarshaller,
- streamingOutputCallResponseMarshaller
- );
- readonly static Method<StreamingInputCallRequest, StreamingInputCallResponse> streamingInputCallMethod = new Method<StreamingInputCallRequest, StreamingInputCallResponse>(
+ "StreamingOutputCall",
+ StreamingOutputCallRequestMarshaller,
+ StreamingOutputCallResponseMarshaller);
+
+ static readonly Method<StreamingInputCallRequest, StreamingInputCallResponse> StreamingInputCallMethod = new Method<StreamingInputCallRequest, StreamingInputCallResponse>(
MethodType.ClientStreaming,
- "/grpc.testing.TestService/StreamingInputCall",
- streamingInputCallRequestMarshaller,
- streamingInputCallResponseMarshaller
- );
- readonly static Method<StreamingOutputCallRequest, StreamingOutputCallResponse> fullDuplexCallMethod = new Method<StreamingOutputCallRequest, StreamingOutputCallResponse>(
+ "StreamingInputCall",
+ StreamingInputCallRequestMarshaller,
+ StreamingInputCallResponseMarshaller);
+
+ static readonly Method<StreamingOutputCallRequest, StreamingOutputCallResponse> FullDuplexCallMethod = new Method<StreamingOutputCallRequest, StreamingOutputCallResponse>(
MethodType.DuplexStreaming,
- "/grpc.testing.TestService/FullDuplexCall",
- streamingOutputCallRequestMarshaller,
- streamingOutputCallResponseMarshaller
- );
- readonly static Method<StreamingOutputCallRequest, StreamingOutputCallResponse> halfDuplexCallMethod = new Method<StreamingOutputCallRequest, StreamingOutputCallResponse>(
+ "FullDuplexCall",
+ StreamingOutputCallRequestMarshaller,
+ StreamingOutputCallResponseMarshaller);
+
+ static readonly Method<StreamingOutputCallRequest, StreamingOutputCallResponse> HalfDuplexCallMethod = new Method<StreamingOutputCallRequest, StreamingOutputCallResponse>(
MethodType.DuplexStreaming,
- "/grpc.testing.TestService/HalfDuplexCall",
- streamingOutputCallRequestMarshaller,
- streamingOutputCallResponseMarshaller
- );
+ "HalfDuplexCall",
+ StreamingOutputCallRequestMarshaller,
+ StreamingOutputCallResponseMarshaller);
public interface ITestServiceClient
{
@@ -108,60 +109,61 @@ namespace grpc.testing
IObserver<StreamingOutputCallRequest> HalfDuplexCall(IObserver<StreamingOutputCallResponse> responseObserver, CancellationToken token = default(CancellationToken));
}
- public class TestServiceClientStub : ITestServiceClient
+ public class TestServiceClientStub : AbstractStub<TestServiceClientStub, StubConfiguration>, ITestServiceClient
{
- readonly Channel channel;
+ public TestServiceClientStub(Channel channel) : base(channel, StubConfiguration.Default)
+ {
+ }
- public TestServiceClientStub(Channel channel)
+ public TestServiceClientStub(Channel channel, StubConfiguration config) : base(channel, config)
{
- this.channel = channel;
}
public Empty EmptyCall(Empty request, CancellationToken token = default(CancellationToken))
{
- var call = new Grpc.Core.Call<Empty, Empty>(emptyCallMethod, channel);
+ var call = CreateCall(ServiceName, EmptyCallMethod);
return Calls.BlockingUnaryCall(call, request, token);
}
public Task<Empty> EmptyCallAsync(Empty request, CancellationToken token = default(CancellationToken))
{
- var call = new Grpc.Core.Call<Empty, Empty>(emptyCallMethod, channel);
+ var call = CreateCall(ServiceName, EmptyCallMethod);
return Calls.AsyncUnaryCall(call, request, token);
}
public SimpleResponse UnaryCall(SimpleRequest request, CancellationToken token = default(CancellationToken))
{
- var call = new Grpc.Core.Call<SimpleRequest, SimpleResponse>(unaryCallMethod, channel);
+ var call = CreateCall(ServiceName, UnaryCallMethod);
return Calls.BlockingUnaryCall(call, request, token);
}
public Task<SimpleResponse> UnaryCallAsync(SimpleRequest request, CancellationToken token = default(CancellationToken))
{
- var call = new Grpc.Core.Call<SimpleRequest, SimpleResponse>(unaryCallMethod, channel);
+ var call = CreateCall(ServiceName, UnaryCallMethod);
return Calls.AsyncUnaryCall(call, request, token);
}
- public void StreamingOutputCall(StreamingOutputCallRequest request, IObserver<StreamingOutputCallResponse> responseObserver, CancellationToken token = default(CancellationToken)) {
- var call = new Grpc.Core.Call<StreamingOutputCallRequest, StreamingOutputCallResponse>(streamingOutputCallMethod, channel);
+ public void StreamingOutputCall(StreamingOutputCallRequest request, IObserver<StreamingOutputCallResponse> responseObserver, CancellationToken token = default(CancellationToken))
+ {
+ var call = CreateCall(ServiceName, StreamingOutputCallMethod);
Calls.AsyncServerStreamingCall(call, request, responseObserver, token);
}
public ClientStreamingAsyncResult<StreamingInputCallRequest, StreamingInputCallResponse> StreamingInputCall(CancellationToken token = default(CancellationToken))
{
- var call = new Grpc.Core.Call<StreamingInputCallRequest, StreamingInputCallResponse>(streamingInputCallMethod, channel);
+ var call = CreateCall(ServiceName, StreamingInputCallMethod);
return Calls.AsyncClientStreamingCall(call, token);
}
public IObserver<StreamingOutputCallRequest> FullDuplexCall(IObserver<StreamingOutputCallResponse> responseObserver, CancellationToken token = default(CancellationToken))
{
- var call = new Grpc.Core.Call<StreamingOutputCallRequest, StreamingOutputCallResponse>(fullDuplexCallMethod, channel);
+ var call = CreateCall(ServiceName, FullDuplexCallMethod);
return Calls.DuplexStreamingCall(call, responseObserver, token);
}
-
public IObserver<StreamingOutputCallRequest> HalfDuplexCall(IObserver<StreamingOutputCallResponse> responseObserver, CancellationToken token = default(CancellationToken))
{
- var call = new Grpc.Core.Call<StreamingOutputCallRequest, StreamingOutputCallResponse>(halfDuplexCallMethod, channel);
+ var call = CreateCall(ServiceName, HalfDuplexCallMethod);
return Calls.DuplexStreamingCall(call, responseObserver, token);
}
}
@@ -184,13 +186,13 @@ namespace grpc.testing
public static ServerServiceDefinition BindService(ITestService serviceImpl)
{
- return ServerServiceDefinition.CreateBuilder("/grpc.testing.TestService/")
- .AddMethod(emptyCallMethod, serviceImpl.EmptyCall)
- .AddMethod(unaryCallMethod, serviceImpl.UnaryCall)
- .AddMethod(streamingOutputCallMethod, serviceImpl.StreamingOutputCall)
- .AddMethod(streamingInputCallMethod, serviceImpl.StreamingInputCall)
- .AddMethod(fullDuplexCallMethod, serviceImpl.FullDuplexCall)
- .AddMethod(halfDuplexCallMethod, serviceImpl.HalfDuplexCall)
+ return ServerServiceDefinition.CreateBuilder(ServiceName)
+ .AddMethod(EmptyCallMethod, serviceImpl.EmptyCall)
+ .AddMethod(UnaryCallMethod, serviceImpl.UnaryCall)
+ .AddMethod(StreamingOutputCallMethod, serviceImpl.StreamingOutputCall)
+ .AddMethod(StreamingInputCallMethod, serviceImpl.StreamingInputCall)
+ .AddMethod(FullDuplexCallMethod, serviceImpl.FullDuplexCall)
+ .AddMethod(HalfDuplexCallMethod, serviceImpl.HalfDuplexCall)
.Build();
}
diff --git a/src/csharp/Grpc.IntegrationTesting/TestServiceImpl.cs b/src/csharp/Grpc.IntegrationTesting/TestServiceImpl.cs
index 176843b130..661b31b0ee 100644
--- a/src/csharp/Grpc.IntegrationTesting/TestServiceImpl.cs
+++ b/src/csharp/Grpc.IntegrationTesting/TestServiceImpl.cs
@@ -55,14 +55,14 @@ namespace grpc.testing
{
var response = SimpleResponse.CreateBuilder()
.SetPayload(CreateZerosPayload(request.ResponseSize)).Build();
- //TODO: check we support ReponseType
+ // TODO: check we support ReponseType
responseObserver.OnNext(response);
responseObserver.OnCompleted();
}
public void StreamingOutputCall(StreamingOutputCallRequest request, IObserver<StreamingOutputCallResponse> responseObserver)
{
- foreach(var responseParam in request.ResponseParametersList)
+ foreach (var responseParam in request.ResponseParametersList)
{
var response = StreamingOutputCallResponse.CreateBuilder()
.SetPayload(CreateZerosPayload(responseParam.Size)).Build();
@@ -74,9 +74,10 @@ namespace grpc.testing
public IObserver<StreamingInputCallRequest> StreamingInputCall(IObserver<StreamingInputCallResponse> responseObserver)
{
var recorder = new RecordingObserver<StreamingInputCallRequest>();
- Task.Run(() => {
+ Task.Run(() =>
+ {
int sum = 0;
- foreach(var req in recorder.ToList().Result)
+ foreach (var req in recorder.ToList().Result)
{
sum += req.Payload.Body.Length;
}
@@ -98,8 +99,8 @@ namespace grpc.testing
throw new NotImplementedException();
}
- private class FullDuplexObserver : IObserver<StreamingOutputCallRequest> {
-
+ private class FullDuplexObserver : IObserver<StreamingOutputCallRequest>
+ {
readonly IObserver<StreamingOutputCallResponse> responseObserver;
public FullDuplexObserver(IObserver<StreamingOutputCallResponse> responseObserver)
@@ -119,22 +120,18 @@ namespace grpc.testing
public void OnNext(StreamingOutputCallRequest value)
{
- // TODO: this is not in order!!!
- //Task.Factory.StartNew(() => {
-
- foreach(var responseParam in value.ResponseParametersList)
- {
- var response = StreamingOutputCallResponse.CreateBuilder()
- .SetPayload(CreateZerosPayload(responseParam.Size)).Build();
- responseObserver.OnNext(response);
- }
- //});
+ foreach (var responseParam in value.ResponseParametersList)
+ {
+ var response = StreamingOutputCallResponse.CreateBuilder()
+ .SetPayload(CreateZerosPayload(responseParam.Size)).Build();
+ responseObserver.OnNext(response);
+ }
}
}
- private static Payload CreateZerosPayload(int size) {
+ private static Payload CreateZerosPayload(int size)
+ {
return Payload.CreateBuilder().SetBody(ByteString.CopyFrom(new byte[size])).Build();
}
}
}
-
diff --git a/src/csharp/Grpc.IntegrationTesting/packages.config b/src/csharp/Grpc.IntegrationTesting/packages.config
index 51c17bcd5e..157c264eac 100644
--- a/src/csharp/Grpc.IntegrationTesting/packages.config
+++ b/src/csharp/Grpc.IntegrationTesting/packages.config
@@ -2,4 +2,5 @@
<packages>
<package id="Google.ProtocolBuffers" version="2.4.1.521" targetFramework="net45" />
<package id="NUnit" version="2.6.4" targetFramework="net45" />
+ <package id="System.Collections.Immutable" version="1.1.34-rc" targetFramework="net45" />
</packages> \ No newline at end of file
diff --git a/src/csharp/Settings.StyleCop b/src/csharp/Settings.StyleCop
new file mode 100644
index 0000000000..2ecf22f69e
--- /dev/null
+++ b/src/csharp/Settings.StyleCop
@@ -0,0 +1,509 @@
+<StyleCopSettings Version="105">
+ <Analyzers>
+ <Analyzer AnalyzerId="StyleCop.CSharp.DocumentationRules">
+ <Rules>
+ <Rule Name="ElementsMustBeDocumented">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="PartialElementsMustBeDocumented">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="EnumerationItemsMustBeDocumented">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="DocumentationMustContainValidXml">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="ElementDocumentationMustHaveSummary">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="PartialElementDocumentationMustHaveSummary">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="ElementDocumentationMustHaveSummaryText">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="PartialElementDocumentationMustHaveSummaryText">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="ElementDocumentationMustNotHaveDefaultSummary">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="ElementParametersMustBeDocumented">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="ElementParameterDocumentationMustMatchElementParameters">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="ElementParameterDocumentationMustDeclareParameterName">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="ElementParameterDocumentationMustHaveText">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="ElementReturnValueMustBeDocumented">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="ElementReturnValueDocumentationMustHaveText">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="VoidReturnValueMustNotBeDocumented">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="GenericTypeParametersMustBeDocumented">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="GenericTypeParametersMustBeDocumentedPartialClass">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="GenericTypeParameterDocumentationMustMatchTypeParameters">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="GenericTypeParameterDocumentationMustDeclareParameterName">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="GenericTypeParameterDocumentationMustHaveText">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="PropertySummaryDocumentationMustMatchAccessors">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="PropertySummaryDocumentationMustOmitSetAccessorWithRestrictedAccess">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="ElementDocumentationMustNotBeCopiedAndPasted">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="SingleLineCommentsMustNotUseDocumentationStyleSlashes">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="DocumentationTextMustNotBeEmpty">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="DocumentationTextMustContainWhitespace">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="DocumentationMustMeetCharacterPercentage">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="ConstructorSummaryDocumentationMustBeginWithStandardText">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="DestructorSummaryDocumentationMustBeginWithStandardText">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="DocumentationHeadersMustNotContainBlankLines">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="IncludedDocumentationXPathDoesNotExist">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="IncludeNodeDoesNotContainValidFileAndPath">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="InheritDocMustBeUsedWithInheritingClass">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="ElementDocumentationMustBeSpelledCorrectly">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="FileMustHaveHeader">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="FileHeaderMustShowCopyright">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="FileHeaderMustHaveCopyrightText">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="FileHeaderMustContainFileName">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="FileHeaderFileNameDocumentationMustMatchFileName">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="FileHeaderMustHaveValidCompanyText">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="FileHeaderFileNameDocumentationMustMatchTypeName">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ </Rules>
+ <AnalyzerSettings />
+ </Analyzer>
+ <Analyzer AnalyzerId="StyleCop.CSharp.MaintainabilityRules">
+ <Rules>
+ <Rule Name="AccessModifierMustBeDeclared">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="FieldsMustBePrivate">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="CodeAnalysisSuppressionMustHaveJustification">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="DebugAssertMustProvideMessageText">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="DebugFailMustProvideMessageText">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="FileMayOnlyContainASingleClass">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="StatementMustNotUseUnnecessaryParenthesis">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="ArithmeticExpressionsMustDeclarePrecedence">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="ConditionalExpressionsMustDeclarePrecedence">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="RemoveDelegateParenthesisWhenPossible">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="AttributeConstructorMustNotUseUnnecessaryParenthesis">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="RemoveUnnecessaryCode">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ </Rules>
+ <AnalyzerSettings />
+ </Analyzer>
+ <Analyzer AnalyzerId="StyleCop.CSharp.NamingRules">
+ <Rules>
+ <Rule Name="NonPrivateReadonlyFieldsMustBeginWithUpperCaseLetter">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="FieldNamesMustNotUseHungarianNotation">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="FieldNamesMustBeginWithLowerCaseLetter">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="AccessibleFieldsMustBeginWithUpperCaseLetter">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="VariableNamesMustNotBePrefixed">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="FieldNamesMustNotBeginWithUnderscore">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="FieldNamesMustNotContainUnderscore">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="ElementMustBeginWithUpperCaseLetter">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ </Rules>
+ <AnalyzerSettings />
+ </Analyzer>
+ <Analyzer AnalyzerId="StyleCop.CSharp.OrderingRules">
+ <Rules>
+ <Rule Name="UsingDirectivesMustBePlacedWithinNamespace">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="ElementsMustAppearInTheCorrectOrder">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="ElementsMustBeOrderedByAccess">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="StaticElementsMustAppearBeforeInstanceElements">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="PropertyAccessorsMustFollowOrder">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="EventAccessorsMustFollowOrder">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="UsingAliasDirectivesMustBePlacedAfterOtherUsingDirectives">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="UsingAliasDirectivesMustBeOrderedAlphabeticallyByAliasName">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ </Rules>
+ <AnalyzerSettings />
+ </Analyzer>
+ <Analyzer AnalyzerId="StyleCop.CSharp.ReadabilityRules">
+ <Rules>
+ <Rule Name="DoNotPrefixCallsWithBaseUnlessLocalImplementationExists">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="PrefixLocalCallsWithThis">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="PrefixCallsCorrectly">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="OpeningParenthesisMustBeOnDeclarationLine">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="ClosingParenthesisMustBeOnLineOfLastParameter">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="ClosingParenthesisMustBeOnLineOfOpeningParenthesis">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="CommaMustBeOnSameLineAsPreviousParameter">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="ParameterListMustFollowDeclaration">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="ParameterMustFollowComma">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="SplitParametersMustStartOnLineAfterDeclaration">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="ParametersMustBeOnSameLineOrSeparateLines">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="ParameterMustNotSpanMultipleLines">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="QueryClauseMustFollowPreviousClause">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="QueryClausesMustBeOnSeparateLinesOrAllOnOneLine">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="QueryClauseMustBeginOnNewLineWhenPreviousClauseSpansMultipleLines">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="QueryClausesSpanningMultipleLinesMustBeginOnOwnLine">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="CodeMustNotContainEmptyStatements">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="CodeMustNotContainMultipleStatementsOnOneLine">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="BlockStatementsMustNotContainEmbeddedComments">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="BlockStatementsMustNotContainEmbeddedRegions">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="UseStringEmptyForEmptyStrings">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ </Rules>
+ <AnalyzerSettings />
+ </Analyzer>
+ <Analyzer AnalyzerId="StyleCop.CSharp.LayoutRules">
+ <Rules>
+ <Rule Name="SingleLineCommentsMustNotBeFollowedByBlankLine">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="ClosingCurlyBracketMustBeFollowedByBlankLine">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="ElementDocumentationHeaderMustBePrecededByBlankLine">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ <Rule Name="SingleLineCommentMustBePrecededByBlankLine">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
+ </Rules>
+ <AnalyzerSettings />
+ </Analyzer>
+ </Analyzers>
+</StyleCopSettings> \ No newline at end of file
diff --git a/src/csharp/ext/grpc_csharp_ext.c b/src/csharp/ext/grpc_csharp_ext.c
index e24438704c..9a1c908d11 100644
--- a/src/csharp/ext/grpc_csharp_ext.c
+++ b/src/csharp/ext/grpc_csharp_ext.c
@@ -102,34 +102,114 @@ grpcsharp_batch_context *grpcsharp_batch_context_create() {
return ctx;
}
-/**
- * Destroys metadata array including keys and values.
+/*
+ * Destroys array->metadata.
+ * The array pointer itself is not freed.
*/
-void grpcsharp_metadata_array_destroy_recursive(grpc_metadata_array *array) {
- if (!array->metadata) {
+void grpcsharp_metadata_array_destroy_metadata_only(
+ grpc_metadata_array *array) {
+ gpr_free(array->metadata);
+}
+
+/*
+ * Destroys keys, values and array->metadata.
+ * The array pointer itself is not freed.
+ */
+void grpcsharp_metadata_array_destroy_metadata_including_entries(
+ grpc_metadata_array *array) {
+ size_t i;
+ if (array->metadata) {
+ for (i = 0; i < array->count; i++) {
+ gpr_free((void *)array->metadata[i].key);
+ gpr_free((void *)array->metadata[i].value);
+ }
+ }
+ gpr_free(array->metadata);
+}
+
+/*
+ * Fully destroys the metadata array.
+ */
+GPR_EXPORT void GPR_CALLTYPE
+grpcsharp_metadata_array_destroy_full(grpc_metadata_array *array) {
+ if (!array) {
return;
}
- /* TODO: destroy also keys and values */
- grpc_metadata_array_destroy(array);
+ grpcsharp_metadata_array_destroy_metadata_including_entries(array);
+ gpr_free(array);
+}
+
+/*
+ * Creates an empty metadata array with given capacity.
+ * Array can later be destroyed by grpc_metadata_array_destroy_full.
+ */
+GPR_EXPORT grpc_metadata_array *GPR_CALLTYPE
+grpcsharp_metadata_array_create(size_t capacity) {
+ grpc_metadata_array *array =
+ (grpc_metadata_array *)gpr_malloc(sizeof(grpc_metadata_array));
+ grpc_metadata_array_init(array);
+ array->capacity = capacity;
+ array->count = 0;
+ if (capacity > 0) {
+ array->metadata =
+ (grpc_metadata *)gpr_malloc(sizeof(grpc_metadata) * capacity);
+ memset(array->metadata, 0, sizeof(grpc_metadata) * capacity);
+ } else {
+ array->metadata = NULL;
+ }
+ return array;
+}
+
+GPR_EXPORT void GPR_CALLTYPE
+grpcsharp_metadata_array_add(grpc_metadata_array *array, const char *key,
+ const char *value, size_t value_length) {
+ size_t i = array->count;
+ GPR_ASSERT(array->count < array->capacity);
+ array->metadata[i].key = gpr_strdup(key);
+ array->metadata[i].value = (char *)gpr_malloc(value_length);
+ memcpy((void *)array->metadata[i].value, value, value_length);
+ array->metadata[i].value_length = value_length;
+ array->count++;
+}
+
+/* Move contents of metadata array */
+void grpcsharp_metadata_array_move(grpc_metadata_array *dest,
+ grpc_metadata_array *src) {
+ if (!src) {
+ dest->capacity = 0;
+ dest->count = 0;
+ dest->metadata = NULL;
+ return;
+ }
+
+ dest->capacity = src->capacity;
+ dest->count = src->count;
+ dest->metadata = src->metadata;
+
+ src->capacity = 0;
+ src->count = 0;
+ src->metadata = NULL;
}
void grpcsharp_batch_context_destroy(grpcsharp_batch_context *ctx) {
if (!ctx) {
return;
}
- grpcsharp_metadata_array_destroy_recursive(&(ctx->send_initial_metadata));
+ grpcsharp_metadata_array_destroy_metadata_including_entries(
+ &(ctx->send_initial_metadata));
grpc_byte_buffer_destroy(ctx->send_message);
- grpcsharp_metadata_array_destroy_recursive(
+ grpcsharp_metadata_array_destroy_metadata_including_entries(
&(ctx->send_status_from_server.trailing_metadata));
gpr_free(ctx->send_status_from_server.status_details);
- grpc_metadata_array_destroy(&(ctx->recv_initial_metadata));
+ grpcsharp_metadata_array_destroy_metadata_only(&(ctx->recv_initial_metadata));
grpc_byte_buffer_destroy(ctx->recv_message);
- grpc_metadata_array_destroy(&(ctx->recv_status_on_client.trailing_metadata));
+ grpcsharp_metadata_array_destroy_metadata_only(
+ &(ctx->recv_status_on_client.trailing_metadata));
gpr_free((void *)ctx->recv_status_on_client.status_details);
/* NOTE: ctx->server_rpc_new.call is not destroyed because callback handler is
@@ -137,7 +217,8 @@ void grpcsharp_batch_context_destroy(grpcsharp_batch_context *ctx) {
to take its ownership. */
grpc_call_details_destroy(&(ctx->server_rpc_new.call_details));
- grpc_metadata_array_destroy(&(ctx->server_rpc_new.request_metadata));
+ grpcsharp_metadata_array_destroy_metadata_only(
+ &(ctx->server_rpc_new.request_metadata));
gpr_free(ctx);
}
@@ -346,17 +427,19 @@ grpcsharp_call_start_write_from_copied_buffer(grpc_call *call,
GPR_EXPORT grpc_call_error GPR_CALLTYPE
grpcsharp_call_start_unary(grpc_call *call, callback_funcptr callback,
- const char *send_buffer, size_t send_buffer_len) {
+ const char *send_buffer, size_t send_buffer_len,
+ grpc_metadata_array *initial_metadata) {
/* TODO: don't use magic number */
grpc_op ops[6];
grpcsharp_batch_context *ctx = grpcsharp_batch_context_create();
ctx->callback = callback;
- /* TODO: implement sending the metadata... */
ops[0].op = GRPC_OP_SEND_INITIAL_METADATA;
- /* ctx->send_initial_metadata is already zeroed out. */
- ops[0].data.send_initial_metadata.count = 0;
- ops[0].data.send_initial_metadata.metadata = NULL;
+ grpcsharp_metadata_array_move(&(ctx->send_initial_metadata),
+ initial_metadata);
+ ops[0].data.send_initial_metadata.count = ctx->send_initial_metadata.count;
+ ops[0].data.send_initial_metadata.metadata =
+ ctx->send_initial_metadata.metadata;
ops[1].op = GRPC_OP_SEND_MESSAGE;
ctx->send_message = string_to_byte_buffer(send_buffer, send_buffer_len);
@@ -389,9 +472,11 @@ GPR_EXPORT void GPR_CALLTYPE
grpcsharp_call_blocking_unary(grpc_call *call,
grpc_completion_queue *dedicated_cq,
callback_funcptr callback,
- const char *send_buffer, size_t send_buffer_len) {
+ const char *send_buffer, size_t send_buffer_len,
+ grpc_metadata_array *initial_metadata) {
GPR_ASSERT(grpcsharp_call_start_unary(call, callback, send_buffer,
- send_buffer_len) == GRPC_CALL_OK);
+ send_buffer_len,
+ initial_metadata) == GRPC_CALL_OK);
/* TODO: we would like to use pluck, but we don't know the tag */
GPR_ASSERT(grpcsharp_completion_queue_next_with_callback(dedicated_cq) ==
@@ -403,17 +488,19 @@ grpcsharp_call_blocking_unary(grpc_call *call,
GPR_EXPORT grpc_call_error GPR_CALLTYPE
grpcsharp_call_start_client_streaming(grpc_call *call,
- callback_funcptr callback) {
+ callback_funcptr callback,
+ grpc_metadata_array *initial_metadata) {
/* TODO: don't use magic number */
grpc_op ops[4];
grpcsharp_batch_context *ctx = grpcsharp_batch_context_create();
ctx->callback = callback;
- /* TODO: implement sending the metadata... */
ops[0].op = GRPC_OP_SEND_INITIAL_METADATA;
- /* ctx->send_initial_metadata is already zeroed out. */
- ops[0].data.send_initial_metadata.count = 0;
- ops[0].data.send_initial_metadata.metadata = NULL;
+ grpcsharp_metadata_array_move(&(ctx->send_initial_metadata),
+ initial_metadata);
+ ops[0].data.send_initial_metadata.count = ctx->send_initial_metadata.count;
+ ops[0].data.send_initial_metadata.metadata =
+ ctx->send_initial_metadata.metadata;
ops[1].op = GRPC_OP_RECV_INITIAL_METADATA;
ops[1].data.recv_initial_metadata = &(ctx->recv_initial_metadata);
@@ -435,21 +522,20 @@ grpcsharp_call_start_client_streaming(grpc_call *call,
return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx);
}
-GPR_EXPORT grpc_call_error GPR_CALLTYPE
-grpcsharp_call_start_server_streaming(grpc_call *call,
- callback_funcptr callback,
- const char *send_buffer,
- size_t send_buffer_len) {
+GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_start_server_streaming(
+ grpc_call *call, callback_funcptr callback, const char *send_buffer,
+ size_t send_buffer_len, grpc_metadata_array *initial_metadata) {
/* TODO: don't use magic number */
grpc_op ops[5];
grpcsharp_batch_context *ctx = grpcsharp_batch_context_create();
ctx->callback = callback;
- /* TODO: implement sending the metadata... */
ops[0].op = GRPC_OP_SEND_INITIAL_METADATA;
- /* ctx->send_initial_metadata is already zeroed out. */
- ops[0].data.send_initial_metadata.count = 0;
- ops[0].data.send_initial_metadata.metadata = NULL;
+ grpcsharp_metadata_array_move(&(ctx->send_initial_metadata),
+ initial_metadata);
+ ops[0].data.send_initial_metadata.count = ctx->send_initial_metadata.count;
+ ops[0].data.send_initial_metadata.metadata =
+ ctx->send_initial_metadata.metadata;
ops[1].op = GRPC_OP_SEND_MESSAGE;
ctx->send_message = string_to_byte_buffer(send_buffer, send_buffer_len);
@@ -476,17 +562,19 @@ grpcsharp_call_start_server_streaming(grpc_call *call,
GPR_EXPORT grpc_call_error GPR_CALLTYPE
grpcsharp_call_start_duplex_streaming(grpc_call *call,
- callback_funcptr callback) {
+ callback_funcptr callback,
+ grpc_metadata_array *initial_metadata) {
/* TODO: don't use magic number */
grpc_op ops[3];
grpcsharp_batch_context *ctx = grpcsharp_batch_context_create();
ctx->callback = callback;
- /* TODO: implement sending the metadata... */
ops[0].op = GRPC_OP_SEND_INITIAL_METADATA;
- /* ctx->send_initial_metadata is already zeroed out. */
- ops[0].data.send_initial_metadata.count = 0;
- ops[0].data.send_initial_metadata.metadata = NULL;
+ grpcsharp_metadata_array_move(&(ctx->send_initial_metadata),
+ initial_metadata);
+ ops[0].data.send_initial_metadata.count = ctx->send_initial_metadata.count;
+ ops[0].data.send_initial_metadata.metadata =
+ ctx->send_initial_metadata.metadata;
ops[1].op = GRPC_OP_RECV_INITIAL_METADATA;
ops[1].data.recv_initial_metadata = &(ctx->recv_initial_metadata);
@@ -653,6 +741,41 @@ grpcsharp_secure_channel_create(grpc_credentials *creds, const char *target,
return grpc_secure_channel_create(creds, target, args);
}
+GPR_EXPORT grpc_server_credentials *GPR_CALLTYPE
+grpcsharp_ssl_server_credentials_create(
+ const char *pem_root_certs, const char **key_cert_pair_cert_chain_array,
+ const char **key_cert_pair_private_key_array, size_t num_key_cert_pairs) {
+ size_t i;
+ grpc_server_credentials *creds;
+ grpc_ssl_pem_key_cert_pair *key_cert_pairs =
+ gpr_malloc(sizeof(grpc_ssl_pem_key_cert_pair) * num_key_cert_pairs);
+ memset(key_cert_pairs, 0,
+ sizeof(grpc_ssl_pem_key_cert_pair) * num_key_cert_pairs);
+
+ for (i = 0; i < num_key_cert_pairs; i++) {
+ if (key_cert_pair_cert_chain_array[i] ||
+ key_cert_pair_private_key_array[i]) {
+ key_cert_pairs[i].cert_chain = key_cert_pair_cert_chain_array[i];
+ key_cert_pairs[i].private_key = key_cert_pair_private_key_array[i];
+ }
+ }
+ creds = grpc_ssl_server_credentials_create(pem_root_certs, key_cert_pairs,
+ num_key_cert_pairs);
+ gpr_free(key_cert_pairs);
+ return creds;
+}
+
+GPR_EXPORT void grpcsharp_server_credentials_release(
+ grpc_server_credentials *creds) {
+ grpc_server_credentials_release(creds);
+}
+
+GPR_EXPORT gpr_int32 GPR_CALLTYPE
+grpcsharp_server_add_secure_http2_port(grpc_server *server, const char *addr,
+ grpc_server_credentials *creds) {
+ return grpc_server_add_secure_http2_port(server, addr, creds);
+}
+
/* Logging */
typedef void(GPR_CALLTYPE *grpcsharp_log_func)(const char *file, gpr_int32 line,
diff --git a/src/node/README.md b/src/node/README.md
index 5b3de6b4f6..b1d2310ede 100644
--- a/src/node/README.md
+++ b/src/node/README.md
@@ -10,9 +10,9 @@ This requires `node` to be installed. If you instead have the `nodejs` executabl
## Installation
-First, clone this repository (NPM package coming soon). Then follow the instructions in the `INSTALL` file in the root of the repository to install the C core library that this package depends on.
-
-Then, simply run `npm install` in or referencing this directory.
+ 1. Clone [the grpc repository](https://github.com/grpc/grpc).
+ 2. Follow the instructions in the `INSTALL` file in the root of that repository to install the C core library that this package depends on.
+ 3. Run `npm install`.
## Tests
diff --git a/src/node/examples/qps_test.js b/src/node/examples/qps_test.js
new file mode 100644
index 0000000000..00293b464a
--- /dev/null
+++ b/src/node/examples/qps_test.js
@@ -0,0 +1,136 @@
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/**
+ * This script runs a QPS test. It sends requests for a specified length of time
+ * with a specified number pending at any one time. It then outputs the measured
+ * QPS. Usage:
+ * node qps_test.js [--concurrent=count] [--time=seconds]
+ * concurrent defaults to 100 and time defaults to 10
+ */
+
+'use strict';
+
+var async = require('async');
+var parseArgs = require('minimist');
+
+var grpc = require('..');
+var testProto = grpc.load(__dirname + '/../interop/test.proto').grpc.testing;
+var interop_server = require('../interop/interop_server.js');
+
+/**
+ * Runs the QPS test. Sends requests constantly for the given number of seconds,
+ * and keeps concurrent_calls requests pending at all times. When the test ends,
+ * the callback is called with the number of calls that completed within the
+ * time limit.
+ * @param {number} concurrent_calls The number of calls to have pending
+ * simultaneously
+ * @param {number} seconds The number of seconds to run the test for
+ * @param {function(Error, number)} callback Callback for test completion
+ */
+function runTest(concurrent_calls, seconds, callback) {
+ var testServer = interop_server.getServer(0, false);
+ testServer.server.listen();
+ var client = new testProto.TestService('localhost:' + testServer.port);
+
+ var warmup_num = 100;
+
+ /**
+ * Warms up the client to avoid counting startup time in the test result
+ * @param {function(Error)} callback Called when warmup is complete
+ */
+ function warmUp(callback) {
+ var pending = warmup_num;
+ function startCall() {
+ client.emptyCall({}, function(err, resp) {
+ if (err) {
+ callback(err);
+ return;
+ }
+ pending--;
+ if (pending === 0) {
+ callback(null);
+ }
+ });
+ }
+ for (var i = 0; i < warmup_num; i++) {
+ startCall();
+ }
+ }
+ /**
+ * Run the QPS test. Starts concurrent_calls requests, then starts a new
+ * request whenever one completes until time runs out.
+ * @param {function(Error, number)} callback Called when the test is complete.
+ * The second argument is the number of calls that finished within the
+ * time limit
+ */
+ function run(callback) {
+ var running = 0;
+ var count = 0;
+ var start = process.hrtime();
+ function responseCallback(err, resp) {
+ if (process.hrtime(start)[0] < seconds) {
+ count += 1;
+ client.emptyCall({}, responseCallback);
+ } else {
+ running -= 1;
+ if (running <= 0) {
+ callback(null, count);
+ }
+ }
+ }
+ for (var i = 0; i < concurrent_calls; i++) {
+ running += 1;
+ client.emptyCall({}, responseCallback);
+ }
+ }
+ async.waterfall([warmUp, run], function(err, count) {
+ testServer.server.shutdown();
+ callback(err, count);
+ });
+}
+
+if (require.main === module) {
+ var argv = parseArgs(process.argv.slice(2), {
+ default: {'concurrent': 100,
+ 'time': 10}
+ });
+ runTest(argv.concurrent, argv.time, function(err, count) {
+ if (err) {
+ throw err;
+ }
+ console.log('Concurrent calls:', argv.concurrent);
+ console.log('Time:', argv.time, 'seconds');
+ console.log('QPS:', (count/argv.time));
+ });
+}
diff --git a/src/node/ext/byte_buffer.cc b/src/node/ext/byte_buffer.cc
index 5235c8e083..82b54b518c 100644
--- a/src/node/ext/byte_buffer.cc
+++ b/src/node/ext/byte_buffer.cc
@@ -65,7 +65,7 @@ grpc_byte_buffer *BufferToByteBuffer(Handle<Value> buffer) {
Handle<Value> ByteBufferToBuffer(grpc_byte_buffer *buffer) {
NanEscapableScope();
if (buffer == NULL) {
- return NanNull();
+ return NanEscapeScope(NanNull());
}
size_t length = grpc_byte_buffer_length(buffer);
char *result = reinterpret_cast<char *>(calloc(length, sizeof(char)));
diff --git a/src/node/ext/call.cc b/src/node/ext/call.cc
index afb6541783..8cc3e38cd9 100644
--- a/src/node/ext/call.cc
+++ b/src/node/ext/call.cc
@@ -75,6 +75,9 @@ using v8::Value;
NanCallback *Call::constructor;
Persistent<FunctionTemplate> Call::fun_tpl;
+bool EndsWith(const char *str, const char *substr) {
+ return strcmp(str+strlen(str)-strlen(substr), substr) == 0;
+}
bool CreateMetadataArray(Handle<Object> metadata, grpc_metadata_array *array,
shared_ptr<Resources> resources) {
@@ -99,14 +102,19 @@ bool CreateMetadataArray(Handle<Object> metadata, grpc_metadata_array *array,
Handle<Value> value = values->Get(j);
grpc_metadata *current = &array->metadata[array->count];
current->key = **utf8_key;
- if (::node::Buffer::HasInstance(value)) {
- current->value = ::node::Buffer::Data(value);
- current->value_length = ::node::Buffer::Length(value);
- Persistent<Value> *handle = new Persistent<Value>();
- NanAssignPersistent(*handle, value);
- resources->handles.push_back(unique_ptr<PersistentHolder>(
- new PersistentHolder(handle)));
- } else if (value->IsString()) {
+ // Only allow binary headers for "-bin" keys
+ if (EndsWith(current->key, "-bin")) {
+ if (::node::Buffer::HasInstance(value)) {
+ current->value = ::node::Buffer::Data(value);
+ current->value_length = ::node::Buffer::Length(value);
+ Persistent<Value> *handle = new Persistent<Value>();
+ NanAssignPersistent(*handle, value);
+ resources->handles.push_back(unique_ptr<PersistentHolder>(
+ new PersistentHolder(handle)));
+ continue;
+ }
+ }
+ if (value->IsString()) {
Handle<String> string_value = value->ToString();
NanUtf8String *utf8_value = new NanUtf8String(string_value);
resources->strings.push_back(unique_ptr<NanUtf8String>(utf8_value));
@@ -146,9 +154,13 @@ Handle<Value> ParseMetadata(const grpc_metadata_array *metadata_array) {
array = NanNew<Array>(size_map[elem->key]);
metadata_object->Set(key_string, array);
}
- array->Set(index_map[elem->key],
- MakeFastBuffer(
- NanNewBufferHandle(elem->value, elem->value_length)));
+ if (EndsWith(elem->key, "-bin")) {
+ array->Set(index_map[elem->key],
+ MakeFastBuffer(
+ NanNewBufferHandle(elem->value, elem->value_length)));
+ } else {
+ array->Set(index_map[elem->key], NanNew(elem->value));
+ }
index_map[elem->key] += 1;
}
return NanEscapeScope(metadata_object);
diff --git a/src/node/ext/completion_queue_async_worker.cc b/src/node/ext/completion_queue_async_worker.cc
index ca22527e6f..cd7acd1d1b 100644
--- a/src/node/ext/completion_queue_async_worker.cc
+++ b/src/node/ext/completion_queue_async_worker.cc
@@ -80,7 +80,6 @@ void CompletionQueueAsyncWorker::HandleOKCallback() {
NanScope();
NanCallback *callback = GetTagCallback(result->tag);
Handle<Value> argv[] = {NanNull(), GetTagNodeValue(result->tag)};
-
callback->Call(2, argv);
DestroyTag(result->tag);
diff --git a/src/node/index.js b/src/node/index.js
index ad3dd96af7..0b768edc6b 100644
--- a/src/node/index.js
+++ b/src/node/index.js
@@ -56,7 +56,7 @@ function loadObject(value) {
});
return result;
} else if (value.className === 'Service') {
- return client.makeClientConstructor(value);
+ return client.makeProtobufClientConstructor(value);
} else if (value.className === 'Message' || value.className === 'Enum') {
return value.build();
} else {
@@ -119,7 +119,7 @@ exports.load = load;
/**
* See docs for server.makeServerConstructor
*/
-exports.buildServer = server.makeServerConstructor;
+exports.buildServer = server.makeProtobufServerConstructor;
/**
* Status name to code number mapping
@@ -141,3 +141,7 @@ exports.Credentials = grpc.Credentials;
exports.ServerCredentials = grpc.ServerCredentials;
exports.getGoogleAuthDelegate = getGoogleAuthDelegate;
+
+exports.makeGenericClientConstructor = client.makeClientConstructor;
+
+exports.makeGenericServerConstructor = server.makeServerConstructor;
diff --git a/src/node/interop/interop_client.js b/src/node/interop/interop_client.js
index 8060baf827..77804cf595 100644
--- a/src/node/interop/interop_client.js
+++ b/src/node/interop/interop_client.js
@@ -35,6 +35,7 @@
var fs = require('fs');
var path = require('path');
+var _ = require('underscore');
var grpc = require('..');
var testProto = grpc.load(__dirname + '/test.proto').grpc.testing;
var GoogleAuth = require('google-auth-library');
@@ -45,6 +46,8 @@ var AUTH_SCOPE = 'https://www.googleapis.com/auth/xapi.zoo';
var AUTH_SCOPE_RESPONSE = 'xapi.zoo';
var AUTH_USER = ('155450119199-3psnrh1sdr3d8cpj1v46naggf81mhdnk' +
'@developer.gserviceaccount.com');
+var COMPUTE_ENGINE_USER = ('155450119199-r5aaqa2vqoa9g5mv2m6s3m1l293rlmel' +
+ '@developer.gserviceaccount.com');
/**
* Create a buffer filled with size zeroes
@@ -265,11 +268,12 @@ function cancelAfterFirstResponse(client, done) {
/**
* Run one of the authentication tests.
+ * @param {string} expected_user The expected username in the response
* @param {Client} client The client to test against
* @param {function} done Callback to call when the test is completed. Included
* primarily for use with mocha
*/
-function authTest(client, done) {
+function authTest(expected_user, client, done) {
(new GoogleAuth()).getApplicationDefault(function(err, credential) {
assert.ifError(err);
if (credential.createScopedRequired()) {
@@ -290,7 +294,7 @@ function authTest(client, done) {
assert.strictEqual(resp.payload.type, testProto.PayloadType.COMPRESSABLE);
assert.strictEqual(resp.payload.body.limit - resp.payload.body.offset,
314159);
- assert.strictEqual(resp.username, AUTH_USER);
+ assert.strictEqual(resp.username, expected_user);
assert.strictEqual(resp.oauth_scope, AUTH_SCOPE_RESPONSE);
});
call.on('status', function(status) {
@@ -314,8 +318,8 @@ var test_cases = {
empty_stream: emptyStream,
cancel_after_begin: cancelAfterBegin,
cancel_after_first_response: cancelAfterFirstResponse,
- compute_engine_creds: authTest,
- service_account_creds: authTest
+ compute_engine_creds: _.partial(authTest, AUTH_USER),
+ service_account_creds: _.partial(authTest, COMPUTE_ENGINE_USER)
};
/**
diff --git a/src/node/package.json b/src/node/package.json
index 20eb21fc47..9f52f8c988 100644
--- a/src/node/package.json
+++ b/src/node/package.json
@@ -1,6 +1,6 @@
{
"name": "grpc",
- "version": "0.5.2",
+ "version": "0.6.0",
"author": "Google Inc.",
"description": "gRPC Library for Node",
"homepage": "http://www.grpc.io/",
@@ -26,7 +26,7 @@
"dependencies": {
"bindings": "^1.2.0",
"nan": "^1.5.0",
- "protobufjs": "murgatroid99/ProtoBuf.js",
+ "protobufjs": "^4.0.0-b2",
"underscore": "^1.6.0",
"underscore.string": "^3.0.0"
},
diff --git a/src/node/src/client.js b/src/node/src/client.js
index 54b8dbdc9c..c46f7d0526 100644
--- a/src/node/src/client.js
+++ b/src/node/src/client.js
@@ -35,9 +35,6 @@
var _ = require('underscore');
-var capitalize = require('underscore.string/capitalize');
-var decapitalize = require('underscore.string/decapitalize');
-
var grpc = require('bindings')('grpc.node');
var common = require('./common.js');
@@ -463,13 +460,18 @@ var requester_makers = {
};
/**
- * Creates a constructor for clients for the given service
- * @param {ProtoBuf.Reflect.Service} service The service to generate a client
- * for
+ * Creates a constructor for a client with the given methods. The methods object
+ * maps method name to an object with the following keys:
+ * path: The path on the server for accessing the method. For example, for
+ * protocol buffers, we use "/service_name/method_name"
+ * requestStream: bool indicating whether the client sends a stream
+ * resonseStream: bool indicating whether the server sends a stream
+ * requestSerialize: function to serialize request objects
+ * responseDeserialize: function to deserialize response objects
+ * @param {Object} methods An object mapping method names to method attributes
* @return {function(string, Object)} New client constructor
*/
-function makeClientConstructor(service) {
- var prefix = '/' + common.fullyQualifiedName(service) + '/';
+function makeClientConstructor(methods) {
/**
* Create a client with the given methods
* @constructor
@@ -489,30 +491,41 @@ function makeClientConstructor(service) {
this.channel = new grpc.Channel(address, options);
}
- _.each(service.children, function(method) {
+ _.each(methods, function(attrs, name) {
var method_type;
- if (method.requestStream) {
- if (method.responseStream) {
+ if (attrs.requestStream) {
+ if (attrs.responseStream) {
method_type = 'bidi';
} else {
method_type = 'client_stream';
}
} else {
- if (method.responseStream) {
+ if (attrs.responseStream) {
method_type = 'server_stream';
} else {
method_type = 'unary';
}
}
- var serialize = common.serializeCls(method.resolvedRequestType.build());
- var deserialize = common.deserializeCls(
- method.resolvedResponseType.build());
- Client.prototype[decapitalize(method.name)] = requester_makers[method_type](
- prefix + capitalize(method.name), serialize, deserialize);
- Client.prototype[decapitalize(method.name)].serialize = serialize;
- Client.prototype[decapitalize(method.name)].deserialize = deserialize;
+ var serialize = attrs.requestSerialize;
+ var deserialize = attrs.responseDeserialize;
+ Client.prototype[name] = requester_makers[method_type](
+ attrs.path, serialize, deserialize);
+ Client.prototype[name].serialize = serialize;
+ Client.prototype[name].deserialize = deserialize;
});
+ return Client;
+}
+
+/**
+ * Creates a constructor for clients for the given service
+ * @param {ProtoBuf.Reflect.Service} service The service to generate a client
+ * for
+ * @return {function(string, Object)} New client constructor
+ */
+function makeProtobufClientConstructor(service) {
+ var method_attrs = common.getProtobufServiceAttrs(service);
+ var Client = makeClientConstructor(method_attrs);
Client.service = service;
return Client;
@@ -520,6 +533,8 @@ function makeClientConstructor(service) {
exports.makeClientConstructor = makeClientConstructor;
+exports.makeProtobufClientConstructor = makeProtobufClientConstructor;
+
/**
* See docs for client.status
*/
diff --git a/src/node/src/common.js b/src/node/src/common.js
index eec8f0f987..55a6b13782 100644
--- a/src/node/src/common.js
+++ b/src/node/src/common.js
@@ -36,6 +36,7 @@
var _ = require('underscore');
var capitalize = require('underscore.string/capitalize');
+var decapitalize = require('underscore.string/decapitalize');
/**
* Get a function that deserializes a specific type of protobuf.
@@ -110,6 +111,26 @@ function wrapIgnoreNull(func) {
}
/**
+ * Return a map from method names to method attributes for the service.
+ * @param {ProtoBuf.Reflect.Service} service The service to get attributes for
+ * @return {Object} The attributes map
+ */
+function getProtobufServiceAttrs(service) {
+ var prefix = '/' + fullyQualifiedName(service) + '/';
+ return _.object(_.map(service.children, function(method) {
+ return [decapitalize(method.name), {
+ path: prefix + capitalize(method.name),
+ requestStream: method.requestStream,
+ responseStream: method.responseStream,
+ requestSerialize: serializeCls(method.resolvedRequestType.build()),
+ requestDeserialize: deserializeCls(method.resolvedRequestType.build()),
+ responseSerialize: serializeCls(method.resolvedResponseType.build()),
+ responseDeserialize: deserializeCls(method.resolvedResponseType.build())
+ }];
+ }));
+}
+
+/**
* See docs for deserializeCls
*/
exports.deserializeCls = deserializeCls;
@@ -128,3 +149,5 @@ exports.fullyQualifiedName = fullyQualifiedName;
* See docs for wrapIgnoreNull
*/
exports.wrapIgnoreNull = wrapIgnoreNull;
+
+exports.getProtobufServiceAttrs = getProtobufServiceAttrs;
diff --git a/src/node/src/server.js b/src/node/src/server.js
index b72d110666..8a26a43606 100644
--- a/src/node/src/server.js
+++ b/src/node/src/server.js
@@ -35,9 +35,6 @@
var _ = require('underscore');
-var capitalize = require('underscore.string/capitalize');
-var decapitalize = require('underscore.string/decapitalize');
-
var grpc = require('bindings')('grpc.node');
var common = require('./common');
@@ -532,26 +529,20 @@ Server.prototype.bind = function(port, creds) {
};
/**
- * Creates a constructor for servers with a service defined by the methods
- * object. The methods object has string keys and values of this form:
- * {serialize: function, deserialize: function, client_stream: bool,
- * server_stream: bool}
- * @param {Object} methods Method descriptor for each method the server should
- * expose
- * @param {string} prefix The prefex to prepend to each method name
- * @return {function(Object, Object)} New server constructor
+ * Create a constructor for servers with services defined by service_attr_map.
+ * That is an object that maps (namespaced) service names to objects that in
+ * turn map method names to objects with the following keys:
+ * path: The path on the server for accessing the method. For example, for
+ * protocol buffers, we use "/service_name/method_name"
+ * requestStream: bool indicating whether the client sends a stream
+ * resonseStream: bool indicating whether the server sends a stream
+ * requestDeserialize: function to deserialize request objects
+ * responseSerialize: function to serialize response objects
+ * @param {Object} service_attr_map An object mapping service names to method
+ * attribute map objects
+ * @return {function(Object, function, Object=)} New server constructor
*/
-function makeServerConstructor(services) {
- var qual_names = [];
- _.each(services, function(service) {
- _.each(service.children, function(method) {
- var name = common.fullyQualifiedName(method);
- if (_.indexOf(qual_names, name) !== -1) {
- throw new Error('Method ' + name + ' exposed by more than one service');
- }
- qual_names.push(name);
- });
- });
+function makeServerConstructor(service_attr_map) {
/**
* Create a server with the given handlers for all of the methods.
* @constructor
@@ -565,41 +556,34 @@ function makeServerConstructor(services) {
function SurfaceServer(service_handlers, getMetadata, options) {
var server = new Server(getMetadata, options);
this.inner_server = server;
- _.each(services, function(service) {
- var service_name = common.fullyQualifiedName(service);
+ _.each(service_attr_map, function(service_attrs, service_name) {
if (service_handlers[service_name] === undefined) {
throw new Error('Handlers for service ' +
service_name + ' not provided.');
}
- var prefix = '/' + common.fullyQualifiedName(service) + '/';
- _.each(service.children, function(method) {
+ _.each(service_attrs, function(attrs, name) {
var method_type;
- if (method.requestStream) {
- if (method.responseStream) {
+ if (attrs.requestStream) {
+ if (attrs.responseStream) {
method_type = 'bidi';
} else {
method_type = 'client_stream';
}
} else {
- if (method.responseStream) {
+ if (attrs.responseStream) {
method_type = 'server_stream';
} else {
method_type = 'unary';
}
}
- if (service_handlers[service_name][decapitalize(method.name)] ===
- undefined) {
- throw new Error('Method handler for ' +
- common.fullyQualifiedName(method) + ' not provided.');
+ if (service_handlers[service_name][name] === undefined) {
+ throw new Error('Method handler for ' + attrs.path +
+ ' not provided.');
}
- var serialize = common.serializeCls(
- method.resolvedResponseType.build());
- var deserialize = common.deserializeCls(
- method.resolvedRequestType.build());
- server.register(
- prefix + capitalize(method.name),
- service_handlers[service_name][decapitalize(method.name)],
- serialize, deserialize, method_type);
+ var serialize = attrs.responseSerialize;
+ var deserialize = attrs.requestDeserialize;
+ server.register(attrs.path, service_handlers[service_name][name],
+ serialize, deserialize, method_type);
});
}, this);
}
@@ -636,6 +620,39 @@ function makeServerConstructor(services) {
}
/**
+ * Create a constructor for servers that serve the given services.
+ * @param {Array<ProtoBuf.Reflect.Service>} services The services that the
+ * servers will serve
+ * @return {function(Object, function, Object=)} New server constructor
+ */
+function makeProtobufServerConstructor(services) {
+ var qual_names = [];
+ var service_attr_map = {};
+ _.each(services, function(service) {
+ var service_name = common.fullyQualifiedName(service);
+ _.each(service.children, function(method) {
+ var name = common.fullyQualifiedName(method);
+ if (_.indexOf(qual_names, name) !== -1) {
+ throw new Error('Method ' + name + ' exposed by more than one service');
+ }
+ qual_names.push(name);
+ });
+ var method_attrs = common.getProtobufServiceAttrs(service);
+ if (!service_attr_map.hasOwnProperty(service_name)) {
+ service_attr_map[service_name] = {};
+ }
+ service_attr_map[service_name] = _.extend(service_attr_map[service_name],
+ method_attrs);
+ });
+ return makeServerConstructor(service_attr_map);
+}
+
+/**
* See documentation for makeServerConstructor
*/
exports.makeServerConstructor = makeServerConstructor;
+
+/**
+ * See documentation for makeProtobufServerConstructor
+ */
+exports.makeProtobufServerConstructor = makeProtobufServerConstructor;
diff --git a/src/node/test/call_test.js b/src/node/test/call_test.js
index 7b2b36ae37..98158ffff3 100644
--- a/src/node/test/call_test.js
+++ b/src/node/test/call_test.js
@@ -142,8 +142,8 @@ describe('call', function() {
assert.doesNotThrow(function() {
var batch = {};
batch[grpc.opType.SEND_INITIAL_METADATA] = {
- 'key1': [new Buffer('value1')],
- 'key2': [new Buffer('value2')]
+ 'key1-bin': [new Buffer('value1')],
+ 'key2-bin': [new Buffer('value2')]
};
call.startBatch(batch, function(err, resp) {
assert.ifError(err);
diff --git a/src/node/test/end_to_end_test.js b/src/node/test/end_to_end_test.js
index 1cc1928691..60e9861bc8 100644
--- a/src/node/test/end_to_end_test.js
+++ b/src/node/test/end_to_end_test.js
@@ -138,21 +138,21 @@ describe('end-to-end', function() {
client_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true;
call.startBatch(client_batch, function(err, response) {
assert.ifError(err);
- assert(response['send metadata']);
- assert(response['client close']);
- assert(response.hasOwnProperty('metadata'));
- assert.strictEqual(response.metadata.server_key[0].toString(),
- 'server_value');
- assert.deepEqual(response.status, {'code': grpc.status.OK,
- 'details': status_text,
- 'metadata': {}});
+ assert.deepEqual(response,{
+ 'send metadata': true,
+ 'client close': true,
+ metadata: {server_key: ['server_value']},
+ status: {'code': grpc.status.OK,
+ 'details': status_text,
+ 'metadata': {}}
+ });
done();
});
server.requestCall(function(err, call_details) {
var new_call = call_details['new call'];
assert.notEqual(new_call, null);
- assert.strictEqual(new_call.metadata.client_key[0].toString(),
+ assert.strictEqual(new_call.metadata.client_key[0],
'client_value');
var server_call = new_call.call;
assert.notEqual(server_call, null);
@@ -235,4 +235,73 @@ describe('end-to-end', function() {
});
});
});
+ it('should send multiple messages', function(complete) {
+ var done = multiDone(complete, 2);
+ var requests = ['req1', 'req2'];
+ var deadline = new Date();
+ deadline.setSeconds(deadline.getSeconds() + 3);
+ var status_text = 'xyz';
+ var call = new grpc.Call(channel,
+ 'dummy_method',
+ Infinity);
+ var client_batch = {};
+ client_batch[grpc.opType.SEND_INITIAL_METADATA] = {};
+ client_batch[grpc.opType.SEND_MESSAGE] = new Buffer(requests[0]);
+ client_batch[grpc.opType.RECV_INITIAL_METADATA] = true;
+ call.startBatch(client_batch, function(err, response) {
+ assert.ifError(err);
+ assert.deepEqual(response, {
+ 'send metadata': true,
+ 'send message': true,
+ 'metadata': {}
+ });
+ var req2_batch = {};
+ req2_batch[grpc.opType.SEND_MESSAGE] = new Buffer(requests[1]);
+ req2_batch[grpc.opType.SEND_CLOSE_FROM_CLIENT] = true;
+ req2_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true;
+ call.startBatch(req2_batch, function(err, resp) {
+ assert.ifError(err);
+ assert.deepEqual(resp, {
+ 'send message': true,
+ 'client close': true,
+ 'status': {
+ 'code': grpc.status.OK,
+ 'details': status_text,
+ 'metadata': {}
+ }
+ });
+ done();
+ });
+ });
+
+ server.requestCall(function(err, call_details) {
+ var new_call = call_details['new call'];
+ assert.notEqual(new_call, null);
+ var server_call = new_call.call;
+ assert.notEqual(server_call, null);
+ var server_batch = {};
+ server_batch[grpc.opType.SEND_INITIAL_METADATA] = {};
+ server_batch[grpc.opType.RECV_MESSAGE] = true;
+ server_call.startBatch(server_batch, function(err, response) {
+ assert.ifError(err);
+ assert(response['send metadata']);
+ assert.strictEqual(response.read.toString(), requests[0]);
+ var end_batch = {};
+ end_batch[grpc.opType.RECV_CLOSE_ON_SERVER] = true;
+ end_batch[grpc.opType.SEND_STATUS_FROM_SERVER] = {
+ 'metadata': {},
+ 'code': grpc.status.OK,
+ 'details': status_text
+ };
+ end_batch[grpc.opType.RECV_MESSAGE] = true;
+ server_call.startBatch(end_batch, function(err, response) {
+ assert.ifError(err);
+ assert(response['send status']);
+ assert(!response.cancelled);
+ assert.strictEqual(response.read.toString(), requests[1]);
+ done();
+ });
+ });
+ });
+ });
});
diff --git a/src/node/test/server_test.js b/src/node/test/server_test.js
new file mode 100644
index 0000000000..7cb34fa0cb
--- /dev/null
+++ b/src/node/test/server_test.js
@@ -0,0 +1,94 @@
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+'use strict';
+
+var assert = require('assert');
+var grpc = require('bindings')('grpc.node');
+
+describe('server', function() {
+ describe('constructor', function() {
+ it('should work with no arguments', function() {
+ assert.doesNotThrow(function() {
+ new grpc.Server();
+ });
+ });
+ it('should work with an empty list argument', function() {
+ assert.doesNotThrow(function() {
+ new grpc.Server([]);
+ });
+ });
+ });
+ describe('addHttp2Port', function() {
+ var server;
+ before(function() {
+ server = new grpc.Server();
+ });
+ it('should bind to an unused port', function() {
+ var port;
+ assert.doesNotThrow(function() {
+ port = server.addHttp2Port('0.0.0.0:0');
+ });
+ assert(port > 0);
+ });
+ });
+ describe('addSecureHttp2Port', function() {
+ var server;
+ before(function() {
+ server = new grpc.Server();
+ });
+ it('should bind to an unused port with fake credentials', function() {
+ var port;
+ var creds = grpc.ServerCredentials.createFake();
+ assert.doesNotThrow(function() {
+ port = server.addSecureHttp2Port('0.0.0.0:0', creds);
+ });
+ assert(port > 0);
+ });
+ });
+ describe('listen', function() {
+ var server;
+ before(function() {
+ server = new grpc.Server();
+ server.addHttp2Port('0.0.0.0:0');
+ });
+ after(function() {
+ server.shutdown();
+ });
+ it('should listen without error', function() {
+ assert.doesNotThrow(function() {
+ server.start();
+ });
+ });
+ });
+});
diff --git a/src/node/test/surface_test.js b/src/node/test/surface_test.js
index 91d8197bee..96b47815e1 100644
--- a/src/node/test/surface_test.js
+++ b/src/node/test/surface_test.js
@@ -45,6 +45,8 @@ var math_proto = ProtoBuf.loadProtoFile(__dirname + '/../examples/math.proto');
var mathService = math_proto.lookup('math.Math');
+var capitalize = require('underscore.string/capitalize');
+
describe('Surface server constructor', function() {
it('Should fail with conflicting method names', function() {
assert.throws(function() {
@@ -75,6 +77,55 @@ describe('Surface server constructor', function() {
}, /math.Math/);
});
});
+describe('Generic client and server', function() {
+ function toString(val) {
+ return val.toString();
+ }
+ function toBuffer(str) {
+ return new Buffer(str);
+ }
+ var string_service_attrs = {
+ 'capitalize' : {
+ path: '/string/capitalize',
+ requestStream: false,
+ responseStream: false,
+ requestSerialize: toBuffer,
+ requestDeserialize: toString,
+ responseSerialize: toBuffer,
+ responseDeserialize: toString
+ }
+ };
+ describe('String client and server', function() {
+ var client;
+ var server;
+ before(function() {
+ var Server = grpc.makeGenericServerConstructor({
+ string: string_service_attrs
+ });
+ server = new Server({
+ string: {
+ capitalize: function(call, callback) {
+ callback(null, capitalize(call.request));
+ }
+ }
+ });
+ var port = server.bind('localhost:0');
+ server.listen();
+ var Client = grpc.makeGenericClientConstructor(string_service_attrs);
+ client = new Client('localhost:' + port);
+ });
+ after(function() {
+ server.shutdown();
+ });
+ it('Should respond with a capitalized string', function(done) {
+ client.capitalize('abc', function(err, response) {
+ assert.ifError(err);
+ assert.strictEqual(response, 'Abc');
+ done();
+ });
+ });
+ });
+});
describe('Cancelling surface client', function() {
var client;
var server;
@@ -89,7 +140,7 @@ describe('Cancelling surface client', function() {
}
});
var port = server.bind('localhost:0');
- var Client = surface_client.makeClientConstructor(mathService);
+ var Client = surface_client.makeProtobufClientConstructor(mathService);
client = new Client('localhost:' + port);
});
after(function() {
diff --git a/src/php/ext/grpc/byte_buffer.c b/src/php/ext/grpc/byte_buffer.c
index 1ced1bf3f0..9f122d6da6 100644
--- a/src/php/ext/grpc/byte_buffer.c
+++ b/src/php/ext/grpc/byte_buffer.c
@@ -57,6 +57,11 @@ grpc_byte_buffer *string_to_byte_buffer(char *string, size_t length) {
void byte_buffer_to_string(grpc_byte_buffer *buffer, char **out_string,
size_t *out_length) {
+ if (buffer == NULL) {
+ *out_string = NULL;
+ *out_length = 0;
+ return;
+ }
size_t length = grpc_byte_buffer_length(buffer);
char *string = ecalloc(length + 1, sizeof(char));
size_t offset = 0;
diff --git a/src/php/ext/grpc/call.c b/src/php/ext/grpc/call.c
index df0635dc72..ba1b2a407d 100644
--- a/src/php/ext/grpc/call.c
+++ b/src/php/ext/grpc/call.c
@@ -49,17 +49,31 @@
#include <stdbool.h>
#include "grpc/support/log.h"
+#include "grpc/support/alloc.h"
#include "grpc/grpc.h"
#include "timeval.h"
#include "channel.h"
-#include "completion_queue.h"
#include "byte_buffer.h"
+zend_class_entry *grpc_ce_call;
+
/* Frees and destroys an instance of wrapped_grpc_call */
void free_wrapped_grpc_call(void *object TSRMLS_DC) {
wrapped_grpc_call *call = (wrapped_grpc_call *)object;
+ grpc_event *event;
if (call->owned && call->wrapped != NULL) {
+ if (call->queue != NULL) {
+ grpc_completion_queue_shutdown(call->queue);
+ event = grpc_completion_queue_next(call->queue, gpr_inf_future);
+ while (event != NULL) {
+ if (event->type == GRPC_QUEUE_SHUTDOWN) {
+ break;
+ }
+ event = grpc_completion_queue_next(call->queue, gpr_inf_future);
+ }
+ grpc_completion_queue_destroy(call->queue);
+ }
grpc_call_destroy(call->wrapped);
}
efree(call);
@@ -86,17 +100,23 @@ zend_object_value create_wrapped_grpc_call(zend_class_entry *class_type
/* Wraps a grpc_call struct in a PHP object. Owned indicates whether the struct
should be destroyed at the end of the object's lifecycle */
-zval *grpc_php_wrap_call(grpc_call *wrapped, bool owned) {
+zval *grpc_php_wrap_call(grpc_call *wrapped, grpc_completion_queue *queue,
+ bool owned) {
zval *call_object;
MAKE_STD_ZVAL(call_object);
object_init_ex(call_object, grpc_ce_call);
wrapped_grpc_call *call =
(wrapped_grpc_call *)zend_object_store_get_object(call_object TSRMLS_CC);
call->wrapped = wrapped;
+ call->queue = queue;
return call_object;
}
-zval *grpc_call_create_metadata_array(int count, grpc_metadata *elements) {
+/* Creates and returns a PHP array object with the data in a
+ * grpc_metadata_array. Returns NULL on failure */
+zval *grpc_parse_metadata_array(grpc_metadata_array *metadata_array) {
+ int count = metadata_array->count;
+ grpc_metadata *elements = metadata_array->metadata;
int i;
zval *array;
zval **data = NULL;
@@ -137,6 +157,64 @@ zval *grpc_call_create_metadata_array(int count, grpc_metadata *elements) {
return array;
}
+/* Populates a grpc_metadata_array with the data in a PHP array object.
+ Returns true on success and false on failure */
+bool create_metadata_array(zval *array, grpc_metadata_array *metadata) {
+ zval **inner_array;
+ zval **value;
+ HashTable *array_hash;
+ HashPosition array_pointer;
+ HashTable *inner_array_hash;
+ HashPosition inner_array_pointer;
+ char *key;
+ uint key_len;
+ ulong index;
+ if (Z_TYPE_P(array) != IS_ARRAY) {
+ return false;
+ }
+ grpc_metadata_array_init(metadata);
+ array_hash = Z_ARRVAL_P(array);
+ for (zend_hash_internal_pointer_reset_ex(array_hash, &array_pointer);
+ zend_hash_get_current_data_ex(array_hash, (void**)&inner_array,
+ &array_pointer) == SUCCESS;
+ zend_hash_move_forward_ex(array_hash, &array_pointer)) {
+ if (zend_hash_get_current_key_ex(array_hash, &key, &key_len, &index, 0,
+ &array_pointer) != HASH_KEY_IS_STRING) {
+ return false;
+ }
+ if (Z_TYPE_P(*inner_array) != IS_ARRAY) {
+ return false;
+ }
+ inner_array_hash = Z_ARRVAL_P(*inner_array);
+ metadata->capacity += zend_hash_num_elements(inner_array_hash);
+ }
+ metadata->metadata = gpr_malloc(metadata->capacity * sizeof(grpc_metadata));
+ for (zend_hash_internal_pointer_reset_ex(array_hash, &array_pointer);
+ zend_hash_get_current_data_ex(array_hash, (void**)&inner_array,
+ &array_pointer) == SUCCESS;
+ zend_hash_move_forward_ex(array_hash, &array_pointer)) {
+ if (zend_hash_get_current_key_ex(array_hash, &key, &key_len, &index, 0,
+ &array_pointer) != HASH_KEY_IS_STRING) {
+ return false;
+ }
+ inner_array_hash = Z_ARRVAL_P(*inner_array);
+ for (zend_hash_internal_pointer_reset_ex(inner_array_hash,
+ &inner_array_pointer);
+ zend_hash_get_current_data_ex(inner_array_hash, (void**)&value,
+ &inner_array_pointer) == SUCCESS;
+ zend_hash_move_forward_ex(inner_array_hash, &inner_array_pointer)) {
+ if (Z_TYPE_P(*value) != IS_STRING) {
+ return false;
+ }
+ metadata->metadata[metadata->count].key = key;
+ metadata->metadata[metadata->count].value = Z_STRVAL_P(*value);
+ metadata->metadata[metadata->count].value_length = Z_STRLEN_P(*value);
+ metadata->count += 1;
+ }
+ }
+ return true;
+}
+
/**
* Constructs a new instance of the Call class.
* @param Channel $channel The channel to associate the call with. Must not be
@@ -155,9 +233,10 @@ PHP_METHOD(Call, __construct) {
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "OsO", &channel_obj,
grpc_ce_channel, &method, &method_len,
&deadline_obj, grpc_ce_timeval) == FAILURE) {
- zend_throw_exception(spl_ce_InvalidArgumentException,
- "Call expects a Channel, a String, and a Timeval",
- 1 TSRMLS_CC);
+ zend_throw_exception(
+ spl_ce_InvalidArgumentException,
+ "Call expects a Channel, a String, and a Timeval",
+ 1 TSRMLS_CC);
return;
}
wrapped_grpc_channel *channel =
@@ -173,289 +252,250 @@ PHP_METHOD(Call, __construct) {
wrapped_grpc_timeval *deadline =
(wrapped_grpc_timeval *)zend_object_store_get_object(
deadline_obj TSRMLS_CC);
- call->wrapped = grpc_channel_create_call_old(
- channel->wrapped, method, channel->target, deadline->wrapped);
+ call->queue = grpc_completion_queue_create();
+ call->wrapped = grpc_channel_create_call(
+ channel->wrapped, call->queue, method, channel->target,
+ deadline->wrapped);
}
/**
- * Add metadata to the call. All array keys must be strings. If the value is a
- * string, it is added as a key/value pair. If it is an array, each value is
- * added paired with the same string
- * @param array $metadata The metadata to add
- * @param long $flags A bitwise combination of the Grpc\WRITE_* constants
- * (optional)
- * @return Void
+ * Start a batch of RPC actions.
+ * @param array batch Array of actions to take
+ * @return object Object with results of all actions
*/
-PHP_METHOD(Call, add_metadata) {
+PHP_METHOD(Call, start_batch) {
wrapped_grpc_call *call =
(wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC);
- grpc_metadata metadata;
- grpc_call_error error_code;
+ grpc_op ops[8];
+ size_t op_num = 0;
zval *array;
- zval **inner_array;
zval **value;
+ zval **inner_value;
HashTable *array_hash;
HashPosition array_pointer;
- HashTable *inner_array_hash;
- HashPosition inner_array_pointer;
+ HashTable *status_hash;
char *key;
uint key_len;
ulong index;
- long flags = 0;
- /* "a|l" == 1 array, 1 optional long */
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|l", &array, &flags) ==
+ grpc_metadata_array metadata;
+ grpc_metadata_array trailing_metadata;
+ grpc_metadata_array recv_metadata;
+ grpc_metadata_array recv_trailing_metadata;
+ grpc_status_code status;
+ char *status_details = NULL;
+ size_t status_details_capacity = 0;
+ grpc_byte_buffer *message;
+ int cancelled;
+ grpc_call_error error;
+ grpc_event *event;
+ zval *result;
+ char *message_str;
+ size_t message_len;
+ zval *recv_status;
+ grpc_metadata_array_init(&metadata);
+ grpc_metadata_array_init(&trailing_metadata);
+ grpc_metadata_array_init(&recv_metadata);
+ grpc_metadata_array_init(&recv_trailing_metadata);
+ MAKE_STD_ZVAL(result);
+ object_init(result);
+ /* "a" == 1 array */
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &array) ==
FAILURE) {
zend_throw_exception(spl_ce_InvalidArgumentException,
- "add_metadata expects an array and an optional long",
- 1 TSRMLS_CC);
- return;
+ "start_batch expects an array", 1 TSRMLS_CC);
+ goto cleanup;
}
array_hash = Z_ARRVAL_P(array);
for (zend_hash_internal_pointer_reset_ex(array_hash, &array_pointer);
- zend_hash_get_current_data_ex(array_hash, (void**)&inner_array,
+ zend_hash_get_current_data_ex(array_hash, (void**)&value,
&array_pointer) == SUCCESS;
zend_hash_move_forward_ex(array_hash, &array_pointer)) {
if (zend_hash_get_current_key_ex(array_hash, &key, &key_len, &index, 0,
- &array_pointer) != HASH_KEY_IS_STRING) {
- zend_throw_exception(spl_ce_InvalidArgumentException,
- "metadata keys must be strings", 1 TSRMLS_CC);
- return;
- }
- if (Z_TYPE_P(*inner_array) != IS_ARRAY) {
+ &array_pointer) != HASH_KEY_IS_LONG) {
zend_throw_exception(spl_ce_InvalidArgumentException,
- "metadata values must be arrays",
- 1 TSRMLS_CC);
- return;
+ "batch keys must be integers", 1 TSRMLS_CC);
+ goto cleanup;
}
- inner_array_hash = Z_ARRVAL_P(*inner_array);
- for (zend_hash_internal_pointer_reset_ex(inner_array_hash,
- &inner_array_pointer);
- zend_hash_get_current_data_ex(inner_array_hash, (void**)&value,
- &inner_array_pointer) == SUCCESS;
- zend_hash_move_forward_ex(inner_array_hash, &inner_array_pointer)) {
- if (Z_TYPE_P(*value) != IS_STRING) {
+ switch(index) {
+ case GRPC_OP_SEND_INITIAL_METADATA:
+ if (!create_metadata_array(*value, &metadata)) {
+ zend_throw_exception(spl_ce_InvalidArgumentException,
+ "Bad metadata value given", 1 TSRMLS_CC);
+ goto cleanup;
+ }
+ ops[op_num].data.send_initial_metadata.count =
+ metadata.count;
+ ops[op_num].data.send_initial_metadata.metadata =
+ metadata.metadata;
+ break;
+ case GRPC_OP_SEND_MESSAGE:
+ if (Z_TYPE_PP(value) != IS_STRING) {
+ zend_throw_exception(spl_ce_InvalidArgumentException,
+ "Expected a string for send message",
+ 1 TSRMLS_CC);
+ }
+ ops[op_num].data.send_message =
+ string_to_byte_buffer(Z_STRVAL_PP(value), Z_STRLEN_PP(value));
+ break;
+ case GRPC_OP_SEND_CLOSE_FROM_CLIENT:
+ break;
+ case GRPC_OP_SEND_STATUS_FROM_SERVER:
+ status_hash = Z_ARRVAL_PP(value);
+ if (zend_hash_find(status_hash, "metadata", sizeof("metadata"),
+ (void **)&inner_value) == SUCCESS) {
+ if (!create_metadata_array(*inner_value, &trailing_metadata)) {
+ zend_throw_exception(spl_ce_InvalidArgumentException,
+ "Bad trailing metadata value given",
+ 1 TSRMLS_CC);
+ goto cleanup;
+ }
+ ops[op_num].data.send_status_from_server.trailing_metadata =
+ trailing_metadata.metadata;
+ ops[op_num].data.send_status_from_server.trailing_metadata_count =
+ trailing_metadata.count;
+ }
+ if (zend_hash_find(status_hash, "code", sizeof("code"),
+ (void**)&inner_value) == SUCCESS) {
+ if (Z_TYPE_PP(inner_value) != IS_LONG) {
+ zend_throw_exception(spl_ce_InvalidArgumentException,
+ "Status code must be an integer",
+ 1 TSRMLS_CC);
+ goto cleanup;
+ }
+ ops[op_num].data.send_status_from_server.status =
+ Z_LVAL_PP(inner_value);
+ } else {
+ zend_throw_exception(spl_ce_InvalidArgumentException,
+ "Integer status code is required",
+ 1 TSRMLS_CC);
+ goto cleanup;
+ }
+ if (zend_hash_find(status_hash, "details", sizeof("details"),
+ (void**)&inner_value) == SUCCESS) {
+ if (Z_TYPE_PP(inner_value) != IS_STRING) {
+ zend_throw_exception(spl_ce_InvalidArgumentException,
+ "Status details must be a string",
+ 1 TSRMLS_CC);
+ goto cleanup;
+ }
+ ops[op_num].data.send_status_from_server.status_details =
+ Z_STRVAL_PP(inner_value);
+ } else {
+ zend_throw_exception(spl_ce_InvalidArgumentException,
+ "String status details is required",
+ 1 TSRMLS_CC);
+ goto cleanup;
+ }
+ break;
+ case GRPC_OP_RECV_INITIAL_METADATA:
+ ops[op_num].data.recv_initial_metadata = &recv_metadata;
+ break;
+ case GRPC_OP_RECV_MESSAGE:
+ ops[op_num].data.recv_message = &message;
+ break;
+ case GRPC_OP_RECV_STATUS_ON_CLIENT:
+ ops[op_num].data.recv_status_on_client.trailing_metadata =
+ &recv_trailing_metadata;
+ ops[op_num].data.recv_status_on_client.status = &status;
+ ops[op_num].data.recv_status_on_client.status_details =
+ &status_details;
+ ops[op_num].data.recv_status_on_client.status_details_capacity =
+ &status_details_capacity;
+ break;
+ case GRPC_OP_RECV_CLOSE_ON_SERVER:
+ ops[op_num].data.recv_close_on_server.cancelled = &cancelled;
+ break;
+ default:
zend_throw_exception(spl_ce_InvalidArgumentException,
- "metadata values must be arrays of strings",
- 1 TSRMLS_CC);
- return;
- }
- metadata.key = key;
- metadata.value = Z_STRVAL_P(*value);
- metadata.value_length = Z_STRLEN_P(*value);
- error_code = grpc_call_add_metadata_old(call->wrapped, &metadata, 0u);
- MAYBE_THROW_CALL_ERROR(add_metadata, error_code);
+ "Unrecognized key in batch", 1 TSRMLS_CC);
+ goto cleanup;
}
+ ops[op_num].op = (grpc_op_type)index;
+ op_num++;
}
-}
-
-/**
- * Invoke the RPC. Starts sending metadata and request headers over the wire
- * @param CompletionQueue $queue The completion queue to use with this call
- * @param long $metadata_tag The tag to associate with returned metadata
- * @param long $finished_tag The tag to associate with the finished event
- * @param long $flags A bitwise combination of the Grpc\WRITE_* constants
- * (optional)
- * @return Void
- */
-PHP_METHOD(Call, invoke) {
- grpc_call_error error_code;
- long tag1;
- long tag2;
- zval *queue_obj;
- long flags = 0;
- /* "Oll|l" == 1 Object, 3 mandatory longs, 1 optional long */
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Oll|l", &queue_obj,
- grpc_ce_completion_queue, &tag1, &tag2,
- &flags) == FAILURE) {
- zend_throw_exception(
- spl_ce_InvalidArgumentException,
- "invoke needs a CompletionQueue, 2 longs, and an optional long",
- 1 TSRMLS_CC);
- return;
- }
- add_property_zval(getThis(), "completion_queue", queue_obj);
- wrapped_grpc_call *call =
- (wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC);
- wrapped_grpc_completion_queue *queue =
- (wrapped_grpc_completion_queue *)zend_object_store_get_object(
- queue_obj TSRMLS_CC);
- error_code = grpc_call_invoke_old(call->wrapped, queue->wrapped, (void *)tag1,
- (void *)tag2, (gpr_uint32)flags);
- MAYBE_THROW_CALL_ERROR(invoke, error_code);
-}
-
-/**
- * Accept an incoming RPC, binding a completion queue to it. To be called after
- * adding metadata to the call, but before sending messages. Can only be called
- * on the server
- * @param CompletionQueue $queue The completion queue to use with this call
- * @param long $finished_tag The tag to associate with the finished event
- * @param long $flags A bitwise combination of the Grpc\WRITE_* constants
- * (optional)
- * @return Void
- */
-PHP_METHOD(Call, server_accept) {
- long tag;
- zval *queue_obj;
- grpc_call_error error_code;
- /* "Ol|l" == 1 Object, 1 long */
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Ol", &queue_obj,
- grpc_ce_completion_queue, &tag) == FAILURE) {
- zend_throw_exception(
- spl_ce_InvalidArgumentException,
- "server_accept expects a CompletionQueue, a long, and an optional long",
- 1 TSRMLS_CC);
- return;
+ error = grpc_call_start_batch(call->wrapped, ops, op_num, call->wrapped);
+ if (error != GRPC_CALL_OK) {
+ zend_throw_exception(spl_ce_LogicException,
+ "start_batch was called incorrectly",
+ (long)error TSRMLS_CC);
+ goto cleanup;
}
- add_property_zval(getThis(), "completion_queue", queue_obj);
- wrapped_grpc_call *call =
- (wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC);
- wrapped_grpc_completion_queue *queue =
- (wrapped_grpc_completion_queue *)zend_object_store_get_object(
- queue_obj TSRMLS_CC);
- error_code =
- grpc_call_server_accept_old(call->wrapped, queue->wrapped, (void *)tag);
- MAYBE_THROW_CALL_ERROR(server_accept, error_code);
-}
-
-PHP_METHOD(Call, server_end_initial_metadata) {
- grpc_call_error error_code;
- long flags = 0;
- /* "|l" == 1 optional long */
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &flags) ==
- FAILURE) {
- zend_throw_exception(spl_ce_InvalidArgumentException,
- "server_end_initial_metadata expects an optional long",
+ event = grpc_completion_queue_pluck(call->queue, call->wrapped,
+ gpr_inf_future);
+ if (event->data.op_complete != GRPC_OP_OK) {
+ zend_throw_exception(spl_ce_LogicException,
+ "The batch failed for some reason",
1 TSRMLS_CC);
+ goto cleanup;
}
- wrapped_grpc_call *call =
- (wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC);
- error_code = grpc_call_server_end_initial_metadata_old(call->wrapped, flags);
- MAYBE_THROW_CALL_ERROR(server_end_initial_metadata, error_code);
-}
-
-/**
- * Called by clients to cancel an RPC on the server.
- * @return Void
- */
-PHP_METHOD(Call, cancel) {
- wrapped_grpc_call *call =
- (wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC);
- grpc_call_error error_code = grpc_call_cancel(call->wrapped);
- MAYBE_THROW_CALL_ERROR(cancel, error_code);
-}
-
-/**
- * Queue a byte buffer for writing
- * @param string $buffer The buffer to queue for writing
- * @param long $tag The tag to associate with this write
- * @param long $flags A bitwise combination of the Grpc\WRITE_* constants
- * (optional)
- * @return Void
- */
-PHP_METHOD(Call, start_write) {
- grpc_call_error error_code;
- wrapped_grpc_call *call =
- (wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC);
- char *buffer;
- int buffer_len;
- long tag;
- long flags = 0;
- /* "Ol|l" == 1 Object, 1 mandatory long, 1 optional long */
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl|l", &buffer,
- &buffer_len, &tag, &flags) == FAILURE) {
- zend_throw_exception(spl_ce_InvalidArgumentException,
- "start_write expects a string and an optional long",
- 1 TSRMLS_CC);
- return;
- }
- error_code = grpc_call_start_write_old(
- call->wrapped, string_to_byte_buffer(buffer, buffer_len), (void *)tag,
- (gpr_uint32)flags);
- MAYBE_THROW_CALL_ERROR(start_write, error_code);
-}
-
-/**
- * Queue a status for writing
- * @param long $status_code The status code to send
- * @param string $status_details The status details to send
- * @param long $tag The tag to associate with this status
- * @return Void
- */
-PHP_METHOD(Call, start_write_status) {
- grpc_call_error error_code;
- wrapped_grpc_call *call =
- (wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC);
- long status_code;
- int status_details_length;
- long tag;
- char *status_details;
- /* "lsl" == 1 long, 1 string, 1 long */
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lsl", &status_code,
- &status_details, &status_details_length,
- &tag) == FAILURE) {
- zend_throw_exception(
- spl_ce_InvalidArgumentException,
- "start_write_status expects a long, a string, and a long", 1 TSRMLS_CC);
- return;
+ for (int i = 0; i < op_num; i++) {
+ switch(ops[i].op) {
+ case GRPC_OP_SEND_INITIAL_METADATA:
+ add_property_bool(result, "send_metadata", true);
+ break;
+ case GRPC_OP_SEND_MESSAGE:
+ add_property_bool(result, "send_message", true);
+ break;
+ case GRPC_OP_SEND_CLOSE_FROM_CLIENT:
+ add_property_bool(result, "send_close", true);
+ break;
+ case GRPC_OP_SEND_STATUS_FROM_SERVER:
+ add_property_bool(result, "send_status", true);
+ break;
+ case GRPC_OP_RECV_INITIAL_METADATA:
+ add_property_zval(result, "metadata",
+ grpc_parse_metadata_array(&recv_metadata));
+ break;
+ case GRPC_OP_RECV_MESSAGE:
+ byte_buffer_to_string(message, &message_str, &message_len);
+ if (message_str == NULL) {
+ add_property_null(result, "message");
+ } else {
+ add_property_stringl(result, "message", message_str, message_len,
+ false);
+ }
+ break;
+ case GRPC_OP_RECV_STATUS_ON_CLIENT:
+ MAKE_STD_ZVAL(recv_status);
+ object_init(recv_status);
+ add_property_zval(recv_status, "metadata",
+ grpc_parse_metadata_array(&recv_trailing_metadata));
+ add_property_long(recv_status, "code", status);
+ add_property_string(recv_status, "details", status_details, true);
+ add_property_zval(result, "status", recv_status);
+ break;
+ case GRPC_OP_RECV_CLOSE_ON_SERVER:
+ add_property_bool(result, "cancelled", cancelled);
+ break;
+ default:
+ break;
+ }
}
- error_code = grpc_call_start_write_status_old(call->wrapped,
- (grpc_status_code)status_code,
- status_details, (void *)tag);
- MAYBE_THROW_CALL_ERROR(start_write_status, error_code);
-}
-
-/**
- * Indicate that there are no more messages to send
- * @return Void
- */
-PHP_METHOD(Call, writes_done) {
- grpc_call_error error_code;
- wrapped_grpc_call *call =
- (wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC);
- long tag;
- /* "l" == 1 long */
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &tag) == FAILURE) {
- zend_throw_exception(spl_ce_InvalidArgumentException,
- "writes_done expects a long", 1 TSRMLS_CC);
- return;
+cleanup:
+ grpc_metadata_array_destroy(&metadata);
+ grpc_metadata_array_destroy(&trailing_metadata);
+ grpc_metadata_array_destroy(&recv_metadata);
+ grpc_metadata_array_destroy(&recv_trailing_metadata);
+ if (status_details != NULL) {
+ gpr_free(status_details);
}
- error_code = grpc_call_writes_done_old(call->wrapped, (void *)tag);
- MAYBE_THROW_CALL_ERROR(writes_done, error_code);
+ RETURN_DESTROY_ZVAL(result);
}
/**
- * Initiate a read on a call. Output event contains a byte buffer with the
- * result of the read
- * @param long $tag The tag to associate with this read
- * @return Void
+ * Cancel the call. This will cause the call to end with STATUS_CANCELLED if it
+ * has not already ended with another status.
*/
-PHP_METHOD(Call, start_read) {
- grpc_call_error error_code;
+PHP_METHOD(Call, cancel) {
wrapped_grpc_call *call =
(wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC);
- long tag;
- /* "l" == 1 long */
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &tag) == FAILURE) {
- zend_throw_exception(spl_ce_InvalidArgumentException,
- "start_read expects a long", 1 TSRMLS_CC);
- return;
- }
- error_code = grpc_call_start_read_old(call->wrapped, (void *)tag);
- MAYBE_THROW_CALL_ERROR(start_read, error_code);
+ grpc_call_cancel(call->wrapped);
}
static zend_function_entry call_methods[] = {
PHP_ME(Call, __construct, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
- PHP_ME(Call, server_accept, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(Call, server_end_initial_metadata, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(Call, add_metadata, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(Call, cancel, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(Call, invoke, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(Call, start_read, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(Call, start_write, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(Call, start_write_status, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(Call, writes_done, NULL, ZEND_ACC_PUBLIC) PHP_FE_END};
+ PHP_ME(Call, start_batch, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(Call, cancel, NULL, ZEND_ACC_PUBLIC) PHP_FE_END};
void grpc_init_call(TSRMLS_D) {
zend_class_entry ce;
diff --git a/src/php/ext/grpc/call.h b/src/php/ext/grpc/call.h
index 827e9a27a8..743effe5a1 100644
--- a/src/php/ext/grpc/call.h
+++ b/src/php/ext/grpc/call.h
@@ -45,19 +45,8 @@
#include "grpc/grpc.h"
-// Throw an exception if error_code is not OK
-#define MAYBE_THROW_CALL_ERROR(func_name, error_code) \
- do { \
- if (error_code != GRPC_CALL_OK) { \
- zend_throw_exception(spl_ce_LogicException, \
- #func_name " was called incorrectly", \
- (long)error_code TSRMLS_CC); \
- return; \
- } \
- } while (0)
-
/* Class entry for the Call PHP class */
-zend_class_entry *grpc_ce_call;
+extern zend_class_entry *grpc_ce_call;
/* Wrapper struct for grpc_call that can be associated with a PHP object */
typedef struct wrapped_grpc_call {
@@ -65,16 +54,18 @@ typedef struct wrapped_grpc_call {
bool owned;
grpc_call *wrapped;
+ grpc_completion_queue *queue;
} wrapped_grpc_call;
/* Initializes the Call PHP class */
void grpc_init_call(TSRMLS_D);
/* Creates a Call object that wraps the given grpc_call struct */
-zval *grpc_php_wrap_call(grpc_call *wrapped, bool owned);
+zval *grpc_php_wrap_call(grpc_call *wrapped, grpc_completion_queue *queue,
+ bool owned);
/* Creates and returns a PHP associative array of metadata from a C array of
* call metadata */
-zval *grpc_call_create_metadata_array(int count, grpc_metadata *elements);
+zval *grpc_parse_metadata_array(grpc_metadata_array *metadata_array);
#endif /* NET_GRPC_PHP_GRPC_CHANNEL_H_ */
diff --git a/src/php/ext/grpc/channel.c b/src/php/ext/grpc/channel.c
index d6296f9413..c96fb128a6 100644
--- a/src/php/ext/grpc/channel.c
+++ b/src/php/ext/grpc/channel.c
@@ -51,10 +51,11 @@
#include "grpc/support/log.h"
#include "grpc/grpc_security.h"
-#include "completion_queue.h"
#include "server.h"
#include "credentials.h"
+zend_class_entry *grpc_ce_channel;
+
/* Frees and destroys an instance of wrapped_grpc_channel */
void free_wrapped_grpc_channel(void *object TSRMLS_DC) {
wrapped_grpc_channel *channel = (wrapped_grpc_channel *)object;
@@ -137,6 +138,9 @@ PHP_METHOD(Channel, __construct) {
HashTable *array_hash;
zval **creds_obj = NULL;
wrapped_grpc_credentials *creds = NULL;
+ zval **override_obj;
+ char *override;
+ int override_len;
/* "s|a" == 1 string, 1 optional array */
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|a", &target,
&target_length, &args_array) == FAILURE) {
@@ -144,6 +148,8 @@ PHP_METHOD(Channel, __construct) {
"Channel expects a string and an array", 1 TSRMLS_CC);
return;
}
+ override = target;
+ override_len = target_length;
if (args_array == NULL) {
channel->wrapped = grpc_channel_create(target, NULL);
} else {
@@ -160,6 +166,19 @@ PHP_METHOD(Channel, __construct) {
*creds_obj TSRMLS_CC);
zend_hash_del(array_hash, "credentials", 12);
}
+ if (zend_hash_find(array_hash, GRPC_SSL_TARGET_NAME_OVERRIDE_ARG,
+ sizeof(GRPC_SSL_TARGET_NAME_OVERRIDE_ARG),
+ (void **)&override_obj) == SUCCESS) {
+ if (Z_TYPE_PP(override_obj) != IS_STRING) {
+ zend_throw_exception(spl_ce_InvalidArgumentException,
+ GRPC_SSL_TARGET_NAME_OVERRIDE_ARG
+ " must be a string",
+ 1 TSRMLS_CC);
+ return;
+ }
+ override = Z_STRVAL_PP(override_obj);
+ override_len = Z_STRLEN_PP(override_obj);
+ }
php_grpc_read_args_array(args_array, &args);
if (creds == NULL) {
channel->wrapped = grpc_channel_create(target, &args);
@@ -170,8 +189,8 @@ PHP_METHOD(Channel, __construct) {
}
efree(args.args);
}
- channel->target = ecalloc(target_length + 1, sizeof(char));
- memcpy(channel->target, target, target_length);
+ channel->target = ecalloc(override_len + 1, sizeof(char));
+ memcpy(channel->target, override, override_len);
}
/**
diff --git a/src/php/ext/grpc/channel.h b/src/php/ext/grpc/channel.h
index f426a25caf..2c79668a4d 100755
--- a/src/php/ext/grpc/channel.h
+++ b/src/php/ext/grpc/channel.h
@@ -46,7 +46,7 @@
#include "grpc/grpc.h"
/* Class entry for the PHP Channel class */
-zend_class_entry *grpc_ce_channel;
+extern zend_class_entry *grpc_ce_channel;
/* Wrapper struct for grpc_channel that can be associated with a PHP object */
typedef struct wrapped_grpc_channel {
diff --git a/src/php/ext/grpc/completion_queue.c b/src/php/ext/grpc/completion_queue.c
deleted file mode 100644
index 30c871b078..0000000000
--- a/src/php/ext/grpc/completion_queue.c
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- *
- * Copyright 2015, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "completion_queue.h"
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "php.h"
-#include "php_ini.h"
-#include "ext/standard/info.h"
-#include "ext/spl/spl_exceptions.h"
-#include "php_grpc.h"
-
-#include "zend_exceptions.h"
-
-#include <stdbool.h>
-
-#include "grpc/grpc.h"
-
-#include "event.h"
-#include "timeval.h"
-
-/* Frees and destroys a wrapped instance of grpc_completion_queue */
-void free_wrapped_grpc_completion_queue(void *object TSRMLS_DC) {
- wrapped_grpc_completion_queue *queue = NULL;
- grpc_event *event;
- queue = (wrapped_grpc_completion_queue *)object;
- if (queue->wrapped != NULL) {
- grpc_completion_queue_shutdown(queue->wrapped);
- event = grpc_completion_queue_next(queue->wrapped, gpr_inf_future);
- while (event != NULL) {
- if (event->type == GRPC_QUEUE_SHUTDOWN) {
- break;
- }
- event = grpc_completion_queue_next(queue->wrapped, gpr_inf_future);
- }
- grpc_completion_queue_destroy(queue->wrapped);
- }
- efree(queue);
-}
-
-/* Initializes an instance of wrapped_grpc_channel to be associated with an
- * object of a class specified by class_type */
-zend_object_value create_wrapped_grpc_completion_queue(
- zend_class_entry *class_type TSRMLS_DC) {
- zend_object_value retval;
- wrapped_grpc_completion_queue *intern;
-
- intern = (wrapped_grpc_completion_queue *)emalloc(
- sizeof(wrapped_grpc_completion_queue));
- memset(intern, 0, sizeof(wrapped_grpc_completion_queue));
-
- zend_object_std_init(&intern->std, class_type TSRMLS_CC);
- object_properties_init(&intern->std, class_type);
- retval.handle = zend_objects_store_put(
- intern, (zend_objects_store_dtor_t)zend_objects_destroy_object,
- free_wrapped_grpc_completion_queue, NULL TSRMLS_CC);
- retval.handlers = zend_get_std_object_handlers();
- return retval;
-}
-
-/**
- * Construct an instance of CompletionQueue
- */
-PHP_METHOD(CompletionQueue, __construct) {
- wrapped_grpc_completion_queue *queue =
- (wrapped_grpc_completion_queue *)zend_object_store_get_object(getThis()
- TSRMLS_CC);
- queue->wrapped = grpc_completion_queue_create();
-}
-
-/**
- * Blocks until an event is available, the completion queue is being shutdown,
- * or timeout is reached. Returns NULL on timeout, otherwise the event that
- * occurred. Callers should call event.finish once they have processed the
- * event.
- * @param Timeval $timeout The timeout for the event
- * @return Event The event that occurred
- */
-PHP_METHOD(CompletionQueue, next) {
- zval *timeout;
- /* "O" == 1 Object */
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &timeout,
- grpc_ce_timeval) == FAILURE) {
- zend_throw_exception(spl_ce_InvalidArgumentException,
- "next needs a Timeval", 1 TSRMLS_CC);
- return;
- }
- wrapped_grpc_completion_queue *completion_queue =
- (wrapped_grpc_completion_queue *)zend_object_store_get_object(getThis()
- TSRMLS_CC);
- wrapped_grpc_timeval *wrapped_timeout =
- (wrapped_grpc_timeval *)zend_object_store_get_object(timeout TSRMLS_CC);
- grpc_event *event = grpc_completion_queue_next(completion_queue->wrapped,
- wrapped_timeout->wrapped);
- if (event == NULL) {
- RETURN_NULL();
- }
- zval *wrapped_event = grpc_php_convert_event(event);
- RETURN_DESTROY_ZVAL(wrapped_event);
-}
-
-PHP_METHOD(CompletionQueue, pluck) {
- long tag;
- zval *timeout;
- /* "lO" == 1 long, 1 Object */
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lO", &tag, &timeout,
- grpc_ce_timeval) == FAILURE) {
- zend_throw_exception(spl_ce_InvalidArgumentException,
- "pluck needs a long and a Timeval", 1 TSRMLS_CC);
- }
- wrapped_grpc_completion_queue *completion_queue =
- (wrapped_grpc_completion_queue *)zend_object_store_get_object(getThis()
- TSRMLS_CC);
- wrapped_grpc_timeval *wrapped_timeout =
- (wrapped_grpc_timeval *)zend_object_store_get_object(timeout TSRMLS_CC);
- grpc_event *event = grpc_completion_queue_pluck(
- completion_queue->wrapped, (void *)tag, wrapped_timeout->wrapped);
- if (event == NULL) {
- RETURN_NULL();
- }
- zval *wrapped_event = grpc_php_convert_event(event);
- RETURN_DESTROY_ZVAL(wrapped_event);
-}
-
-static zend_function_entry completion_queue_methods[] = {
- PHP_ME(CompletionQueue, __construct, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
- PHP_ME(CompletionQueue, next, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(CompletionQueue, pluck, NULL, ZEND_ACC_PUBLIC) PHP_FE_END};
-
-void grpc_init_completion_queue(TSRMLS_D) {
- zend_class_entry ce;
- INIT_CLASS_ENTRY(ce, "Grpc\\CompletionQueue", completion_queue_methods);
- ce.create_object = create_wrapped_grpc_completion_queue;
- grpc_ce_completion_queue = zend_register_internal_class(&ce TSRMLS_CC);
-}
diff --git a/src/php/ext/grpc/config.m4 b/src/php/ext/grpc/config.m4
index 27c67781e7..d1a8decb73 100755
--- a/src/php/ext/grpc/config.m4
+++ b/src/php/ext/grpc/config.m4
@@ -66,5 +66,5 @@ if test "$PHP_GRPC" != "no"; then
PHP_SUBST(GRPC_SHARED_LIBADD)
- PHP_NEW_EXTENSION(grpc, byte_buffer.c call.c channel.c completion_queue.c credentials.c event.c timeval.c server.c server_credentials.c php_grpc.c, $ext_shared, , -Wall -Werror -pedantic -std=c99)
+ PHP_NEW_EXTENSION(grpc, byte_buffer.c call.c channel.c credentials.c timeval.c server.c server_credentials.c php_grpc.c, $ext_shared, , -Wall -Werror -pedantic -std=c99)
fi
diff --git a/src/php/ext/grpc/credentials.c b/src/php/ext/grpc/credentials.c
index 6d8f59fa33..a94b0eac2d 100644
--- a/src/php/ext/grpc/credentials.c
+++ b/src/php/ext/grpc/credentials.c
@@ -49,6 +49,8 @@
#include "grpc/grpc.h"
#include "grpc/grpc_security.h"
+zend_class_entry *grpc_ce_credentials;
+
/* Frees and destroys an instance of wrapped_grpc_credentials */
void free_wrapped_grpc_credentials(void *object TSRMLS_DC) {
wrapped_grpc_credentials *creds = (wrapped_grpc_credentials *)object;
diff --git a/src/php/ext/grpc/credentials.h b/src/php/ext/grpc/credentials.h
index 3ff75af9db..86d7ae5b14 100755
--- a/src/php/ext/grpc/credentials.h
+++ b/src/php/ext/grpc/credentials.h
@@ -47,7 +47,7 @@
#include "grpc/grpc_security.h"
/* Class entry for the Credentials PHP class */
-zend_class_entry *grpc_ce_credentials;
+extern zend_class_entry *grpc_ce_credentials;
/* Wrapper struct for grpc_credentials that can be associated with a PHP
* object */
diff --git a/src/php/ext/grpc/event.c b/src/php/ext/grpc/event.c
deleted file mode 100644
index 452c4b8bcb..0000000000
--- a/src/php/ext/grpc/event.c
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- *
- * Copyright 2015, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "event.h"
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "php.h"
-#include "php_ini.h"
-#include "ext/standard/info.h"
-#include "php_grpc.h"
-
-#include <stdbool.h>
-
-#include "grpc/grpc.h"
-
-#include "byte_buffer.h"
-#include "call.h"
-#include "timeval.h"
-
-/* Create a new PHP object containing the event data in the event struct.
- event must not be used after this function is called */
-zval *grpc_php_convert_event(grpc_event *event) {
- zval *data_object;
- char *detail_string;
- size_t detail_len;
- char *method_string;
- size_t method_len;
- char *host_string;
- size_t host_len;
- char *read_string;
- size_t read_len;
-
- zval *event_object;
-
- if (event == NULL) {
- return NULL;
- }
-
- MAKE_STD_ZVAL(event_object);
- object_init(event_object);
-
- add_property_zval(
- event_object, "call",
- grpc_php_wrap_call(event->call, event->type == GRPC_SERVER_RPC_NEW));
- add_property_long(event_object, "type", event->type);
- add_property_long(event_object, "tag", (long)event->tag);
-
- switch (event->type) {
- case GRPC_QUEUE_SHUTDOWN:
- add_property_null(event_object, "data");
- break;
- case GRPC_READ:
- if (event->data.read == NULL) {
- add_property_null(event_object, "data");
- } else {
- byte_buffer_to_string(event->data.read, &read_string, &read_len);
- add_property_stringl(event_object, "data", read_string, read_len, true);
- }
- break;
- case GRPC_WRITE_ACCEPTED:
- add_property_long(event_object, "data", (long)event->data.write_accepted);
- break;
- case GRPC_FINISH_ACCEPTED:
- add_property_long(event_object, "data",
- (long)event->data.finish_accepted);
- break;
- case GRPC_CLIENT_METADATA_READ:
- data_object = grpc_call_create_metadata_array(
- event->data.client_metadata_read.count,
- event->data.client_metadata_read.elements);
- add_property_zval(event_object, "data", data_object);
- break;
- case GRPC_FINISHED:
- MAKE_STD_ZVAL(data_object);
- object_init(data_object);
- add_property_long(data_object, "code", event->data.finished.status);
- if (event->data.finished.details == NULL) {
- add_property_null(data_object, "details");
- } else {
- detail_len = strlen(event->data.finished.details);
- detail_string = ecalloc(detail_len + 1, sizeof(char));
- memcpy(detail_string, event->data.finished.details, detail_len);
- add_property_string(data_object, "details", detail_string, true);
- }
- add_property_zval(data_object, "metadata",
- grpc_call_create_metadata_array(
- event->data.finished.metadata_count,
- event->data.finished.metadata_elements));
- add_property_zval(event_object, "data", data_object);
- break;
- case GRPC_SERVER_RPC_NEW:
- MAKE_STD_ZVAL(data_object);
- object_init(data_object);
- method_len = strlen(event->data.server_rpc_new.method);
- method_string = ecalloc(method_len + 1, sizeof(char));
- memcpy(method_string, event->data.server_rpc_new.method, method_len);
- add_property_string(data_object, "method", method_string, false);
- host_len = strlen(event->data.server_rpc_new.host);
- host_string = ecalloc(host_len + 1, sizeof(char));
- memcpy(host_string, event->data.server_rpc_new.host, host_len);
- add_property_string(data_object, "host", host_string, false);
- add_property_zval(
- data_object, "absolute_timeout",
- grpc_php_wrap_timeval(event->data.server_rpc_new.deadline));
- add_property_zval(data_object, "metadata",
- grpc_call_create_metadata_array(
- event->data.server_rpc_new.metadata_count,
- event->data.server_rpc_new.metadata_elements));
- add_property_zval(event_object, "data", data_object);
- break;
- default:
- add_property_null(event_object, "data");
- break;
- }
- grpc_event_finish(event);
- return event_object;
-}
diff --git a/src/php/ext/grpc/php_grpc.c b/src/php/ext/grpc/php_grpc.c
index 67e366c385..1f9edfe881 100644
--- a/src/php/ext/grpc/php_grpc.c
+++ b/src/php/ext/grpc/php_grpc.c
@@ -34,8 +34,6 @@
#include "call.h"
#include "channel.h"
#include "server.h"
-#include "completion_queue.h"
-#include "event.h"
#include "timeval.h"
#include "credentials.h"
#include "server_credentials.h"
@@ -127,27 +125,12 @@ PHP_MINIT_FUNCTION(grpc) {
REGISTER_LONG_CONSTANT("Grpc\\CALL_ERROR_INVALID_FLAGS",
GRPC_CALL_ERROR_INVALID_FLAGS, CONST_CS);
- /* Register op error constants */
- REGISTER_LONG_CONSTANT("Grpc\\OP_OK", GRPC_OP_OK, CONST_CS);
- REGISTER_LONG_CONSTANT("Grpc\\OP_ERROR", GRPC_OP_ERROR, CONST_CS);
-
/* Register flag constants */
REGISTER_LONG_CONSTANT("Grpc\\WRITE_BUFFER_HINT", GRPC_WRITE_BUFFER_HINT,
CONST_CS);
REGISTER_LONG_CONSTANT("Grpc\\WRITE_NO_COMPRESS", GRPC_WRITE_NO_COMPRESS,
CONST_CS);
- /* Register completion type constants */
- REGISTER_LONG_CONSTANT("Grpc\\QUEUE_SHUTDOWN", GRPC_QUEUE_SHUTDOWN, CONST_CS);
- REGISTER_LONG_CONSTANT("Grpc\\READ", GRPC_READ, CONST_CS);
- REGISTER_LONG_CONSTANT("Grpc\\FINISH_ACCEPTED", GRPC_FINISH_ACCEPTED,
- CONST_CS);
- REGISTER_LONG_CONSTANT("Grpc\\WRITE_ACCEPTED", GRPC_WRITE_ACCEPTED, CONST_CS);
- REGISTER_LONG_CONSTANT("Grpc\\CLIENT_METADATA_READ",
- GRPC_CLIENT_METADATA_READ, CONST_CS);
- REGISTER_LONG_CONSTANT("Grpc\\FINISHED", GRPC_FINISHED, CONST_CS);
- REGISTER_LONG_CONSTANT("Grpc\\SERVER_RPC_NEW", GRPC_SERVER_RPC_NEW, CONST_CS);
-
/* Register status constants */
REGISTER_LONG_CONSTANT("Grpc\\STATUS_OK", GRPC_STATUS_OK, CONST_CS);
REGISTER_LONG_CONSTANT("Grpc\\STATUS_CANCELLED", GRPC_STATUS_CANCELLED,
@@ -181,10 +164,27 @@ PHP_MINIT_FUNCTION(grpc) {
REGISTER_LONG_CONSTANT("Grpc\\STATUS_DATA_LOSS", GRPC_STATUS_DATA_LOSS,
CONST_CS);
+ /* Register op type constants */
+ REGISTER_LONG_CONSTANT("Grpc\\OP_SEND_INITIAL_METADATA",
+ GRPC_OP_SEND_INITIAL_METADATA, CONST_CS);
+ REGISTER_LONG_CONSTANT("Grpc\\OP_SEND_MESSAGE",
+ GRPC_OP_SEND_MESSAGE, CONST_CS);
+ REGISTER_LONG_CONSTANT("Grpc\\OP_SEND_CLOSE_FROM_CLIENT",
+ GRPC_OP_SEND_CLOSE_FROM_CLIENT, CONST_CS);
+ REGISTER_LONG_CONSTANT("Grpc\\OP_SEND_STATUS_FROM_SERVER",
+ GRPC_OP_SEND_STATUS_FROM_SERVER, CONST_CS);
+ REGISTER_LONG_CONSTANT("Grpc\\OP_RECV_INITIAL_METADATA",
+ GRPC_OP_RECV_INITIAL_METADATA, CONST_CS);
+ REGISTER_LONG_CONSTANT("Grpc\\OP_RECV_MESSAGE",
+ GRPC_OP_RECV_MESSAGE, CONST_CS);
+ REGISTER_LONG_CONSTANT("Grpc\\OP_RECV_STATUS_ON_CLIENT",
+ GRPC_OP_RECV_STATUS_ON_CLIENT, CONST_CS);
+ REGISTER_LONG_CONSTANT("Grpc\\OP_RECV_CLOSE_ON_SERVER",
+ GRPC_OP_RECV_CLOSE_ON_SERVER, CONST_CS);
+
grpc_init_call(TSRMLS_C);
grpc_init_channel(TSRMLS_C);
grpc_init_server(TSRMLS_C);
- grpc_init_completion_queue(TSRMLS_C);
grpc_init_timeval(TSRMLS_C);
grpc_init_credentials(TSRMLS_C);
grpc_init_server_credentials(TSRMLS_C);
diff --git a/src/php/ext/grpc/server.c b/src/php/ext/grpc/server.c
index 00d08c6ecf..86b29958fb 100644
--- a/src/php/ext/grpc/server.c
+++ b/src/php/ext/grpc/server.c
@@ -52,13 +52,27 @@
#include "grpc/grpc_security.h"
#include "server.h"
-#include "completion_queue.h"
#include "channel.h"
#include "server_credentials.h"
+#include "timeval.h"
+
+zend_class_entry *grpc_ce_server;
/* Frees and destroys an instance of wrapped_grpc_server */
void free_wrapped_grpc_server(void *object TSRMLS_DC) {
wrapped_grpc_server *server = (wrapped_grpc_server *)object;
+ grpc_event *event;
+ if (server->queue != NULL) {
+ grpc_completion_queue_shutdown(server->queue);
+ event = grpc_completion_queue_next(server->queue, gpr_inf_future);
+ while (event != NULL) {
+ if (event->type == GRPC_QUEUE_SHUTDOWN) {
+ break;
+ }
+ event = grpc_completion_queue_next(server->queue, gpr_inf_future);
+ }
+ grpc_completion_queue_destroy(server->queue);
+ }
if (server->wrapped != NULL) {
grpc_server_shutdown(server->wrapped);
grpc_server_destroy(server->wrapped);
@@ -93,26 +107,22 @@ zend_object_value create_wrapped_grpc_server(zend_class_entry *class_type
PHP_METHOD(Server, __construct) {
wrapped_grpc_server *server =
(wrapped_grpc_server *)zend_object_store_get_object(getThis() TSRMLS_CC);
- zval *queue_obj;
zval *args_array = NULL;
grpc_channel_args args;
- /* "O|a" == 1 Object, 1 optional array */
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|a", &queue_obj,
- grpc_ce_completion_queue, &args_array) == FAILURE) {
+ /* "|a" == 1 optional array */
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a", &args_array) ==
+ FAILURE) {
zend_throw_exception(spl_ce_InvalidArgumentException,
- "Server expects a CompletionQueue and an array",
+ "Server expects an array",
1 TSRMLS_CC);
return;
}
- add_property_zval(getThis(), "completion_queue", queue_obj);
- wrapped_grpc_completion_queue *queue =
- (wrapped_grpc_completion_queue *)zend_object_store_get_object(
- queue_obj TSRMLS_CC);
+ server->queue = grpc_completion_queue_create();
if (args_array == NULL) {
- server->wrapped = grpc_server_create(queue->wrapped, NULL);
+ server->wrapped = grpc_server_create(server->queue, NULL);
} else {
php_grpc_read_args_array(args_array, &args);
- server->wrapped = grpc_server_create(queue->wrapped, &args);
+ server->wrapped = grpc_server_create(server->queue, &args);
efree(args.args);
}
}
@@ -127,16 +137,40 @@ PHP_METHOD(Server, request_call) {
grpc_call_error error_code;
wrapped_grpc_server *server =
(wrapped_grpc_server *)zend_object_store_get_object(getThis() TSRMLS_CC);
- long tag_new;
- /* "l" == 1 long */
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &tag_new) ==
- FAILURE) {
- zend_throw_exception(spl_ce_InvalidArgumentException,
- "request_call expects a long", 1 TSRMLS_CC);
- return;
+ grpc_call *call;
+ grpc_call_details details;
+ grpc_metadata_array metadata;
+ zval *result;
+ grpc_event *event;
+ MAKE_STD_ZVAL(result);
+ object_init(result);
+ grpc_call_details_init(&details);
+ grpc_metadata_array_init(&metadata);
+ error_code = grpc_server_request_call(server->wrapped, &call, &details,
+ &metadata, server->queue, NULL);
+ if (error_code != GRPC_CALL_OK) {
+ zend_throw_exception(spl_ce_LogicException, "request_call failed",
+ (long)error_code TSRMLS_CC);
+ goto cleanup;
+ }
+ event = grpc_completion_queue_pluck(server->queue, NULL, gpr_inf_future);
+ if (event->data.op_complete != GRPC_OP_OK) {
+ zend_throw_exception(spl_ce_LogicException,
+ "Failed to request a call for some reason",
+ 1 TSRMLS_CC);
+ goto cleanup;
}
- error_code = grpc_server_request_call_old(server->wrapped, (void *)tag_new);
- MAYBE_THROW_CALL_ERROR(request_call, error_code);
+ add_property_zval(result, "call", grpc_php_wrap_call(call, server->queue,
+ true));
+ add_property_string(result, "method", details.method, true);
+ add_property_string(result, "host", details.host, true);
+ add_property_zval(result, "absolute_deadline",
+ grpc_php_wrap_timeval(details.deadline));
+ add_property_zval(result, "metadata", grpc_parse_metadata_array(&metadata));
+cleanup:
+ grpc_call_details_destroy(&details);
+ grpc_metadata_array_destroy(&metadata);
+ RETURN_DESTROY_ZVAL(result);
}
/**
@@ -166,7 +200,7 @@ PHP_METHOD(Server, add_secure_http2_port) {
int addr_len;
zval *creds_obj;
/* "sO" == 1 string, 1 object */
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &addr, &addr_len,
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sO", &addr, &addr_len,
&creds_obj, grpc_ce_server_credentials) ==
FAILURE) {
zend_throw_exception(
diff --git a/src/php/ext/grpc/server.h b/src/php/ext/grpc/server.h
index ecef4c6429..ebb8d25ae1 100755
--- a/src/php/ext/grpc/server.h
+++ b/src/php/ext/grpc/server.h
@@ -46,13 +46,14 @@
#include "grpc/grpc.h"
/* Class entry for the Server PHP class */
-zend_class_entry *grpc_ce_server;
+extern zend_class_entry *grpc_ce_server;
/* Wrapper struct for grpc_server that can be associated with a PHP object */
typedef struct wrapped_grpc_server {
zend_object std;
grpc_server *wrapped;
+ grpc_completion_queue *queue;
} wrapped_grpc_server;
/* Initializes the Server class */
diff --git a/src/php/ext/grpc/server_credentials.c b/src/php/ext/grpc/server_credentials.c
index 8aaa86ce94..df64e65986 100644
--- a/src/php/ext/grpc/server_credentials.c
+++ b/src/php/ext/grpc/server_credentials.c
@@ -49,6 +49,8 @@
#include "grpc/grpc.h"
#include "grpc/grpc_security.h"
+zend_class_entry *grpc_ce_server_credentials;
+
/* Frees and destroys an instace of wrapped_grpc_server_credentials */
void free_wrapped_grpc_server_credentials(void *object TSRMLS_DC) {
wrapped_grpc_server_credentials *creds =
diff --git a/src/php/ext/grpc/server_credentials.h b/src/php/ext/grpc/server_credentials.h
index ce2a4da138..8ed3697150 100755
--- a/src/php/ext/grpc/server_credentials.h
+++ b/src/php/ext/grpc/server_credentials.h
@@ -47,7 +47,7 @@
#include "grpc/grpc_security.h"
/* Class entry for the Server_Credentials PHP class */
-zend_class_entry *grpc_ce_server_credentials;
+extern zend_class_entry *grpc_ce_server_credentials;
/* Wrapper struct for grpc_server_credentials that can be associated with a PHP
* object */
diff --git a/src/php/ext/grpc/timeval.c b/src/php/ext/grpc/timeval.c
index 5b0142cbe4..f90f0062ba 100644
--- a/src/php/ext/grpc/timeval.c
+++ b/src/php/ext/grpc/timeval.c
@@ -50,6 +50,8 @@
#include "grpc/grpc.h"
#include "grpc/support/time.h"
+zend_class_entry *grpc_ce_timeval;
+
/* Frees and destroys an instance of wrapped_grpc_call */
void free_wrapped_grpc_timeval(void *object TSRMLS_DC) { efree(object); }
diff --git a/src/php/ext/grpc/timeval.h b/src/php/ext/grpc/timeval.h
index 0e215fc884..e3183f691d 100755
--- a/src/php/ext/grpc/timeval.h
+++ b/src/php/ext/grpc/timeval.h
@@ -47,7 +47,7 @@
#include "grpc/support/time.h"
/* Class entry for the Timeval PHP Class */
-zend_class_entry *grpc_ce_timeval;
+extern zend_class_entry *grpc_ce_timeval;
/* Wrapper struct for timeval that can be associated with a PHP object */
typedef struct wrapped_grpc_timeval {
diff --git a/src/php/lib/Grpc/ActiveCall.php b/src/php/lib/Grpc/ActiveCall.php
index f0d0d55582..9e048ae03b 100755
--- a/src/php/lib/Grpc/ActiveCall.php
+++ b/src/php/lib/Grpc/ActiveCall.php
@@ -38,9 +38,7 @@ require_once realpath(dirname(__FILE__) . '/../autoload.php');
* Represents an active call that allows sending and recieving binary data
*/
class ActiveCall {
- private $completion_queue;
private $call;
- private $flags;
private $metadata;
/**
@@ -48,24 +46,15 @@ class ActiveCall {
* @param Channel $channel The channel to communicate on
* @param string $method The method to call on the remote server
* @param array $metadata Metadata to send with the call, if applicable
- * @param long $flags Write flags to use with this call
*/
public function __construct(Channel $channel,
$method,
- $metadata = array(),
- $flags = 0) {
- $this->completion_queue = new CompletionQueue();
+ $metadata = array()) {
$this->call = new Call($channel, $method, Timeval::inf_future());
- $this->call->add_metadata($metadata, 0);
- $this->flags = $flags;
- // Invoke the call.
- $this->call->invoke($this->completion_queue,
- CLIENT_METADATA_READ,
- FINISHED, 0);
- $metadata_event = $this->completion_queue->pluck(CLIENT_METADATA_READ,
- Timeval::inf_future());
- $this->metadata = $metadata_event->data;
+ $event = $this->call->start_batch([OP_SEND_INITIAL_METADATA => $metadata]);
+
+ $this->metadata = $event->metadata;
}
/**
@@ -87,9 +76,8 @@ class ActiveCall {
* @return The next message from the server, or null if there is none.
*/
public function read() {
- $this->call->start_read(READ);
- $read_event = $this->completion_queue->pluck(READ, Timeval::inf_future());
- return $read_event->data;
+ $read_event = $this->call->start_batch([OP_RECV_MESSAGE => true]);
+ return $read_event->message;
}
/**
@@ -98,16 +86,14 @@ class ActiveCall {
* @param ByteBuffer $data The data to write
*/
public function write($data) {
- $this->call->start_write($data, WRITE_ACCEPTED, $this->flags);
- $this->completion_queue->pluck(WRITE_ACCEPTED, Timeval::inf_future());
+ $this->call->start_batch([OP_SEND_MESSAGE => $data]);
}
/**
* Indicate that no more writes will be sent.
*/
public function writesDone() {
- $this->call->writes_done(FINISH_ACCEPTED);
- $this->completion_queue->pluck(FINISH_ACCEPTED, Timeval::inf_future());
+ $this->call->start_batch([OP_SEND_CLOSE_FROM_CLIENT => true]);
}
/**
@@ -116,8 +102,9 @@ class ActiveCall {
* and array $metadata members
*/
public function getStatus() {
- $status_event = $this->completion_queue->pluck(FINISHED,
- Timeval::inf_future());
- return $status_event->data;
+ $status_event = $this->call->start_batch([
+ OP_RECV_STATUS_ON_CLIENT => true
+ ]);
+ return $status_event->status;
}
}
diff --git a/src/php/tests/interop/interop_client.php b/src/php/tests/interop/interop_client.php
index 82ca438169..7ee089e241 100755
--- a/src/php/tests/interop/interop_client.php
+++ b/src/php/tests/interop/interop_client.php
@@ -132,8 +132,6 @@ function serverStreaming($stub) {
}
$call = $stub->StreamingOutputCall($request);
- hardAssert($call->getStatus()->code === Grpc\STATUS_OK,
- 'Call did not complete successfully');
$i = 0;
foreach($call->responses() as $value) {
hardAssert($i < 4, 'Too many responses');
@@ -142,7 +140,10 @@ function serverStreaming($stub) {
'Payload ' . $i . ' had the wrong type');
hardAssert(strlen($payload->getBody()) === $sizes[$i],
'Response ' . $i . ' had the wrong length');
+ $i += 1;
}
+ hardAssert($call->getStatus()->code === Grpc\STATUS_OK,
+ 'Call did not complete successfully');
}
/**
@@ -240,4 +241,6 @@ switch($args['test_case']) {
break;
case 'cancel_after_first_response':
cancelAfterFirstResponse($stub);
+ default:
+ exit(1);
}
diff --git a/src/php/tests/unit_tests/CallTest.php b/src/php/tests/unit_tests/CallTest.php
index 8bb0927f21..d361ce0030 100755
--- a/src/php/tests/unit_tests/CallTest.php
+++ b/src/php/tests/unit_tests/CallTest.php
@@ -36,65 +36,47 @@ class CallTest extends PHPUnit_Framework_TestCase{
static $port;
public static function setUpBeforeClass() {
- $cq = new Grpc\CompletionQueue();
- self::$server = new Grpc\Server($cq, []);
+ self::$server = new Grpc\Server([]);
self::$port = self::$server->add_http2_port('0.0.0.0:0');
}
public function setUp() {
- $this->cq = new Grpc\CompletionQueue();
$this->channel = new Grpc\Channel('localhost:' . self::$port, []);
$this->call = new Grpc\Call($this->channel,
'/foo',
Grpc\Timeval::inf_future());
}
- /**
- * @expectedException LogicException
- * @expectedExceptionCode Grpc\CALL_ERROR_INVALID_FLAGS
- * @expectedExceptionMessage invoke
- */
- public function testInvokeRejectsBadFlags() {
- $this->call->invoke($this->cq, 0, 0, 0xDEADBEEF);
- }
-
- /**
- * @expectedException LogicException
- * @expectedExceptionCode Grpc\CALL_ERROR_NOT_ON_CLIENT
- * @expectedExceptionMessage server_accept
- */
- public function testServerAcceptFailsCorrectly() {
- $this->call->server_accept($this->cq, 0);
- }
-
- /* These test methods with assertTrue(true) at the end just check that the
- method calls completed without errors. PHPUnit warns for tests with no
- asserts, and this avoids that warning without changing the meaning of the
- tests */
-
public function testAddEmptyMetadata() {
- $this->call->add_metadata([], 0);
- /* Dummy assert: Checks that the previous call completed without error */
- $this->assertTrue(true);
+ $batch = [
+ Grpc\OP_SEND_INITIAL_METADATA => []
+ ];
+ $result = $this->call->start_batch($batch);
+ $this->assertTrue($result->send_metadata);
}
public function testAddSingleMetadata() {
- $this->call->add_metadata(['key' => ['value']], 0);
- /* Dummy assert: Checks that the previous call completed without error */
- $this->assertTrue(true);
+ $batch = [
+ Grpc\OP_SEND_INITIAL_METADATA => ['key' => ['value']]
+ ];
+ $result = $this->call->start_batch($batch);
+ $this->assertTrue($result->send_metadata);
}
public function testAddMultiValueMetadata() {
- $this->call->add_metadata(['key' => ['value1', 'value2']], 0);
- /* Dummy assert: Checks that the previous call completed without error */
- $this->assertTrue(true);
+ $batch = [
+ Grpc\OP_SEND_INITIAL_METADATA => ['key' => ['value1', 'value2']]
+ ];
+ $result = $this->call->start_batch($batch);
+ $this->assertTrue($result->send_metadata);
}
public function testAddSingleAndMultiValueMetadata() {
- $this->call->add_metadata(
- ['key1' => ['value1'],
- 'key2' => ['value2', 'value3']], 0);
- /* Dummy assert: Checks that the previous call completed without error */
- $this->assertTrue(true);
+ $batch = [
+ Grpc\OP_SEND_INITIAL_METADATA => ['key1' => ['value1'],
+ 'key2' => ['value2', 'value3']]
+ ];
+ $result = $this->call->start_batch($batch);
+ $this->assertTrue($result->send_metadata);
}
}
diff --git a/src/php/tests/unit_tests/EndToEndTest.php b/src/php/tests/unit_tests/EndToEndTest.php
index 0cbc506c8e..3e165b7213 100755
--- a/src/php/tests/unit_tests/EndToEndTest.php
+++ b/src/php/tests/unit_tests/EndToEndTest.php
@@ -33,18 +33,15 @@
*/
class EndToEndTest extends PHPUnit_Framework_TestCase{
public function setUp() {
- $this->client_queue = new Grpc\CompletionQueue();
- $this->server_queue = new Grpc\CompletionQueue();
- $this->server = new Grpc\Server($this->server_queue, []);
+ $this->server = new Grpc\Server([]);
$port = $this->server->add_http2_port('0.0.0.0:0');
$this->channel = new Grpc\Channel('localhost:' . $port, []);
+ $this->server->start();
}
public function tearDown() {
unset($this->channel);
unset($this->server);
- unset($this->client_queue);
- unset($this->server_queue);
}
public function testSimpleRequestBody() {
@@ -53,55 +50,45 @@ class EndToEndTest extends PHPUnit_Framework_TestCase{
$call = new Grpc\Call($this->channel,
'dummy_method',
$deadline);
- $tag = 1;
- $call->invoke($this->client_queue, $tag, $tag);
- $server_tag = 2;
-
- $call->writes_done($tag);
- $event = $this->client_queue->next($deadline);
- $this->assertNotNull($event);
- $this->assertSame(Grpc\FINISH_ACCEPTED, $event->type);
- $this->assertSame(Grpc\OP_OK, $event->data);
-
- // check that a server rpc new was received
- $this->server->start();
- $this->server->request_call($server_tag);
- $event = $this->server_queue->next($deadline);
- $this->assertNotNull($event);
- $this->assertSame(Grpc\SERVER_RPC_NEW, $event->type);
- $server_call = $event->call;
- $this->assertNotNull($server_call);
- $server_call->server_accept($this->server_queue, $server_tag);
-
- $server_call->server_end_initial_metadata();
+ $event = $call->start_batch([
+ Grpc\OP_SEND_INITIAL_METADATA => [],
+ Grpc\OP_SEND_CLOSE_FROM_CLIENT => true
+ ]);
- // the server sends the status
- $server_call->start_write_status(Grpc\STATUS_OK, $status_text, $server_tag);
- $event = $this->server_queue->next($deadline);
- $this->assertNotNull($event);
- $this->assertSame(Grpc\FINISH_ACCEPTED, $event->type);
- $this->assertSame(Grpc\OP_OK, $event->data);
+ $this->assertTrue($event->send_metadata);
+ $this->assertTrue($event->send_close);
- // the client gets CLIENT_METADATA_READ
- $event = $this->client_queue->next($deadline);
- $this->assertNotNull($event);
- $this->assertSame(Grpc\CLIENT_METADATA_READ, $event->type);
+ $event = $this->server->request_call();
+ $this->assertSame('dummy_method', $event->method);
+ $this->assertSame([], $event->metadata);
+ $server_call = $event->call;
- // the client gets FINISHED
- $event = $this->client_queue->next($deadline);
- $this->assertNotNull($event);
- $this->assertSame(Grpc\FINISHED, $event->type);
- $status = $event->data;
+ $event = $server_call->start_batch([
+ Grpc\OP_SEND_INITIAL_METADATA => [],
+ Grpc\OP_SEND_STATUS_FROM_SERVER => [
+ 'metadata' => [],
+ 'code' => Grpc\STATUS_OK,
+ 'details' => $status_text
+ ],
+ Grpc\OP_RECV_CLOSE_ON_SERVER => true
+ ]);
+
+ $this->assertTrue($event->send_metadata);
+ $this->assertTrue($event->send_status);
+ $this->assertFalse($event->cancelled);
+
+ $event = $call->start_batch([
+ Grpc\OP_RECV_INITIAL_METADATA => true,
+ Grpc\OP_RECV_STATUS_ON_CLIENT => true
+ ]);
+
+ $this->assertSame([], $event->metadata);
+ $status = $event->status;
+ $this->assertSame([], $status->metadata);
$this->assertSame(Grpc\STATUS_OK, $status->code);
$this->assertSame($status_text, $status->details);
- // and the server gets FINISHED
- $event = $this->server_queue->next($deadline);
- $this->assertNotNull($event);
- $this->assertSame(Grpc\FINISHED, $event->type);
- $status = $event->data;
-
unset($call);
unset($server_call);
}
@@ -115,79 +102,52 @@ class EndToEndTest extends PHPUnit_Framework_TestCase{
$call = new Grpc\Call($this->channel,
'dummy_method',
$deadline);
- $tag = 1;
- $call->invoke($this->client_queue, $tag, $tag);
- $server_tag = 2;
+ $event = $call->start_batch([
+ Grpc\OP_SEND_INITIAL_METADATA => [],
+ Grpc\OP_SEND_CLOSE_FROM_CLIENT => true,
+ Grpc\OP_SEND_MESSAGE => $req_text
+ ]);
- // the client writes
- $call->start_write($req_text, $tag);
- $event = $this->client_queue->next($deadline);
- $this->assertNotNull($event);
- $this->assertSame(Grpc\WRITE_ACCEPTED, $event->type);
+ $this->assertTrue($event->send_metadata);
+ $this->assertTrue($event->send_close);
+ $this->assertTrue($event->send_message);
- // check that a server rpc new was received
- $this->server->start();
- $this->server->request_call($server_tag);
- $event = $this->server_queue->next($deadline);
- $this->assertNotNull($event);
- $this->assertSame(Grpc\SERVER_RPC_NEW, $event->type);
+ $event = $this->server->request_call();
+ $this->assertSame('dummy_method', $event->method);
$server_call = $event->call;
- $this->assertNotNull($server_call);
- $server_call->server_accept($this->server_queue, $server_tag);
-
- $server_call->server_end_initial_metadata();
-
- // start the server read
- $server_call->start_read($server_tag);
- $event = $this->server_queue->next($deadline);
- $this->assertNotNull($event);
- $this->assertSame(Grpc\READ, $event->type);
- $this->assertSame($req_text, $event->data);
-
- // the server replies
- $server_call->start_write($reply_text, $server_tag);
- $event = $this->server_queue->next($deadline);
- $this->assertNotNull($event);
- $this->assertSame(Grpc\WRITE_ACCEPTED, $event->type);
-
- // the client reads the metadata
- $event = $this->client_queue->next($deadline);
- $this->assertNotNull($event);
- $this->assertSame(Grpc\CLIENT_METADATA_READ, $event->type);
-
- // the client reads the reply
- $call->start_read($tag);
- $event = $this->client_queue->next($deadline);
- $this->assertNotNull($event);
- $this->assertSame(Grpc\READ, $event->type);
- $this->assertSame($reply_text, $event->data);
-
- // the client sends writes done
- $call->writes_done($tag);
- $event = $this->client_queue->next($deadline);
- $this->assertSame(Grpc\FINISH_ACCEPTED, $event->type);
- $this->assertSame(Grpc\OP_OK, $event->data);
-
- // the server sends the status
- $server_call->start_write_status(GRPC\STATUS_OK, $status_text, $server_tag);
- $event = $this->server_queue->next($deadline);
- $this->assertSame(Grpc\FINISH_ACCEPTED, $event->type);
- $this->assertSame(Grpc\OP_OK, $event->data);
-
- // the client gets FINISHED
- $event = $this->client_queue->next($deadline);
- $this->assertNotNull($event);
- $this->assertSame(Grpc\FINISHED, $event->type);
- $status = $event->data;
+
+ $event = $server_call->start_batch([
+ Grpc\OP_SEND_INITIAL_METADATA => [],
+ Grpc\OP_SEND_MESSAGE => $reply_text,
+ Grpc\OP_SEND_STATUS_FROM_SERVER => [
+ 'metadata' => [],
+ 'code' => Grpc\STATUS_OK,
+ 'details' => $status_text
+ ],
+ Grpc\OP_RECV_MESSAGE => true,
+ Grpc\OP_RECV_CLOSE_ON_SERVER => true,
+ ]);
+
+ $this->assertTrue($event->send_metadata);
+ $this->assertTrue($event->send_status);
+ $this->assertTrue($event->send_message);
+ $this->assertFalse($event->cancelled);
+ $this->assertSame($req_text, $event->message);
+
+ $event = $call->start_batch([
+ Grpc\OP_RECV_INITIAL_METADATA => true,
+ Grpc\OP_RECV_MESSAGE => true,
+ Grpc\OP_RECV_STATUS_ON_CLIENT => true,
+ ]);
+
+ $this->assertSame([], $event->metadata);
+ $this->assertSame($reply_text, $event->message);
+ $status = $event->status;
+ $this->assertSame([], $status->metadata);
$this->assertSame(Grpc\STATUS_OK, $status->code);
$this->assertSame($status_text, $status->details);
- // and the server gets FINISHED
- $event = $this->server_queue->next($deadline);
- $this->assertNotNull($event);
- $this->assertSame(Grpc\FINISHED, $event->type);
-
unset($call);
unset($server_call);
}
diff --git a/src/php/tests/unit_tests/SecureEndToEndTest.php b/src/php/tests/unit_tests/SecureEndToEndTest.php
index 896afeac49..2d62fe9d5e 100755
--- a/src/php/tests/unit_tests/SecureEndToEndTest.php
+++ b/src/php/tests/unit_tests/SecureEndToEndTest.php
@@ -33,17 +33,16 @@
*/
class SecureEndToEndTest extends PHPUnit_Framework_TestCase{
public function setUp() {
- $this->client_queue = new Grpc\CompletionQueue();
- $this->server_queue = new Grpc\CompletionQueue();
$credentials = Grpc\Credentials::createSsl(
file_get_contents(dirname(__FILE__) . '/../data/ca.pem'));
$server_credentials = Grpc\ServerCredentials::createSsl(
null,
file_get_contents(dirname(__FILE__) . '/../data/server1.key'),
file_get_contents(dirname(__FILE__) . '/../data/server1.pem'));
- $this->server = new Grpc\Server($this->server_queue);
+ $this->server = new Grpc\Server();
$port = $this->server->add_secure_http2_port('0.0.0.0:0',
$server_credentials);
+ $this->server->start();
$this->channel = new Grpc\Channel(
'localhost:' . $port,
[
@@ -55,70 +54,58 @@ class SecureEndToEndTest extends PHPUnit_Framework_TestCase{
public function tearDown() {
unset($this->channel);
unset($this->server);
- unset($this->client_queue);
- unset($this->server_queue);
}
public function testSimpleRequestBody() {
- $this->server->start();
$deadline = Grpc\Timeval::inf_future();
$status_text = 'xyz';
$call = new Grpc\Call($this->channel,
'dummy_method',
$deadline);
- $tag = 1;
- $call->invoke($this->client_queue, $tag, $tag);
- $server_tag = 2;
-
- $call->writes_done($tag);
- $event = $this->client_queue->next($deadline);
- $this->assertNotNull($event);
- $this->assertSame(Grpc\FINISH_ACCEPTED, $event->type);
- $this->assertSame(Grpc\OP_OK, $event->data);
-
- // check that a server rpc new was received
- $this->server->request_call($server_tag);
- $event = $this->server_queue->next($deadline);
- $this->assertNotNull($event);
- $this->assertSame(Grpc\SERVER_RPC_NEW, $event->type);
+
+ $event = $call->start_batch([
+ Grpc\OP_SEND_INITIAL_METADATA => [],
+ Grpc\OP_SEND_CLOSE_FROM_CLIENT => true
+ ]);
+
+ $this->assertTrue($event->send_metadata);
+ $this->assertTrue($event->send_close);
+
+ $event = $this->server->request_call();
+ $this->assertSame('dummy_method', $event->method);
+ $this->assertSame([], $event->metadata);
$server_call = $event->call;
- $this->assertNotNull($server_call);
- $server_call->server_accept($this->server_queue, $server_tag);
-
- $server_call->server_end_initial_metadata();
-
- // the server sends the status
- $server_call->start_write_status(Grpc\STATUS_OK, $status_text, $server_tag);
- $event = $this->server_queue->next($deadline);
- $this->assertNotNull($event);
- $this->assertSame(Grpc\FINISH_ACCEPTED, $event->type);
- $this->assertSame(Grpc\OP_OK, $event->data);
-
- // the client gets CLIENT_METADATA_READ
- $event = $this->client_queue->next($deadline);
- $this->assertNotNull($event);
- $this->assertSame(Grpc\CLIENT_METADATA_READ, $event->type);
-
- // the client gets FINISHED
- $event = $this->client_queue->next($deadline);
- $this->assertNotNull($event);
- $this->assertSame(Grpc\FINISHED, $event->type);
- $status = $event->data;
+
+ $event = $server_call->start_batch([
+ Grpc\OP_SEND_INITIAL_METADATA => [],
+ Grpc\OP_SEND_STATUS_FROM_SERVER => [
+ 'metadata' => [],
+ 'code' => Grpc\STATUS_OK,
+ 'details' => $status_text
+ ],
+ Grpc\OP_RECV_CLOSE_ON_SERVER => true
+ ]);
+
+ $this->assertTrue($event->send_metadata);
+ $this->assertTrue($event->send_status);
+ $this->assertFalse($event->cancelled);
+
+ $event = $call->start_batch([
+ Grpc\OP_RECV_INITIAL_METADATA => true,
+ Grpc\OP_RECV_STATUS_ON_CLIENT => true
+ ]);
+
+ $this->assertSame([], $event->metadata);
+ $status = $event->status;
+ $this->assertSame([], $status->metadata);
$this->assertSame(Grpc\STATUS_OK, $status->code);
$this->assertSame($status_text, $status->details);
- // and the server gets FINISHED
- $event = $this->server_queue->next($deadline);
- $this->assertNotNull($event);
- $this->assertSame(Grpc\FINISHED, $event->type);
- $status = $event->data;
-
unset($call);
unset($server_call);
}
public function testClientServerFullRequestResponse() {
- $this->server->start();
$deadline = Grpc\Timeval::inf_future();
$req_text = 'client_server_full_request_response';
$reply_text = 'reply:client_server_full_request_response';
@@ -127,78 +114,52 @@ class SecureEndToEndTest extends PHPUnit_Framework_TestCase{
$call = new Grpc\Call($this->channel,
'dummy_method',
$deadline);
- $tag = 1;
- $call->invoke($this->client_queue, $tag, $tag);
-
- $server_tag = 2;
-
- // the client writes
- $call->start_write($req_text, $tag);
- $event = $this->client_queue->next($deadline);
- $this->assertNotNull($event);
- $this->assertSame(Grpc\WRITE_ACCEPTED, $event->type);
-
- // check that a server rpc new was received
- $this->server->request_call($server_tag);
- $event = $this->server_queue->next($deadline);
- $this->assertNotNull($event);
- $this->assertSame(Grpc\SERVER_RPC_NEW, $event->type);
+
+ $event = $call->start_batch([
+ Grpc\OP_SEND_INITIAL_METADATA => [],
+ Grpc\OP_SEND_CLOSE_FROM_CLIENT => true,
+ Grpc\OP_SEND_MESSAGE => $req_text
+ ]);
+
+ $this->assertTrue($event->send_metadata);
+ $this->assertTrue($event->send_close);
+ $this->assertTrue($event->send_message);
+
+ $event = $this->server->request_call();
+ $this->assertSame('dummy_method', $event->method);
$server_call = $event->call;
- $this->assertNotNull($server_call);
- $server_call->server_accept($this->server_queue, $server_tag);
-
- $server_call->server_end_initial_metadata();
-
- // start the server read
- $server_call->start_read($server_tag);
- $event = $this->server_queue->next($deadline);
- $this->assertNotNull($event);
- $this->assertSame(Grpc\READ, $event->type);
- $this->assertSame($req_text, $event->data);
-
- // the server replies
- $server_call->start_write($reply_text, $server_tag);
- $event = $this->server_queue->next($deadline);
- $this->assertNotNull($event);
- $this->assertSame(Grpc\WRITE_ACCEPTED, $event->type);
-
- // the client reads the metadata
- $event = $this->client_queue->next($deadline);
- $this->assertNotNull($event);
- $this->assertSame(Grpc\CLIENT_METADATA_READ, $event->type);
-
- // the client reads the reply
- $call->start_read($tag);
- $event = $this->client_queue->next($deadline);
- $this->assertNotNull($event);
- $this->assertSame(Grpc\READ, $event->type);
- $this->assertSame($reply_text, $event->data);
-
- // the client sends writes done
- $call->writes_done($tag);
- $event = $this->client_queue->next($deadline);
- $this->assertSame(Grpc\FINISH_ACCEPTED, $event->type);
- $this->assertSame(Grpc\OP_OK, $event->data);
-
- // the server sends the status
- $server_call->start_write_status(GRPC\STATUS_OK, $status_text, $server_tag);
- $event = $this->server_queue->next($deadline);
- $this->assertSame(Grpc\FINISH_ACCEPTED, $event->type);
- $this->assertSame(Grpc\OP_OK, $event->data);
-
- // the client gets FINISHED
- $event = $this->client_queue->next($deadline);
- $this->assertNotNull($event);
- $this->assertSame(Grpc\FINISHED, $event->type);
- $status = $event->data;
+
+ $event = $server_call->start_batch([
+ Grpc\OP_SEND_INITIAL_METADATA => [],
+ Grpc\OP_SEND_MESSAGE => $reply_text,
+ Grpc\OP_SEND_STATUS_FROM_SERVER => [
+ 'metadata' => [],
+ 'code' => Grpc\STATUS_OK,
+ 'details' => $status_text
+ ],
+ Grpc\OP_RECV_MESSAGE => true,
+ Grpc\OP_RECV_CLOSE_ON_SERVER => true,
+ ]);
+
+ $this->assertTrue($event->send_metadata);
+ $this->assertTrue($event->send_status);
+ $this->assertTrue($event->send_message);
+ $this->assertFalse($event->cancelled);
+ $this->assertSame($req_text, $event->message);
+
+ $event = $call->start_batch([
+ Grpc\OP_RECV_INITIAL_METADATA => true,
+ Grpc\OP_RECV_MESSAGE => true,
+ Grpc\OP_RECV_STATUS_ON_CLIENT => true,
+ ]);
+
+ $this->assertSame([], $event->metadata);
+ $this->assertSame($reply_text, $event->message);
+ $status = $event->status;
+ $this->assertSame([], $status->metadata);
$this->assertSame(Grpc\STATUS_OK, $status->code);
$this->assertSame($status_text, $status->details);
- // and the server gets FINISHED
- $event = $this->server_queue->next($deadline);
- $this->assertNotNull($event);
- $this->assertSame(Grpc\FINISHED, $event->type);
-
unset($call);
unset($server_call);
}
diff --git a/src/python/README.md b/src/python/README.md
index 490a229d1d..c8057be38b 100644
--- a/src/python/README.md
+++ b/src/python/README.md
@@ -46,7 +46,7 @@ Installing
- Install gRPC Python's dependencies
```
-$ pip install -r requirements.txt
+$ pip install -r src/python/requirements.txt
```
- Install gRPC Python
diff --git a/src/python/interop/interop/_insecure_interop_test.py b/src/python/interop/interop/_insecure_interop_test.py
index 1fa6b8b3f8..e4ddff1a0b 100644
--- a/src/python/interop/interop/_insecure_interop_test.py
+++ b/src/python/interop/interop/_insecure_interop_test.py
@@ -42,11 +42,12 @@ class InsecureInteropTest(
unittest.TestCase):
def setUp(self):
- self.server = implementations.insecure_server(methods.SERVER_METHODS, 0)
+ self.server = implementations.insecure_server(
+ methods.SERVICE_NAME, methods.SERVER_METHODS, 0)
self.server.start()
port = self.server.port()
self.stub = implementations.insecure_stub(
- methods.CLIENT_METHODS, 'localhost', port)
+ methods.SERVICE_NAME, methods.CLIENT_METHODS, 'localhost', port)
def tearDown(self):
self.server.stop()
diff --git a/src/python/interop/interop/_secure_interop_test.py b/src/python/interop/interop/_secure_interop_test.py
index cc9e93821a..214212dca4 100644
--- a/src/python/interop/interop/_secure_interop_test.py
+++ b/src/python/interop/interop/_secure_interop_test.py
@@ -46,12 +46,12 @@ class SecureInteropTest(
def setUp(self):
self.server = implementations.secure_server(
- methods.SERVER_METHODS, 0, resources.private_key(),
- resources.certificate_chain())
+ methods.SERVICE_NAME, methods.SERVER_METHODS, 0,
+ resources.private_key(), resources.certificate_chain())
self.server.start()
port = self.server.port()
self.stub = implementations.secure_stub(
- methods.CLIENT_METHODS, 'localhost', port,
+ methods.SERVICE_NAME, methods.CLIENT_METHODS, 'localhost', port,
resources.test_root_certificates(), None, None,
server_host_override=_SERVER_HOST_OVERRIDE)
diff --git a/src/python/interop/interop/client.py b/src/python/interop/interop/client.py
index b674a64f9d..fb7dfb5729 100644
--- a/src/python/interop/interop/client.py
+++ b/src/python/interop/interop/client.py
@@ -67,12 +67,13 @@ def _stub(args):
root_certificates = resources.prod_root_certificates()
stub = implementations.secure_stub(
- methods.CLIENT_METHODS, args.server_host, args.server_port,
- root_certificates, None, None,
+ methods.SERVICE_NAME, methods.CLIENT_METHODS, args.server_host,
+ args.server_port, root_certificates, None, None,
server_host_override=args.server_host_override)
else:
stub = implementations.insecure_stub(
- methods.CLIENT_METHODS, args.server_host, args.server_port)
+ methods.SERVICE_NAME, methods.CLIENT_METHODS, args.server_host,
+ args.server_port)
return stub
diff --git a/src/python/interop/interop/methods.py b/src/python/interop/interop/methods.py
index 2e15fac915..79550a3789 100644
--- a/src/python/interop/interop/methods.py
+++ b/src/python/interop/interop/methods.py
@@ -32,7 +32,7 @@
import enum
import threading
-from grpc.early_adopter import utilities
+from grpc.framework.alpha import utilities
from interop import empty_pb2
from interop import messages_pb2
@@ -122,31 +122,31 @@ _SERVER_HALF_DUPLEX_CALL = utilities.stream_stream_service_description(
messages_pb2.StreamingOutputCallResponse.SerializeToString)
-_SERVICE_NAME = '/grpc.testing.TestService'
+SERVICE_NAME = 'grpc.testing.TestService'
-EMPTY_CALL_METHOD_NAME = _SERVICE_NAME + '/EmptyCall'
-UNARY_CALL_METHOD_NAME = _SERVICE_NAME + '/UnaryCall'
-STREAMING_OUTPUT_CALL_METHOD_NAME = _SERVICE_NAME + '/StreamingOutputCall'
-STREAMING_INPUT_CALL_METHOD_NAME = _SERVICE_NAME + '/StreamingInputCall'
-FULL_DUPLEX_CALL_METHOD_NAME = _SERVICE_NAME + '/FullDuplexCall'
-HALF_DUPLEX_CALL_METHOD_NAME = _SERVICE_NAME + '/HalfDuplexCall'
+_EMPTY_CALL_METHOD_NAME = 'EmptyCall'
+_UNARY_CALL_METHOD_NAME = 'UnaryCall'
+_STREAMING_OUTPUT_CALL_METHOD_NAME = 'StreamingOutputCall'
+_STREAMING_INPUT_CALL_METHOD_NAME = 'StreamingInputCall'
+_FULL_DUPLEX_CALL_METHOD_NAME = 'FullDuplexCall'
+_HALF_DUPLEX_CALL_METHOD_NAME = 'HalfDuplexCall'
CLIENT_METHODS = {
- EMPTY_CALL_METHOD_NAME: _CLIENT_EMPTY_CALL,
- UNARY_CALL_METHOD_NAME: _CLIENT_UNARY_CALL,
- STREAMING_OUTPUT_CALL_METHOD_NAME: _CLIENT_STREAMING_OUTPUT_CALL,
- STREAMING_INPUT_CALL_METHOD_NAME: _CLIENT_STREAMING_INPUT_CALL,
- FULL_DUPLEX_CALL_METHOD_NAME: _CLIENT_FULL_DUPLEX_CALL,
- HALF_DUPLEX_CALL_METHOD_NAME: _CLIENT_HALF_DUPLEX_CALL,
+ _EMPTY_CALL_METHOD_NAME: _CLIENT_EMPTY_CALL,
+ _UNARY_CALL_METHOD_NAME: _CLIENT_UNARY_CALL,
+ _STREAMING_OUTPUT_CALL_METHOD_NAME: _CLIENT_STREAMING_OUTPUT_CALL,
+ _STREAMING_INPUT_CALL_METHOD_NAME: _CLIENT_STREAMING_INPUT_CALL,
+ _FULL_DUPLEX_CALL_METHOD_NAME: _CLIENT_FULL_DUPLEX_CALL,
+ _HALF_DUPLEX_CALL_METHOD_NAME: _CLIENT_HALF_DUPLEX_CALL,
}
SERVER_METHODS = {
- EMPTY_CALL_METHOD_NAME: _SERVER_EMPTY_CALL,
- UNARY_CALL_METHOD_NAME: _SERVER_UNARY_CALL,
- STREAMING_OUTPUT_CALL_METHOD_NAME: _SERVER_STREAMING_OUTPUT_CALL,
- STREAMING_INPUT_CALL_METHOD_NAME: _SERVER_STREAMING_INPUT_CALL,
- FULL_DUPLEX_CALL_METHOD_NAME: _SERVER_FULL_DUPLEX_CALL,
- HALF_DUPLEX_CALL_METHOD_NAME: _SERVER_HALF_DUPLEX_CALL,
+ _EMPTY_CALL_METHOD_NAME: _SERVER_EMPTY_CALL,
+ _UNARY_CALL_METHOD_NAME: _SERVER_UNARY_CALL,
+ _STREAMING_OUTPUT_CALL_METHOD_NAME: _SERVER_STREAMING_OUTPUT_CALL,
+ _STREAMING_INPUT_CALL_METHOD_NAME: _SERVER_STREAMING_INPUT_CALL,
+ _FULL_DUPLEX_CALL_METHOD_NAME: _SERVER_FULL_DUPLEX_CALL,
+ _HALF_DUPLEX_CALL_METHOD_NAME: _SERVER_HALF_DUPLEX_CALL,
}
diff --git a/src/python/interop/interop/server.py b/src/python/interop/interop/server.py
index 4e4b127a9a..5791203743 100644
--- a/src/python/interop/interop/server.py
+++ b/src/python/interop/interop/server.py
@@ -54,10 +54,11 @@ def serve():
private_key = resources.private_key()
certificate_chain = resources.certificate_chain()
server = implementations.secure_server(
- methods.SERVER_METHODS, args.port, private_key, certificate_chain)
+ methods.SERVICE_NAME, methods.SERVER_METHODS, args.port, private_key,
+ certificate_chain)
else:
server = implementations.insecure_server(
- methods.SERVER_METHODS, args.port)
+ methods.SERVICE_NAME, methods.SERVER_METHODS, args.port)
server.start()
logging.info('Server serving.')
diff --git a/src/python/src/grpc/_adapter/_call.c b/src/python/src/grpc/_adapter/_call.c
index dca2e49373..d8806e5680 100644
--- a/src/python/src/grpc/_adapter/_call.c
+++ b/src/python/src/grpc/_adapter/_call.c
@@ -45,7 +45,7 @@ static int pygrpc_call_init(Call *self, PyObject *args, PyObject *kwds) {
const PyObject *channel;
const char *method;
const char *host;
- const double deadline;
+ double deadline;
static char *kwlist[] = {"channel", "method", "host", "deadline", NULL};
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!ssd:Call", kwlist,
diff --git a/src/python/src/grpc/_adapter/_face_test_case.py b/src/python/src/grpc/_adapter/_face_test_case.py
index 475d780c95..923e889844 100644
--- a/src/python/src/grpc/_adapter/_face_test_case.py
+++ b/src/python/src/grpc/_adapter/_face_test_case.py
@@ -34,7 +34,7 @@ import unittest
from grpc._adapter import fore
from grpc._adapter import rear
from grpc.framework.base import util
-from grpc.framework.base.packets import implementations as tickets_implementations
+from grpc.framework.base import implementations as base_implementations
from grpc.framework.face import implementations as face_implementations
from grpc.framework.face.testing import coverage
from grpc.framework.face.testing import serial
@@ -50,31 +50,12 @@ class FaceTestCase(test_case.FaceTestCase, coverage.BlockingCoverage):
"""Provides abstract Face-layer tests a GRPC-backed implementation."""
def set_up_implementation(
- self,
- name,
- methods,
- inline_value_in_value_out_methods,
- inline_value_in_stream_out_methods,
- inline_stream_in_value_out_methods,
- inline_stream_in_stream_out_methods,
- event_value_in_value_out_methods,
- event_value_in_stream_out_methods,
- event_stream_in_value_out_methods,
- event_stream_in_stream_out_methods,
- multi_method):
+ self, name, methods, method_implementations,
+ multi_method_implementation):
pool = logging_pool.pool(_MAXIMUM_POOL_SIZE)
servicer = face_implementations.servicer(
- pool,
- inline_value_in_value_out_methods=inline_value_in_value_out_methods,
- inline_value_in_stream_out_methods=inline_value_in_stream_out_methods,
- inline_stream_in_value_out_methods=inline_stream_in_value_out_methods,
- inline_stream_in_stream_out_methods=inline_stream_in_stream_out_methods,
- event_value_in_value_out_methods=event_value_in_value_out_methods,
- event_value_in_stream_out_methods=event_value_in_stream_out_methods,
- event_stream_in_value_out_methods=event_stream_in_value_out_methods,
- event_stream_in_stream_out_methods=event_stream_in_stream_out_methods,
- multi_method=multi_method)
+ pool, method_implementations, multi_method_implementation)
serialization = serial.serialization(methods)
@@ -88,17 +69,16 @@ class FaceTestCase(test_case.FaceTestCase, coverage.BlockingCoverage):
serialization.request_serializers,
serialization.response_deserializers, False, None, None, None)
rear_link.start()
- front = tickets_implementations.front(pool, pool, pool)
- back = tickets_implementations.back(
+ front = base_implementations.front_link(pool, pool, pool)
+ back = base_implementations.back_link(
servicer, pool, pool, pool, _TIMEOUT, _MAXIMUM_TIMEOUT)
fore_link.join_rear_link(back)
back.join_fore_link(fore_link)
rear_link.join_fore_link(front)
front.join_rear_link(rear_link)
- server = face_implementations.server()
- stub = face_implementations.stub(front, pool)
- return server, stub, (rear_link, fore_link, front, back)
+ stub = face_implementations.generic_stub(front, pool)
+ return stub, (rear_link, fore_link, front, back)
def tear_down_implementation(self, memo):
rear_link, fore_link, front, back = memo
diff --git a/src/python/src/grpc/_adapter/_links_test.py b/src/python/src/grpc/_adapter/_links_test.py
index 5d7e677243..cfdcc2c4bc 100644
--- a/src/python/src/grpc/_adapter/_links_test.py
+++ b/src/python/src/grpc/_adapter/_links_test.py
@@ -37,7 +37,6 @@ from grpc._adapter import _test_links
from grpc._adapter import fore
from grpc._adapter import rear
from grpc.framework.base import interfaces
-from grpc.framework.base.packets import packets as tickets
from grpc.framework.foundation import logging_pool
_IDENTITY = lambda x: x
@@ -60,9 +59,11 @@ class RoundTripTest(unittest.TestCase):
test_fore_link = _test_links.ForeLink(None, None)
def rear_action(front_to_back_ticket, fore_link):
if front_to_back_ticket.kind in (
- tickets.Kind.COMPLETION, tickets.Kind.ENTIRE):
- back_to_front_ticket = tickets.BackToFrontPacket(
- front_to_back_ticket.operation_id, 0, tickets.Kind.COMPLETION, None)
+ interfaces.FrontToBackTicket.Kind.COMPLETION,
+ interfaces.FrontToBackTicket.Kind.ENTIRE):
+ back_to_front_ticket = interfaces.BackToFrontTicket(
+ front_to_back_ticket.operation_id, 0,
+ interfaces.BackToFrontTicket.Kind.COMPLETION, None)
fore_link.accept_back_to_front_ticket(back_to_front_ticket)
test_rear_link = _test_links.RearLink(rear_action, None)
@@ -80,21 +81,25 @@ class RoundTripTest(unittest.TestCase):
test_fore_link.join_rear_link(rear_link)
rear_link.start()
- front_to_back_ticket = tickets.FrontToBackPacket(
- test_operation_id, 0, tickets.Kind.ENTIRE, test_method,
- interfaces.ServicedSubscription.Kind.FULL, None, None, _TIMEOUT)
+ front_to_back_ticket = interfaces.FrontToBackTicket(
+ test_operation_id, 0, interfaces.FrontToBackTicket.Kind.ENTIRE,
+ test_method, interfaces.ServicedSubscription.Kind.FULL, None, None,
+ _TIMEOUT)
rear_link.accept_front_to_back_ticket(front_to_back_ticket)
with test_fore_link.condition:
while (not test_fore_link.tickets or
- test_fore_link.tickets[-1].kind is tickets.Kind.CONTINUATION):
+ test_fore_link.tickets[-1].kind is
+ interfaces.BackToFrontTicket.Kind.CONTINUATION):
test_fore_link.condition.wait()
rear_link.stop()
fore_link.stop()
with test_fore_link.condition:
- self.assertIs(test_fore_link.tickets[-1].kind, tickets.Kind.COMPLETION)
+ self.assertIs(
+ test_fore_link.tickets[-1].kind,
+ interfaces.BackToFrontTicket.Kind.COMPLETION)
def testEntireRoundTrip(self):
test_operation_id = object()
@@ -109,11 +114,15 @@ class RoundTripTest(unittest.TestCase):
else:
payload = test_back_to_front_datum
terminal = front_to_back_ticket.kind in (
- tickets.Kind.COMPLETION, tickets.Kind.ENTIRE)
+ interfaces.FrontToBackTicket.Kind.COMPLETION,
+ interfaces.FrontToBackTicket.Kind.ENTIRE)
if payload is not None or terminal:
- back_to_front_ticket = tickets.BackToFrontPacket(
- front_to_back_ticket.operation_id, rear_sequence_number[0],
- tickets.Kind.COMPLETION if terminal else tickets.Kind.CONTINUATION,
+ if terminal:
+ kind = interfaces.BackToFrontTicket.Kind.COMPLETION
+ else:
+ kind = interfaces.BackToFrontTicket.Kind.CONTINUATION
+ back_to_front_ticket = interfaces.BackToFrontTicket(
+ front_to_back_ticket.operation_id, rear_sequence_number[0], kind,
payload)
rear_sequence_number[0] += 1
fore_link.accept_back_to_front_ticket(back_to_front_ticket)
@@ -134,15 +143,16 @@ class RoundTripTest(unittest.TestCase):
test_fore_link.join_rear_link(rear_link)
rear_link.start()
- front_to_back_ticket = tickets.FrontToBackPacket(
- test_operation_id, 0, tickets.Kind.ENTIRE, test_method,
- interfaces.ServicedSubscription.Kind.FULL, None,
+ front_to_back_ticket = interfaces.FrontToBackTicket(
+ test_operation_id, 0, interfaces.FrontToBackTicket.Kind.ENTIRE,
+ test_method, interfaces.ServicedSubscription.Kind.FULL, None,
test_front_to_back_datum, _TIMEOUT)
rear_link.accept_front_to_back_ticket(front_to_back_ticket)
with test_fore_link.condition:
while (not test_fore_link.tickets or
- test_fore_link.tickets[-1].kind is not tickets.Kind.COMPLETION):
+ test_fore_link.tickets[-1].kind is not
+ interfaces.BackToFrontTicket.Kind.COMPLETION):
test_fore_link.condition.wait()
rear_link.stop()
@@ -172,11 +182,15 @@ class RoundTripTest(unittest.TestCase):
else:
response = None
terminal = front_to_back_ticket.kind in (
- tickets.Kind.COMPLETION, tickets.Kind.ENTIRE)
+ interfaces.FrontToBackTicket.Kind.COMPLETION,
+ interfaces.FrontToBackTicket.Kind.ENTIRE)
if response is not None or terminal:
- back_to_front_ticket = tickets.BackToFrontPacket(
- front_to_back_ticket.operation_id, rear_sequence_number[0],
- tickets.Kind.COMPLETION if terminal else tickets.Kind.CONTINUATION,
+ if terminal:
+ kind = interfaces.BackToFrontTicket.Kind.COMPLETION
+ else:
+ kind = interfaces.BackToFrontTicket.Kind.CONTINUATION
+ back_to_front_ticket = interfaces.BackToFrontTicket(
+ front_to_back_ticket.operation_id, rear_sequence_number[0], kind,
response)
rear_sequence_number[0] += 1
fore_link.accept_back_to_front_ticket(back_to_front_ticket)
@@ -198,26 +212,31 @@ class RoundTripTest(unittest.TestCase):
test_fore_link.join_rear_link(rear_link)
rear_link.start()
- commencement_ticket = tickets.FrontToBackPacket(
- test_operation_id, 0, tickets.Kind.COMMENCEMENT, test_method,
- interfaces.ServicedSubscription.Kind.FULL, None, None, _TIMEOUT)
+ commencement_ticket = interfaces.FrontToBackTicket(
+ test_operation_id, 0,
+ interfaces.FrontToBackTicket.Kind.COMMENCEMENT, test_method,
+ interfaces.ServicedSubscription.Kind.FULL, None, None,
+ _TIMEOUT)
fore_sequence_number = 1
rear_link.accept_front_to_back_ticket(commencement_ticket)
for request in scenario.requests():
- continuation_ticket = tickets.FrontToBackPacket(
- test_operation_id, fore_sequence_number, tickets.Kind.CONTINUATION,
- None, None, None, request, None)
+ continuation_ticket = interfaces.FrontToBackTicket(
+ test_operation_id, fore_sequence_number,
+ interfaces.FrontToBackTicket.Kind.CONTINUATION, None, None, None,
+ request, None)
fore_sequence_number += 1
rear_link.accept_front_to_back_ticket(continuation_ticket)
- completion_ticket = tickets.FrontToBackPacket(
- test_operation_id, fore_sequence_number, tickets.Kind.COMPLETION, None,
- None, None, None, None)
+ completion_ticket = interfaces.FrontToBackTicket(
+ test_operation_id, fore_sequence_number,
+ interfaces.FrontToBackTicket.Kind.COMPLETION, None, None, None, None,
+ None)
fore_sequence_number += 1
rear_link.accept_front_to_back_ticket(completion_ticket)
with test_fore_link.condition:
while (not test_fore_link.tickets or
- test_fore_link.tickets[-1].kind is not tickets.Kind.COMPLETION):
+ test_fore_link.tickets[-1].kind is not
+ interfaces.BackToFrontTicket.Kind.COMPLETION):
test_fore_link.condition.wait()
rear_link.stop()
diff --git a/src/python/src/grpc/_adapter/_lonely_rear_link_test.py b/src/python/src/grpc/_adapter/_lonely_rear_link_test.py
index 77821ba71a..25799d679c 100644
--- a/src/python/src/grpc/_adapter/_lonely_rear_link_test.py
+++ b/src/python/src/grpc/_adapter/_lonely_rear_link_test.py
@@ -34,7 +34,6 @@ import unittest
from grpc._adapter import _test_links
from grpc._adapter import rear
from grpc.framework.base import interfaces
-from grpc.framework.base.packets import packets
from grpc.framework.foundation import logging_pool
_IDENTITY = lambda x: x
@@ -68,7 +67,7 @@ class LonelyRearLinkTest(unittest.TestCase):
rear_link.join_fore_link(fore_link)
rear_link.start()
- front_to_back_ticket = packets.FrontToBackPacket(
+ front_to_back_ticket = interfaces.FrontToBackTicket(
test_operation_id, 0, front_to_back_ticket_kind, test_method,
interfaces.ServicedSubscription.Kind.FULL, None, None, _TIMEOUT)
rear_link.accept_front_to_back_ticket(front_to_back_ticket)
@@ -76,22 +75,25 @@ class LonelyRearLinkTest(unittest.TestCase):
with fore_link.condition:
while True:
if (fore_link.tickets and
- fore_link.tickets[-1].kind is not packets.Kind.CONTINUATION):
+ fore_link.tickets[-1].kind is not
+ interfaces.BackToFrontTicket.Kind.CONTINUATION):
break
fore_link.condition.wait()
rear_link.stop()
with fore_link.condition:
- self.assertIsNot(fore_link.tickets[-1].kind, packets.Kind.COMPLETION)
+ self.assertIsNot(
+ fore_link.tickets[-1].kind,
+ interfaces.BackToFrontTicket.Kind.COMPLETION)
- @unittest.skip('TODO(nathaniel): This seems to have broken in the last few weeks; fix it.')
- def testLonelyClientCommencementPacket(self):
+ def testLonelyClientCommencementTicket(self):
self._perform_lonely_client_test_with_ticket_kind(
- packets.Kind.COMMENCEMENT)
+ interfaces.FrontToBackTicket.Kind.COMMENCEMENT)
- def testLonelyClientEntirePacket(self):
- self._perform_lonely_client_test_with_ticket_kind(packets.Kind.ENTIRE)
+ def testLonelyClientEntireTicket(self):
+ self._perform_lonely_client_test_with_ticket_kind(
+ interfaces.FrontToBackTicket.Kind.ENTIRE)
if __name__ == '__main__':
diff --git a/src/python/src/grpc/_adapter/_test_links.py b/src/python/src/grpc/_adapter/_test_links.py
index ac0d6e20b6..86c7e61b17 100644
--- a/src/python/src/grpc/_adapter/_test_links.py
+++ b/src/python/src/grpc/_adapter/_test_links.py
@@ -31,7 +31,7 @@
import threading
-from grpc.framework.base.packets import interfaces
+from grpc.framework.base import interfaces
class ForeLink(interfaces.ForeLink):
diff --git a/src/python/src/grpc/_adapter/fore.py b/src/python/src/grpc/_adapter/fore.py
index 6ef9e60006..05016cdaf3 100644
--- a/src/python/src/grpc/_adapter/fore.py
+++ b/src/python/src/grpc/_adapter/fore.py
@@ -36,10 +36,8 @@ import time
from grpc._adapter import _common
from grpc._adapter import _low
-from grpc.framework.base import interfaces
-from grpc.framework.base.packets import interfaces as ticket_interfaces
-from grpc.framework.base.packets import null
-from grpc.framework.base.packets import packets as tickets
+from grpc.framework.base import interfaces as base_interfaces
+from grpc.framework.base import null
from grpc.framework.foundation import activated
from grpc.framework.foundation import logging_pool
@@ -69,7 +67,7 @@ def _status(call, rpc_state):
rpc_state.write.low = _LowWrite.CLOSED
-class ForeLink(ticket_interfaces.ForeLink, activated.Activated):
+class ForeLink(base_interfaces.ForeLink, activated.Activated):
"""A service-side bridge between RPC Framework and the C-ish _low code."""
def __init__(
@@ -127,9 +125,9 @@ class ForeLink(ticket_interfaces.ForeLink, activated.Activated):
self._request_deserializers[method],
self._response_serializers[method])
- ticket = tickets.FrontToBackPacket(
- call, 0, tickets.Kind.COMMENCEMENT, method,
- interfaces.ServicedSubscription.Kind.FULL, None, None,
+ ticket = base_interfaces.FrontToBackTicket(
+ call, 0, base_interfaces.FrontToBackTicket.Kind.COMMENCEMENT, method,
+ base_interfaces.ServicedSubscription.Kind.FULL, None, None,
service_acceptance.deadline - time.time())
self._rear_link.accept_front_to_back_ticket(ticket)
@@ -145,14 +143,16 @@ class ForeLink(ticket_interfaces.ForeLink, activated.Activated):
sequence_number = rpc_state.sequence_number
rpc_state.sequence_number += 1
if event.bytes is None:
- ticket = tickets.FrontToBackPacket(
- call, sequence_number, tickets.Kind.COMPLETION, None, None, None,
+ ticket = base_interfaces.FrontToBackTicket(
+ call, sequence_number,
+ base_interfaces.FrontToBackTicket.Kind.COMPLETION, None, None, None,
None, None)
else:
call.read(call)
- ticket = tickets.FrontToBackPacket(
- call, sequence_number, tickets.Kind.CONTINUATION, None, None, None,
- rpc_state.deserializer(event.bytes), None)
+ ticket = base_interfaces.FrontToBackTicket(
+ call, sequence_number,
+ base_interfaces.FrontToBackTicket.Kind.CONTINUATION, None, None,
+ None, rpc_state.deserializer(event.bytes), None)
self._rear_link.accept_front_to_back_ticket(ticket)
@@ -180,9 +180,10 @@ class ForeLink(ticket_interfaces.ForeLink, activated.Activated):
sequence_number = rpc_state.sequence_number
rpc_state.sequence_number += 1
- ticket = tickets.FrontToBackPacket(
- call, sequence_number, tickets.Kind.TRANSMISSION_FAILURE, None, None,
- None, None, None)
+ ticket = base_interfaces.FrontToBackTicket(
+ call, sequence_number,
+ base_interfaces.FrontToBackTicket.Kind.TRANSMISSION_FAILURE, None,
+ None, None, None, None)
self._rear_link.accept_front_to_back_ticket(ticket)
def _on_finish_event(self, event):
@@ -199,18 +200,21 @@ class ForeLink(ticket_interfaces.ForeLink, activated.Activated):
sequence_number = rpc_state.sequence_number
rpc_state.sequence_number += 1
if code is _low.Code.CANCELLED:
- ticket = tickets.FrontToBackPacket(
- call, sequence_number, tickets.Kind.CANCELLATION, None, None, None,
- None, None)
+ ticket = base_interfaces.FrontToBackTicket(
+ call, sequence_number,
+ base_interfaces.FrontToBackTicket.Kind.CANCELLATION, None, None,
+ None, None, None)
elif code is _low.Code.EXPIRED:
- ticket = tickets.FrontToBackPacket(
- call, sequence_number, tickets.Kind.EXPIRATION, None, None, None,
+ ticket = base_interfaces.FrontToBackTicket(
+ call, sequence_number,
+ base_interfaces.FrontToBackTicket.Kind.EXPIRATION, None, None, None,
None, None)
else:
# TODO(nathaniel): Better mapping of codes to ticket-categories
- ticket = tickets.FrontToBackPacket(
- call, sequence_number, tickets.Kind.TRANSMISSION_FAILURE, None, None,
- None, None, None)
+ ticket = base_interfaces.FrontToBackTicket(
+ call, sequence_number,
+ base_interfaces.FrontToBackTicket.Kind.TRANSMISSION_FAILURE, None,
+ None, None, None, None)
self._rear_link.accept_front_to_back_ticket(ticket)
def _spin(self, completion_queue, server):
@@ -266,7 +270,7 @@ class ForeLink(ticket_interfaces.ForeLink, activated.Activated):
self._rpc_states.pop(call, None)
def join_rear_link(self, rear_link):
- """See ticket_interfaces.ForeLink.join_rear_link for specification."""
+ """See base_interfaces.ForeLink.join_rear_link for specification."""
self._rear_link = null.NULL_REAR_LINK if rear_link is None else rear_link
def _start(self):
@@ -346,101 +350,14 @@ class ForeLink(ticket_interfaces.ForeLink, activated.Activated):
return self._port
def accept_back_to_front_ticket(self, ticket):
- """See ticket_interfaces.ForeLink.accept_back_to_front_ticket for spec."""
+ """See base_interfaces.ForeLink.accept_back_to_front_ticket for spec."""
with self._condition:
if self._server is None:
return
- if ticket.kind is tickets.Kind.CONTINUATION:
+ if ticket.kind is base_interfaces.BackToFrontTicket.Kind.CONTINUATION:
self._continue(ticket.operation_id, ticket.payload)
- elif ticket.kind is tickets.Kind.COMPLETION:
+ elif ticket.kind is base_interfaces.BackToFrontTicket.Kind.COMPLETION:
self._complete(ticket.operation_id, ticket.payload)
else:
self._cancel(ticket.operation_id)
-
-
-class _ActivatedForeLink(ticket_interfaces.ForeLink, activated.Activated):
-
- def __init__(
- self, port, request_deserializers, response_serializers,
- root_certificates, key_chain_pairs):
- self._port = port
- self._request_deserializers = request_deserializers
- self._response_serializers = response_serializers
- self._root_certificates = root_certificates
- self._key_chain_pairs = key_chain_pairs
-
- self._lock = threading.Lock()
- self._pool = None
- self._fore_link = None
- self._rear_link = null.NULL_REAR_LINK
-
- def join_rear_link(self, rear_link):
- with self._lock:
- self._rear_link = null.NULL_REAR_LINK if rear_link is None else rear_link
- if self._fore_link is not None:
- self._fore_link.join_rear_link(rear_link)
-
- def _start(self):
- with self._lock:
- self._pool = logging_pool.pool(_THREAD_POOL_SIZE)
- self._fore_link = ForeLink(
- self._pool, self._request_deserializers, self._response_serializers,
- self._root_certificates, self._key_chain_pairs, port=self._port)
- self._fore_link.join_rear_link(self._rear_link)
- self._fore_link.start()
- return self
-
- def _stop(self):
- with self._lock:
- self._fore_link.stop()
- self._fore_link = None
- self._pool.shutdown(wait=True)
- self._pool = None
-
- def __enter__(self):
- return self._start()
-
- def __exit__(self, exc_type, exc_val, exc_tb):
- self._stop()
- return False
-
- def start(self):
- return self._start()
-
- def stop(self):
- self._stop()
-
- def port(self):
- with self._lock:
- return None if self._fore_link is None else self._fore_link.port()
-
- def accept_back_to_front_ticket(self, ticket):
- with self._lock:
- if self._fore_link is not None:
- self._fore_link.accept_back_to_front_ticket(ticket)
-
-
-def activated_fore_link(
- port, request_deserializers, response_serializers, root_certificates,
- key_chain_pairs):
- """Creates a ForeLink that is also an activated.Activated.
-
- The returned object is only valid for use between calls to its start and stop
- methods (or in context when used as a context manager).
-
- Args:
- port: The port on which to serve RPCs, or None for a port to be
- automatically selected.
- request_deserializers: A dictionary from RPC method names to request object
- deserializer behaviors.
- response_serializers: A dictionary from RPC method names to response object
- serializer behaviors.
- root_certificates: The PEM-encoded client root certificates as a bytestring
- or None.
- key_chain_pairs: A sequence of PEM-encoded private key-certificate chain
- pairs.
- """
- return _ActivatedForeLink(
- port, request_deserializers, response_serializers, root_certificates,
- key_chain_pairs)
diff --git a/src/python/src/grpc/_adapter/rear.py b/src/python/src/grpc/_adapter/rear.py
index fc71bf0a6c..f19321c426 100644
--- a/src/python/src/grpc/_adapter/rear.py
+++ b/src/python/src/grpc/_adapter/rear.py
@@ -36,9 +36,8 @@ import time
from grpc._adapter import _common
from grpc._adapter import _low
-from grpc.framework.base.packets import interfaces as ticket_interfaces
-from grpc.framework.base.packets import null
-from grpc.framework.base.packets import packets as tickets
+from grpc.framework.base import interfaces as base_interfaces
+from grpc.framework.base import null
from grpc.framework.foundation import activated
from grpc.framework.foundation import logging_pool
@@ -88,7 +87,7 @@ def _write(operation_id, call, outstanding, write_state, serialized_payload):
raise ValueError('Write attempted after writes completed!')
-class RearLink(ticket_interfaces.RearLink, activated.Activated):
+class RearLink(base_interfaces.RearLink, activated.Activated):
"""An invocation-side bridge between RPC Framework and the C-ish _low code."""
def __init__(
@@ -152,9 +151,9 @@ class RearLink(ticket_interfaces.RearLink, activated.Activated):
else:
logging.error('RPC write not accepted! Event: %s', (event,))
rpc_state.active = False
- ticket = tickets.BackToFrontPacket(
+ ticket = base_interfaces.BackToFrontTicket(
operation_id, rpc_state.common.sequence_number,
- tickets.Kind.TRANSMISSION_FAILURE, None)
+ base_interfaces.BackToFrontTicket.Kind.TRANSMISSION_FAILURE, None)
rpc_state.common.sequence_number += 1
self._fore_link.accept_back_to_front_ticket(ticket)
@@ -163,9 +162,10 @@ class RearLink(ticket_interfaces.RearLink, activated.Activated):
rpc_state.call.read(operation_id)
rpc_state.outstanding.add(_low.Event.Kind.READ_ACCEPTED)
- ticket = tickets.BackToFrontPacket(
+ ticket = base_interfaces.BackToFrontTicket(
operation_id, rpc_state.common.sequence_number,
- tickets.Kind.CONTINUATION, rpc_state.common.deserializer(event.bytes))
+ base_interfaces.BackToFrontTicket.Kind.CONTINUATION,
+ rpc_state.common.deserializer(event.bytes))
rpc_state.common.sequence_number += 1
self._fore_link.accept_back_to_front_ticket(ticket)
@@ -173,9 +173,9 @@ class RearLink(ticket_interfaces.RearLink, activated.Activated):
if not event.complete_accepted:
logging.error('RPC complete not accepted! Event: %s', (event,))
rpc_state.active = False
- ticket = tickets.BackToFrontPacket(
+ ticket = base_interfaces.BackToFrontTicket(
operation_id, rpc_state.common.sequence_number,
- tickets.Kind.TRANSMISSION_FAILURE, None)
+ base_interfaces.BackToFrontTicket.Kind.TRANSMISSION_FAILURE, None)
rpc_state.common.sequence_number += 1
self._fore_link.accept_back_to_front_ticket(ticket)
@@ -188,17 +188,15 @@ class RearLink(ticket_interfaces.RearLink, activated.Activated):
"""Handle termination of an RPC."""
# TODO(nathaniel): Cover all statuses.
if event.status.code is _low.Code.OK:
- category = tickets.Kind.COMPLETION
+ kind = base_interfaces.BackToFrontTicket.Kind.COMPLETION
elif event.status.code is _low.Code.CANCELLED:
- # TODO(issue 752): Use a CANCELLATION ticket kind here.
- category = tickets.Kind.SERVICER_FAILURE
+ kind = base_interfaces.BackToFrontTicket.Kind.CANCELLATION
elif event.status.code is _low.Code.EXPIRED:
- category = tickets.Kind.EXPIRATION
+ kind = base_interfaces.BackToFrontTicket.Kind.EXPIRATION
else:
- category = tickets.Kind.TRANSMISSION_FAILURE
- ticket = tickets.BackToFrontPacket(
- operation_id, rpc_state.common.sequence_number, category,
- None)
+ kind = base_interfaces.BackToFrontTicket.Kind.TRANSMISSION_FAILURE
+ ticket = base_interfaces.BackToFrontTicket(
+ operation_id, rpc_state.common.sequence_number, kind, None)
rpc_state.common.sequence_number += 1
self._fore_link.accept_back_to_front_ticket(ticket)
@@ -318,7 +316,7 @@ class RearLink(ticket_interfaces.RearLink, activated.Activated):
rpc_state.active = False
def join_fore_link(self, fore_link):
- """See ticket_interfaces.RearLink.join_fore_link for specification."""
+ """See base_interfaces.RearLink.join_fore_link for specification."""
with self._condition:
self._fore_link = null.NULL_FORE_LINK if fore_link is None else fore_link
@@ -367,147 +365,23 @@ class RearLink(ticket_interfaces.RearLink, activated.Activated):
self._stop()
def accept_front_to_back_ticket(self, ticket):
- """See ticket_interfaces.RearLink.accept_front_to_back_ticket for spec."""
+ """See base_interfaces.RearLink.accept_front_to_back_ticket for spec."""
with self._condition:
if self._completion_queue is None:
return
- if ticket.kind is tickets.Kind.COMMENCEMENT:
+ if ticket.kind is base_interfaces.FrontToBackTicket.Kind.COMMENCEMENT:
self._commence(
ticket.operation_id, ticket.name, ticket.payload, ticket.timeout)
- elif ticket.kind is tickets.Kind.CONTINUATION:
+ elif ticket.kind is base_interfaces.FrontToBackTicket.Kind.CONTINUATION:
self._continue(ticket.operation_id, ticket.payload)
- elif ticket.kind is tickets.Kind.COMPLETION:
+ elif ticket.kind is base_interfaces.FrontToBackTicket.Kind.COMPLETION:
self._complete(ticket.operation_id, ticket.payload)
- elif ticket.kind is tickets.Kind.ENTIRE:
+ elif ticket.kind is base_interfaces.FrontToBackTicket.Kind.ENTIRE:
self._entire(
ticket.operation_id, ticket.name, ticket.payload, ticket.timeout)
- elif ticket.kind is tickets.Kind.CANCELLATION:
+ elif ticket.kind is base_interfaces.FrontToBackTicket.Kind.CANCELLATION:
self._cancel(ticket.operation_id)
else:
# NOTE(nathaniel): All other categories are treated as cancellation.
self._cancel(ticket.operation_id)
-
-
-class _ActivatedRearLink(ticket_interfaces.RearLink, activated.Activated):
-
- def __init__(
- self, host, port, request_serializers, response_deserializers, secure,
- root_certificates, private_key, certificate_chain,
- server_host_override=None):
- self._host = host
- self._port = port
- self._request_serializers = request_serializers
- self._response_deserializers = response_deserializers
- self._secure = secure
- self._root_certificates = root_certificates
- self._private_key = private_key
- self._certificate_chain = certificate_chain
- self._server_host_override = server_host_override
-
- self._lock = threading.Lock()
- self._pool = None
- self._rear_link = None
- self._fore_link = null.NULL_FORE_LINK
-
- def join_fore_link(self, fore_link):
- with self._lock:
- self._fore_link = null.NULL_FORE_LINK if fore_link is None else fore_link
- if self._rear_link is not None:
- self._rear_link.join_fore_link(self._fore_link)
-
- def _start(self):
- with self._lock:
- self._pool = logging_pool.pool(_THREAD_POOL_SIZE)
- self._rear_link = RearLink(
- self._host, self._port, self._pool, self._request_serializers,
- self._response_deserializers, self._secure, self._root_certificates,
- self._private_key, self._certificate_chain,
- server_host_override=self._server_host_override)
- self._rear_link.join_fore_link(self._fore_link)
- self._rear_link.start()
- return self
-
- def _stop(self):
- with self._lock:
- self._rear_link.stop()
- self._rear_link = None
- self._pool.shutdown(wait=True)
- self._pool = None
-
- def __enter__(self):
- return self._start()
-
- def __exit__(self, exc_type, exc_val, exc_tb):
- self._stop()
- return False
-
- def start(self):
- return self._start()
-
- def stop(self):
- self._stop()
-
- def accept_front_to_back_ticket(self, ticket):
- with self._lock:
- if self._rear_link is not None:
- self._rear_link.accept_front_to_back_ticket(ticket)
-
-
-# TODO(issue 726): reconcile these two creation functions.
-def activated_rear_link(
- host, port, request_serializers, response_deserializers):
- """Creates a RearLink that is also an activated.Activated.
-
- The returned object is only valid for use between calls to its start and stop
- methods (or in context when used as a context manager).
-
- Args:
- host: The host to which to connect for RPC service.
- port: The port to which to connect for RPC service.
- request_serializers: A dictionary from RPC method name to request object
- serializer behavior.
- response_deserializers: A dictionary from RPC method name to response
- object deserializer behavior.
- secure: A boolean indicating whether or not to use a secure connection.
- root_certificates: The PEM-encoded root certificates or None to ask for
- them to be retrieved from a default location.
- private_key: The PEM-encoded private key to use or None if no private key
- should be used.
- certificate_chain: The PEM-encoded certificate chain to use or None if no
- certificate chain should be used.
- """
- return _ActivatedRearLink(
- host, port, request_serializers, response_deserializers, False, None,
- None, None)
-
-
-
-def secure_activated_rear_link(
- host, port, request_serializers, response_deserializers, root_certificates,
- private_key, certificate_chain, server_host_override=None):
- """Creates a RearLink that is also an activated.Activated.
-
- The returned object is only valid for use between calls to its start and stop
- methods (or in context when used as a context manager).
-
- Args:
- host: The host to which to connect for RPC service.
- port: The port to which to connect for RPC service.
- request_serializers: A dictionary from RPC method name to request object
- serializer behavior.
- response_deserializers: A dictionary from RPC method name to response
- object deserializer behavior.
- root_certificates: The PEM-encoded root certificates or None to ask for
- them to be retrieved from a default location.
- private_key: The PEM-encoded private key to use or None if no private key
- should be used.
- certificate_chain: The PEM-encoded certificate chain to use or None if no
- certificate chain should be used.
- server_host_override: (For testing only) the target name used for SSL
- host name checking.
- """
- return _ActivatedRearLink(
- host, port, request_serializers, response_deserializers, True,
- root_certificates, private_key, certificate_chain,
- server_host_override=server_host_override)
diff --git a/src/python/src/grpc/early_adopter/implementations.py b/src/python/src/grpc/early_adopter/implementations.py
index 87ea18d666..cc0b8ec9e8 100644
--- a/src/python/src/grpc/early_adopter/implementations.py
+++ b/src/python/src/grpc/early_adopter/implementations.py
@@ -33,10 +33,16 @@ import threading
from grpc._adapter import fore as _fore
from grpc._adapter import rear as _rear
-from grpc.early_adopter import _assembly_utilities
-from grpc.early_adopter import _reexport
-from grpc.early_adopter import interfaces
-from grpc.framework.assembly import implementations as _assembly_implementations
+from grpc.framework.alpha import _face_utilities
+from grpc.framework.alpha import _reexport
+from grpc.framework.alpha import interfaces
+from grpc.framework.base import implementations as _base_implementations
+from grpc.framework.base import util as _base_utilities
+from grpc.framework.face import implementations as _face_implementations
+from grpc.framework.foundation import logging_pool
+
+_THREAD_POOL_SIZE = 80
+_ONE_DAY_IN_SECONDS = 24 * 60 * 60
class _Server(interfaces.Server):
@@ -50,30 +56,40 @@ class _Server(interfaces.Server):
else:
self._key_chain_pairs = ((private_key, certificate_chain),)
+ self._pool = None
+ self._back = None
self._fore_link = None
- self._server = None
def _start(self):
with self._lock:
- if self._server is None:
- self._fore_link = _fore.activated_fore_link(
- self._port, self._breakdown.request_deserializers,
- self._breakdown.response_serializers, None, self._key_chain_pairs)
-
- self._server = _assembly_implementations.assemble_service(
- self._breakdown.implementations, self._fore_link)
- self._server.start()
+ if self._pool is None:
+ self._pool = logging_pool.pool(_THREAD_POOL_SIZE)
+ servicer = _face_implementations.servicer(
+ self._pool, self._breakdown.implementations, None)
+ self._back = _base_implementations.back_link(
+ servicer, self._pool, self._pool, self._pool, _ONE_DAY_IN_SECONDS,
+ _ONE_DAY_IN_SECONDS)
+ self._fore_link = _fore.ForeLink(
+ self._pool, self._breakdown.request_deserializers,
+ self._breakdown.response_serializers, None, self._key_chain_pairs,
+ port=self._port)
+ self._back.join_fore_link(self._fore_link)
+ self._fore_link.join_rear_link(self._back)
+ self._fore_link.start()
else:
raise ValueError('Server currently running!')
def _stop(self):
with self._lock:
- if self._server is None:
+ if self._pool is None:
raise ValueError('Server not running!')
else:
- self._server.stop()
- self._server = None
+ self._fore_link.stop()
+ _base_utilities.wait_for_idle(self._back)
+ self._pool.shutdown(wait=True)
self._fore_link = None
+ self._back = None
+ self._pool = None
def __enter__(self):
self._start()
@@ -93,46 +109,129 @@ class _Server(interfaces.Server):
with self._lock:
return self._fore_link.port()
-def _build_stub(breakdown, activated_rear_link):
- assembly_stub = _assembly_implementations.assemble_dynamic_inline_stub(
- breakdown.implementations, activated_rear_link)
- return _reexport.stub(assembly_stub, breakdown.cardinalities)
+
+class _Stub(interfaces.Stub):
+
+ def __init__(
+ self, breakdown, host, port, secure, root_certificates, private_key,
+ certificate_chain, server_host_override=None):
+ self._lock = threading.Lock()
+ self._breakdown = breakdown
+ self._host = host
+ self._port = port
+ self._secure = secure
+ self._root_certificates = root_certificates
+ self._private_key = private_key
+ self._certificate_chain = certificate_chain
+ self._server_host_override = server_host_override
+
+ self._pool = None
+ self._front = None
+ self._rear_link = None
+ self._understub = None
+
+ def __enter__(self):
+ with self._lock:
+ if self._pool is None:
+ self._pool = logging_pool.pool(_THREAD_POOL_SIZE)
+ self._front = _base_implementations.front_link(
+ self._pool, self._pool, self._pool)
+ self._rear_link = _rear.RearLink(
+ self._host, self._port, self._pool,
+ self._breakdown.request_serializers,
+ self._breakdown.response_deserializers, self._secure,
+ self._root_certificates, self._private_key, self._certificate_chain,
+ server_host_override=self._server_host_override)
+ self._front.join_rear_link(self._rear_link)
+ self._rear_link.join_fore_link(self._front)
+ self._rear_link.start()
+ self._understub = _face_implementations.dynamic_stub(
+ self._breakdown.face_cardinalities, self._front, self._pool, '')
+ else:
+ raise ValueError('Tried to __enter__ already-__enter__ed Stub!')
+ return self
+
+ def __exit__(self, exc_type, exc_val, exc_tb):
+ with self._lock:
+ if self._pool is None:
+ raise ValueError('Tried to __exit__ non-__enter__ed Stub!')
+ else:
+ self._rear_link.stop()
+ _base_utilities.wait_for_idle(self._front)
+ self._pool.shutdown(wait=True)
+ self._rear_link = None
+ self._front = None
+ self._pool = None
+ self._understub = None
+ return False
+
+ def __getattr__(self, attr):
+ with self._lock:
+ if self._pool is None:
+ raise ValueError('Tried to __getattr__ non-__enter__ed Stub!')
+ else:
+ method_cardinality = self._breakdown.cardinalities.get(attr)
+ underlying_attr = getattr(
+ self._understub, self._breakdown.qualified_names.get(attr), None)
+ if method_cardinality is interfaces.Cardinality.UNARY_UNARY:
+ return _reexport.unary_unary_sync_async(underlying_attr)
+ elif method_cardinality is interfaces.Cardinality.UNARY_STREAM:
+ return lambda request, timeout: _reexport.cancellable_iterator(
+ underlying_attr(request, timeout))
+ elif method_cardinality is interfaces.Cardinality.STREAM_UNARY:
+ return _reexport.stream_unary_sync_async(underlying_attr)
+ elif method_cardinality is interfaces.Cardinality.STREAM_STREAM:
+ return lambda request_iterator, timeout: (
+ _reexport.cancellable_iterator(underlying_attr(
+ request_iterator, timeout)))
+ else:
+ raise AttributeError(attr)
+
+
+def _build_stub(
+ service_name, methods, host, port, secure, root_certificates, private_key,
+ certificate_chain, server_host_override=None):
+ breakdown = _face_utilities.break_down_invocation(service_name, methods)
+ return _Stub(
+ breakdown, host, port, secure, root_certificates, private_key,
+ certificate_chain, server_host_override=server_host_override)
-def _build_server(methods, port, private_key, certificate_chain):
- breakdown = _assembly_utilities.break_down_service(methods)
+def _build_server(service_name, methods, port, private_key, certificate_chain):
+ breakdown = _face_utilities.break_down_service(service_name, methods)
return _Server(breakdown, port, private_key, certificate_chain)
-def insecure_stub(methods, host, port):
+def insecure_stub(service_name, methods, host, port):
"""Constructs an insecure interfaces.Stub.
Args:
+ service_name: The package-qualified full name of the service.
methods: A dictionary from RPC method name to
interfaces.RpcMethodInvocationDescription describing the RPCs to be
- supported by the created stub.
+ supported by the created stub. The RPC method names in the dictionary are
+ not qualified by the service name or decorated in any other way.
host: The host to which to connect for RPC service.
port: The port to which to connect for RPC service.
Returns:
An interfaces.Stub affording RPC invocation.
"""
- breakdown = _assembly_utilities.break_down_invocation(methods)
- activated_rear_link = _rear.activated_rear_link(
- host, port, breakdown.request_serializers,
- breakdown.response_deserializers)
- return _build_stub(breakdown, activated_rear_link)
+ return _build_stub(
+ service_name, methods, host, port, False, None, None, None)
def secure_stub(
- methods, host, port, root_certificates, private_key, certificate_chain,
- server_host_override=None):
+ service_name, methods, host, port, root_certificates, private_key,
+ certificate_chain, server_host_override=None):
"""Constructs an insecure interfaces.Stub.
Args:
+ service_name: The package-qualified full name of the service.
methods: A dictionary from RPC method name to
interfaces.RpcMethodInvocationDescription describing the RPCs to be
- supported by the created stub.
+ supported by the created stub. The RPC method names in the dictionary are
+ not qualified by the service name or decorated in any other way.
host: The host to which to connect for RPC service.
port: The port to which to connect for RPC service.
root_certificates: The PEM-encoded root certificates or None to ask for
@@ -147,21 +246,20 @@ def secure_stub(
Returns:
An interfaces.Stub affording RPC invocation.
"""
- breakdown = _assembly_utilities.break_down_invocation(methods)
- activated_rear_link = _rear.secure_activated_rear_link(
- host, port, breakdown.request_serializers,
- breakdown.response_deserializers, root_certificates, private_key,
+ return _build_stub(
+ service_name, methods, host, port, True, root_certificates, private_key,
certificate_chain, server_host_override=server_host_override)
- return _build_stub(breakdown, activated_rear_link)
-def insecure_server(methods, port):
+def insecure_server(service_name, methods, port):
"""Constructs an insecure interfaces.Server.
Args:
+ service_name: The package-qualified full name of the service.
methods: A dictionary from RPC method name to
interfaces.RpcMethodServiceDescription describing the RPCs to
- be serviced by the created server.
+ be serviced by the created server. The RPC method names in the dictionary
+ are not qualified by the service name or decorated in any other way.
port: The desired port on which to serve or zero to ask for a port to
be automatically selected.
@@ -169,16 +267,18 @@ def insecure_server(methods, port):
An interfaces.Server that will run with no security and
service unsecured raw requests.
"""
- return _build_server(methods, port, None, None)
+ return _build_server(service_name, methods, port, None, None)
-def secure_server(methods, port, private_key, certificate_chain):
+def secure_server(service_name, methods, port, private_key, certificate_chain):
"""Constructs a secure interfaces.Server.
Args:
+ service_name: The package-qualified full name of the service.
methods: A dictionary from RPC method name to
interfaces.RpcMethodServiceDescription describing the RPCs to
- be serviced by the created server.
+ be serviced by the created server. The RPC method names in the dictionary
+ are not qualified by the service name or decorated in any other way.
port: The port on which to serve or zero to ask for a port to be
automatically selected.
private_key: A pem-encoded private key.
@@ -187,4 +287,5 @@ def secure_server(methods, port, private_key, certificate_chain):
Returns:
An interfaces.Server that will serve secure traffic.
"""
- return _build_server(methods, port, private_key, certificate_chain)
+ return _build_server(
+ service_name, methods, port, private_key, certificate_chain)
diff --git a/src/python/src/grpc/early_adopter/implementations_test.py b/src/python/src/grpc/early_adopter/implementations_test.py
index 9ef06c32cb..ae4adad90f 100644
--- a/src/python/src/grpc/early_adopter/implementations_test.py
+++ b/src/python/src/grpc/early_adopter/implementations_test.py
@@ -34,9 +34,11 @@
import unittest
from grpc.early_adopter import implementations
-from grpc.early_adopter import utilities
+from grpc.framework.alpha import utilities
from grpc._junkdrawer import math_pb2
+SERVICE_NAME = 'math.Math'
+
DIV = 'Div'
DIV_MANY = 'DivMany'
FIB = 'Fib'
@@ -104,10 +106,12 @@ _TIMEOUT = 3
class EarlyAdopterImplementationsTest(unittest.TestCase):
def setUp(self):
- self.server = implementations.insecure_server(_SERVICE_DESCRIPTIONS, 0)
+ self.server = implementations.insecure_server(
+ SERVICE_NAME, _SERVICE_DESCRIPTIONS, 0)
self.server.start()
port = self.server.port()
- self.stub = implementations.insecure_stub(_INVOCATION_DESCRIPTIONS, 'localhost', port)
+ self.stub = implementations.insecure_stub(
+ SERVICE_NAME, _INVOCATION_DESCRIPTIONS, 'localhost', port)
def tearDown(self):
self.server.stop()
diff --git a/src/python/src/grpc/framework/base/packets/__init__.py b/src/python/src/grpc/framework/alpha/__init__.py
index 7086519106..b89398809f 100644
--- a/src/python/src/grpc/framework/base/packets/__init__.py
+++ b/src/python/src/grpc/framework/alpha/__init__.py
@@ -26,5 +26,3 @@
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-
diff --git a/src/python/src/grpc/early_adopter/_assembly_utilities.py b/src/python/src/grpc/framework/alpha/_face_utilities.py
index facfc2bf0e..fb0cfe426d 100644
--- a/src/python/src/grpc/early_adopter/_assembly_utilities.py
+++ b/src/python/src/grpc/framework/alpha/_face_utilities.py
@@ -30,27 +30,36 @@
import abc
import collections
-# assembly_interfaces is referenced from specification in this module.
-from grpc.framework.assembly import interfaces as assembly_interfaces # pylint: disable=unused-import
-from grpc.framework.assembly import utilities as assembly_utilities
-from grpc.early_adopter import _reexport
-from grpc.early_adopter import interfaces
+# face_interfaces is referenced from specification in this module.
+from grpc.framework.common import cardinality
+from grpc.framework.face import interfaces as face_interfaces # pylint: disable=unused-import
+from grpc.framework.face import utilities as face_utilities
+from grpc.framework.alpha import _reexport
+from grpc.framework.alpha import interfaces
-# TODO(issue 726): Kill the "implementations" attribute of this in favor
-# of the same-information-less-bogusly-represented "cardinalities".
+def _qualified_name(service_name, method_name):
+ return '/%s/%s' % (service_name, method_name)
+
+
+# TODO(nathaniel): This structure is getting bloated; it could be shrunk if
+# implementations._Stub used a generic rather than a dynamic underlying
+# face-layer stub.
class InvocationBreakdown(object):
"""An intermediate representation of invocation-side views of RPC methods.
Attributes:
cardinalities: A dictionary from RPC method name to interfaces.Cardinality
value.
- implementations: A dictionary from RPC method name to
- assembly_interfaces.MethodImplementation describing the method.
- request_serializers: A dictionary from RPC method name to callable
- behavior to be used serializing request values for the RPC.
- response_deserializers: A dictionary from RPC method name to callable
- behavior to be used deserializing response values for the RPC.
+ qualified_names: A dictionary from unqualified RPC method name to
+ service-qualified RPC method name.
+ face_cardinalities: A dictionary from service-qualified RPC method name to
+ to cardinality.Cardinality value.
+ request_serializers: A dictionary from service-qualified RPC method name to
+ callable behavior to be used serializing request values for the RPC.
+ response_deserializers: A dictionary from service-qualified RPC method name
+ to callable behavior to be used deserializing response values for the
+ RPC.
"""
__metaclass__ = abc.ABCMeta
@@ -59,8 +68,8 @@ class _EasyInvocationBreakdown(
InvocationBreakdown,
collections.namedtuple(
'_EasyInvocationBreakdown',
- ('cardinalities', 'implementations', 'request_serializers',
- 'response_deserializers'))):
+ ('cardinalities', 'qualified_names', 'face_cardinalities',
+ 'request_serializers', 'response_deserializers'))):
pass
@@ -68,12 +77,12 @@ class ServiceBreakdown(object):
"""An intermediate representation of service-side views of RPC methods.
Attributes:
- implementations: A dictionary from RPC method name
- assembly_interfaces.MethodImplementation implementing the RPC method.
- request_deserializers: A dictionary from RPC method name to callable
- behavior to be used deserializing request values for the RPC.
- response_serializers: A dictionary from RPC method name to callable
- behavior to be used serializing response values for the RPC.
+ implementations: A dictionary from service-qualified RPC method name to
+ face_interfaces.MethodImplementation implementing the RPC method.
+ request_deserializers: A dictionary from service-qualified RPC method name
+ to callable behavior to be used deserializing request values for the RPC.
+ response_serializers: A dictionary from service-qualified RPC method name
+ to callable behavior to be used serializing response values for the RPC.
"""
__metaclass__ = abc.ABCMeta
@@ -86,10 +95,11 @@ class _EasyServiceBreakdown(
pass
-def break_down_invocation(method_descriptions):
+def break_down_invocation(service_name, method_descriptions):
"""Derives an InvocationBreakdown from several RPC method descriptions.
Args:
+ service_name: The package-qualified full name of the service.
method_descriptions: A dictionary from RPC method name to
interfaces.RpcMethodInvocationDescription describing the RPCs.
@@ -97,28 +107,26 @@ def break_down_invocation(method_descriptions):
An InvocationBreakdown corresponding to the given method descriptions.
"""
cardinalities = {}
- implementations = {}
+ qualified_names = {}
+ face_cardinalities = {}
request_serializers = {}
response_deserializers = {}
for name, method_description in method_descriptions.iteritems():
- cardinality = method_description.cardinality()
- cardinalities[name] = cardinality
- if cardinality is interfaces.Cardinality.UNARY_UNARY:
- implementations[name] = assembly_utilities.unary_unary_inline(None)
- elif cardinality is interfaces.Cardinality.UNARY_STREAM:
- implementations[name] = assembly_utilities.unary_stream_inline(None)
- elif cardinality is interfaces.Cardinality.STREAM_UNARY:
- implementations[name] = assembly_utilities.stream_unary_inline(None)
- elif cardinality is interfaces.Cardinality.STREAM_STREAM:
- implementations[name] = assembly_utilities.stream_stream_inline(None)
- request_serializers[name] = method_description.serialize_request
- response_deserializers[name] = method_description.deserialize_response
+ qualified_name = _qualified_name(service_name, name)
+ method_cardinality = method_description.cardinality()
+ cardinalities[name] = method_description.cardinality()
+ qualified_names[name] = qualified_name
+ face_cardinalities[qualified_name] = _reexport.common_cardinality(
+ method_cardinality)
+ request_serializers[qualified_name] = method_description.serialize_request
+ response_deserializers[qualified_name] = (
+ method_description.deserialize_response)
return _EasyInvocationBreakdown(
- cardinalities, implementations, request_serializers,
+ cardinalities, qualified_names, face_cardinalities, request_serializers,
response_deserializers)
-def break_down_service(method_descriptions):
+def break_down_service(service_name, method_descriptions):
"""Derives a ServiceBreakdown from several RPC method descriptions.
Args:
@@ -132,37 +140,44 @@ def break_down_service(method_descriptions):
request_deserializers = {}
response_serializers = {}
for name, method_description in method_descriptions.iteritems():
- cardinality = method_description.cardinality()
- if cardinality is interfaces.Cardinality.UNARY_UNARY:
+ qualified_name = _qualified_name(service_name, name)
+ method_cardinality = method_description.cardinality()
+ if method_cardinality is interfaces.Cardinality.UNARY_UNARY:
def service(
request, face_rpc_context,
service_behavior=method_description.service_unary_unary):
return service_behavior(
request, _reexport.rpc_context(face_rpc_context))
- implementations[name] = assembly_utilities.unary_unary_inline(service)
- elif cardinality is interfaces.Cardinality.UNARY_STREAM:
+ implementations[qualified_name] = face_utilities.unary_unary_inline(
+ service)
+ elif method_cardinality is interfaces.Cardinality.UNARY_STREAM:
def service(
request, face_rpc_context,
service_behavior=method_description.service_unary_stream):
return service_behavior(
request, _reexport.rpc_context(face_rpc_context))
- implementations[name] = assembly_utilities.unary_stream_inline(service)
- elif cardinality is interfaces.Cardinality.STREAM_UNARY:
+ implementations[qualified_name] = face_utilities.unary_stream_inline(
+ service)
+ elif method_cardinality is interfaces.Cardinality.STREAM_UNARY:
def service(
request_iterator, face_rpc_context,
service_behavior=method_description.service_stream_unary):
return service_behavior(
request_iterator, _reexport.rpc_context(face_rpc_context))
- implementations[name] = assembly_utilities.stream_unary_inline(service)
- elif cardinality is interfaces.Cardinality.STREAM_STREAM:
+ implementations[qualified_name] = face_utilities.stream_unary_inline(
+ service)
+ elif method_cardinality is interfaces.Cardinality.STREAM_STREAM:
def service(
request_iterator, face_rpc_context,
service_behavior=method_description.service_stream_stream):
return service_behavior(
request_iterator, _reexport.rpc_context(face_rpc_context))
- implementations[name] = assembly_utilities.stream_stream_inline(service)
- request_deserializers[name] = method_description.deserialize_request
- response_serializers[name] = method_description.serialize_response
+ implementations[qualified_name] = face_utilities.stream_stream_inline(
+ service)
+ request_deserializers[qualified_name] = (
+ method_description.deserialize_request)
+ response_serializers[qualified_name] = (
+ method_description.serialize_response)
return _EasyServiceBreakdown(
implementations, request_deserializers, response_serializers)
diff --git a/src/python/src/grpc/early_adopter/_reexport.py b/src/python/src/grpc/framework/alpha/_reexport.py
index 35f4e85a72..198cb95ad5 100644
--- a/src/python/src/grpc/early_adopter/_reexport.py
+++ b/src/python/src/grpc/framework/alpha/_reexport.py
@@ -27,11 +27,19 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+from grpc.framework.common import cardinality
from grpc.framework.face import exceptions as face_exceptions
from grpc.framework.face import interfaces as face_interfaces
from grpc.framework.foundation import future
-from grpc.early_adopter import exceptions
-from grpc.early_adopter import interfaces
+from grpc.framework.alpha import exceptions
+from grpc.framework.alpha import interfaces
+
+_EARLY_ADOPTER_CARDINALITY_TO_COMMON_CARDINALITY = {
+ interfaces.Cardinality.UNARY_UNARY: cardinality.Cardinality.UNARY_UNARY,
+ interfaces.Cardinality.UNARY_STREAM: cardinality.Cardinality.UNARY_STREAM,
+ interfaces.Cardinality.STREAM_UNARY: cardinality.Cardinality.STREAM_UNARY,
+ interfaces.Cardinality.STREAM_STREAM: cardinality.Cardinality.STREAM_STREAM,
+}
_ABORTION_REEXPORT = {
face_interfaces.Abortion.CANCELLED: interfaces.Abortion.CANCELLED,
@@ -142,71 +150,54 @@ class _RpcContext(interfaces.RpcContext):
class _UnaryUnarySyncAsync(interfaces.UnaryUnarySyncAsync):
- def __init__(self, face_unary_unary_sync_async):
- self._underlying = face_unary_unary_sync_async
+ def __init__(self, face_unary_unary_multi_callable):
+ self._underlying = face_unary_unary_multi_callable
def __call__(self, request, timeout):
return _call_reexporting_errors(
self._underlying, request, timeout)
def async(self, request, timeout):
- return _ReexportedFuture(self._underlying.async(request, timeout))
+ return _ReexportedFuture(self._underlying.future(request, timeout))
class _StreamUnarySyncAsync(interfaces.StreamUnarySyncAsync):
- def __init__(self, face_stream_unary_sync_async):
- self._underlying = face_stream_unary_sync_async
+ def __init__(self, face_stream_unary_multi_callable):
+ self._underlying = face_stream_unary_multi_callable
def __call__(self, request_iterator, timeout):
return _call_reexporting_errors(
self._underlying, request_iterator, timeout)
def async(self, request_iterator, timeout):
- return _ReexportedFuture(self._underlying.async(request_iterator, timeout))
+ return _ReexportedFuture(self._underlying.future(request_iterator, timeout))
-class _Stub(interfaces.Stub):
+def common_cardinality(early_adopter_cardinality):
+ return _EARLY_ADOPTER_CARDINALITY_TO_COMMON_CARDINALITY[
+ early_adopter_cardinality]
- def __init__(self, assembly_stub, cardinalities):
- self._assembly_stub = assembly_stub
- self._cardinalities = cardinalities
- def __enter__(self):
- self._assembly_stub.__enter__()
- return self
+def common_cardinalities(early_adopter_cardinalities):
+ common_cardinalities = {}
+ for name, early_adopter_cardinality in early_adopter_cardinalities.iteritems():
+ common_cardinalities[name] = _EARLY_ADOPTER_CARDINALITY_TO_COMMON_CARDINALITY[
+ early_adopter_cardinality]
+ return common_cardinalities
- def __exit__(self, exc_type, exc_val, exc_tb):
- self._assembly_stub.__exit__(exc_type, exc_val, exc_tb)
- return False
-
- def __getattr__(self, attr):
- underlying_attr = self._assembly_stub.__getattr__(attr)
- cardinality = self._cardinalities.get(attr)
- # TODO(nathaniel): unify this trick with its other occurrence in the code.
- if cardinality is None:
- for name, cardinality in self._cardinalities.iteritems():
- last_slash_index = name.rfind('/')
- if 0 <= last_slash_index and name[last_slash_index + 1:] == attr:
- break
- else:
- raise AttributeError(attr)
- if cardinality is interfaces.Cardinality.UNARY_UNARY:
- return _UnaryUnarySyncAsync(underlying_attr)
- elif cardinality is interfaces.Cardinality.UNARY_STREAM:
- return lambda request, timeout: _CancellableIterator(
- underlying_attr(request, timeout))
- elif cardinality is interfaces.Cardinality.STREAM_UNARY:
- return _StreamUnarySyncAsync(underlying_attr)
- elif cardinality is interfaces.Cardinality.STREAM_STREAM:
- return lambda request_iterator, timeout: _CancellableIterator(
- underlying_attr(request_iterator, timeout))
- else:
- raise AttributeError(attr)
def rpc_context(face_rpc_context):
return _RpcContext(face_rpc_context)
-def stub(assembly_stub, cardinalities):
- return _Stub(assembly_stub, cardinalities)
+def cancellable_iterator(face_cancellable_iterator):
+ return _CancellableIterator(face_cancellable_iterator)
+
+
+def unary_unary_sync_async(face_unary_unary_multi_callable):
+ return _UnaryUnarySyncAsync(face_unary_unary_multi_callable)
+
+
+def stream_unary_sync_async(face_stream_unary_multi_callable):
+ return _StreamUnarySyncAsync(face_stream_unary_multi_callable)
diff --git a/src/python/src/grpc/early_adopter/exceptions.py b/src/python/src/grpc/framework/alpha/exceptions.py
index 5234d3b91c..5234d3b91c 100644
--- a/src/python/src/grpc/early_adopter/exceptions.py
+++ b/src/python/src/grpc/framework/alpha/exceptions.py
diff --git a/src/python/src/grpc/early_adopter/interfaces.py b/src/python/src/grpc/framework/alpha/interfaces.py
index b733873c1c..8380567c97 100644
--- a/src/python/src/grpc/early_adopter/interfaces.py
+++ b/src/python/src/grpc/framework/alpha/interfaces.py
@@ -33,7 +33,7 @@ import abc
import enum
# exceptions is referenced from specification in this module.
-from grpc.early_adopter import exceptions # pylint: disable=unused-import
+from grpc.framework.alpha import exceptions # pylint: disable=unused-import
from grpc.framework.foundation import activated
from grpc.framework.foundation import future
diff --git a/src/python/src/grpc/early_adopter/utilities.py b/src/python/src/grpc/framework/alpha/utilities.py
index da8ef825aa..7d7f78f5e4 100644
--- a/src/python/src/grpc/early_adopter/utilities.py
+++ b/src/python/src/grpc/framework/alpha/utilities.py
@@ -29,7 +29,7 @@
"""Utilities for use with GRPC."""
-from grpc.early_adopter import interfaces
+from grpc.framework.alpha import interfaces
class _RpcMethodDescription(
diff --git a/src/python/src/grpc/framework/assembly/__init__.py b/src/python/src/grpc/framework/assembly/__init__.py
deleted file mode 100644
index 7086519106..0000000000
--- a/src/python/src/grpc/framework/assembly/__init__.py
+++ /dev/null
@@ -1,30 +0,0 @@
-# Copyright 2015, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-
diff --git a/src/python/src/grpc/framework/assembly/implementations.py b/src/python/src/grpc/framework/assembly/implementations.py
deleted file mode 100644
index f7166ed99d..0000000000
--- a/src/python/src/grpc/framework/assembly/implementations.py
+++ /dev/null
@@ -1,317 +0,0 @@
-# Copyright 2015, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-"""Implementations for assembling RPC framework values."""
-
-import threading
-
-# tickets_interfaces, face_interfaces, and activated are referenced from
-# specification in this module.
-from grpc.framework.assembly import interfaces
-from grpc.framework.base import util as base_utilities
-from grpc.framework.base.packets import implementations as tickets_implementations
-from grpc.framework.base.packets import interfaces as tickets_interfaces # pylint: disable=unused-import
-from grpc.framework.common import cardinality
-from grpc.framework.common import style
-from grpc.framework.face import implementations as face_implementations
-from grpc.framework.face import interfaces as face_interfaces # pylint: disable=unused-import
-from grpc.framework.face import utilities as face_utilities
-from grpc.framework.foundation import activated # pylint: disable=unused-import
-from grpc.framework.foundation import logging_pool
-
-_ONE_DAY_IN_SECONDS = 60 * 60 * 24
-_THREAD_POOL_SIZE = 100
-
-
-class _FaceStub(object):
-
- def __init__(self, rear_link):
- self._rear_link = rear_link
- self._lock = threading.Lock()
- self._pool = None
- self._front = None
- self._under_stub = None
-
- def __enter__(self):
- with self._lock:
- self._pool = logging_pool.pool(_THREAD_POOL_SIZE)
- self._front = tickets_implementations.front(
- self._pool, self._pool, self._pool)
- self._rear_link.start()
- self._rear_link.join_fore_link(self._front)
- self._front.join_rear_link(self._rear_link)
- self._under_stub = face_implementations.stub(self._front, self._pool)
-
- def __exit__(self, exc_type, exc_val, exc_tb):
- with self._lock:
- self._under_stub = None
- self._rear_link.stop()
- base_utilities.wait_for_idle(self._front)
- self._front = None
- self._pool.shutdown(wait=True)
- self._pool = None
- return False
-
- def __getattr__(self, attr):
- with self._lock:
- if self._under_stub is None:
- raise ValueError('Called out of context!')
- else:
- return getattr(self._under_stub, attr)
-
-
-def _behaviors(implementations, front, pool):
- behaviors = {}
- stub = face_implementations.stub(front, pool)
- for name, implementation in implementations.iteritems():
- if implementation.cardinality is cardinality.Cardinality.UNARY_UNARY:
- behaviors[name] = stub.unary_unary_sync_async(name)
- elif implementation.cardinality is cardinality.Cardinality.UNARY_STREAM:
- behaviors[name] = lambda request, context, bound_name=name: (
- stub.inline_value_in_stream_out(bound_name, request, context))
- elif implementation.cardinality is cardinality.Cardinality.STREAM_UNARY:
- behaviors[name] = stub.stream_unary_sync_async(name)
- elif implementation.cardinality is cardinality.Cardinality.STREAM_STREAM:
- behaviors[name] = lambda request_iterator, context, bound_name=name: (
- stub.inline_stream_in_stream_out(
- bound_name, request_iterator, context))
- return behaviors
-
-
-class _DynamicInlineStub(object):
-
- def __init__(self, implementations, rear_link):
- self._implementations = implementations
- self._rear_link = rear_link
- self._lock = threading.Lock()
- self._pool = None
- self._front = None
- self._behaviors = None
-
- def __enter__(self):
- with self._lock:
- self._pool = logging_pool.pool(_THREAD_POOL_SIZE)
- self._front = tickets_implementations.front(
- self._pool, self._pool, self._pool)
- self._rear_link.start()
- self._rear_link.join_fore_link(self._front)
- self._front.join_rear_link(self._rear_link)
- self._behaviors = _behaviors(
- self._implementations, self._front, self._pool)
- return self
-
- def __exit__(self, exc_type, exc_val, exc_tb):
- with self._lock:
- self._behaviors = None
- self._rear_link.stop()
- base_utilities.wait_for_idle(self._front)
- self._front = None
- self._pool.shutdown(wait=True)
- self._pool = None
- return False
-
- def __getattr__(self, attr):
- with self._lock:
- behavior = self._behaviors.get(attr)
- if behavior is None:
- for name, behavior in self._behaviors.iteritems():
- last_slash_index = name.rfind('/')
- if 0 <= last_slash_index and name[last_slash_index + 1:] == attr:
- return behavior
- else:
- raise AttributeError(
- '_DynamicInlineStub instance has no attribute "%s"!' % attr)
- else:
- return behavior
-
-
-def _servicer(implementations, pool):
- inline_value_in_value_out_methods = {}
- inline_value_in_stream_out_methods = {}
- inline_stream_in_value_out_methods = {}
- inline_stream_in_stream_out_methods = {}
- event_value_in_value_out_methods = {}
- event_value_in_stream_out_methods = {}
- event_stream_in_value_out_methods = {}
- event_stream_in_stream_out_methods = {}
-
- for name, implementation in implementations.iteritems():
- if implementation.cardinality is cardinality.Cardinality.UNARY_UNARY:
- if implementation.style is style.Service.INLINE:
- inline_value_in_value_out_methods[name] = (
- face_utilities.inline_unary_unary_method(implementation.unary_unary_inline))
- elif implementation.style is style.Service.EVENT:
- event_value_in_value_out_methods[name] = (
- face_utilities.event_unary_unary_method(implementation.unary_unary_event))
- elif implementation.cardinality is cardinality.Cardinality.UNARY_STREAM:
- if implementation.style is style.Service.INLINE:
- inline_value_in_stream_out_methods[name] = (
- face_utilities.inline_unary_stream_method(implementation.unary_stream_inline))
- elif implementation.style is style.Service.EVENT:
- event_value_in_stream_out_methods[name] = (
- face_utilities.event_unary_stream_method(implementation.unary_stream_event))
- if implementation.cardinality is cardinality.Cardinality.STREAM_UNARY:
- if implementation.style is style.Service.INLINE:
- inline_stream_in_value_out_methods[name] = (
- face_utilities.inline_stream_unary_method(implementation.stream_unary_inline))
- elif implementation.style is style.Service.EVENT:
- event_stream_in_value_out_methods[name] = (
- face_utilities.event_stream_unary_method(implementation.stream_unary_event))
- elif implementation.cardinality is cardinality.Cardinality.STREAM_STREAM:
- if implementation.style is style.Service.INLINE:
- inline_stream_in_stream_out_methods[name] = (
- face_utilities.inline_stream_stream_method(implementation.stream_stream_inline))
- elif implementation.style is style.Service.EVENT:
- event_stream_in_stream_out_methods[name] = (
- face_utilities.event_stream_stream_method(implementation.stream_stream_event))
-
- return face_implementations.servicer(
- pool,
- inline_value_in_value_out_methods=inline_value_in_value_out_methods,
- inline_value_in_stream_out_methods=inline_value_in_stream_out_methods,
- inline_stream_in_value_out_methods=inline_stream_in_value_out_methods,
- inline_stream_in_stream_out_methods=inline_stream_in_stream_out_methods,
- event_value_in_value_out_methods=event_value_in_value_out_methods,
- event_value_in_stream_out_methods=event_value_in_stream_out_methods,
- event_stream_in_value_out_methods=event_stream_in_value_out_methods,
- event_stream_in_stream_out_methods=event_stream_in_stream_out_methods)
-
-
-class _ServiceAssembly(interfaces.Server):
-
- def __init__(self, implementations, fore_link):
- self._implementations = implementations
- self._fore_link = fore_link
- self._lock = threading.Lock()
- self._pool = None
- self._back = None
-
- def _start(self):
- with self._lock:
- self._pool = logging_pool.pool(_THREAD_POOL_SIZE)
- servicer = _servicer(self._implementations, self._pool)
- self._back = tickets_implementations.back(
- servicer, self._pool, self._pool, self._pool, _ONE_DAY_IN_SECONDS,
- _ONE_DAY_IN_SECONDS)
- self._fore_link.start()
- self._fore_link.join_rear_link(self._back)
- self._back.join_fore_link(self._fore_link)
-
- def _stop(self):
- with self._lock:
- self._fore_link.stop()
- base_utilities.wait_for_idle(self._back)
- self._back = None
- self._pool.shutdown(wait=True)
- self._pool = None
-
- def __enter__(self):
- self._start()
- return self
-
- def __exit__(self, exc_type, exc_val, exc_tb):
- self._stop()
- return False
-
- def start(self):
- return self._start()
-
- def stop(self):
- self._stop()
-
- def port(self):
- with self._lock:
- return self._fore_link.port()
-
-
-def assemble_face_stub(activated_rear_link):
- """Assembles a face_interfaces.Stub.
-
- The returned object is a context manager and may only be used in context to
- invoke RPCs.
-
- Args:
- activated_rear_link: An object that is both a tickets_interfaces.RearLink
- and an activated.Activated. The object should be in the inactive state
- when passed to this method.
-
- Returns:
- A face_interfaces.Stub on which, in context, RPCs can be invoked.
- """
- return _FaceStub(activated_rear_link)
-
-
-def assemble_dynamic_inline_stub(implementations, activated_rear_link):
- """Assembles a stub with method names for attributes.
-
- The returned object is a context manager and may only be used in context to
- invoke RPCs.
-
- The returned object, when used in context, will respond to attribute access
- as follows: if the requested attribute is the name of a unary-unary RPC
- method, the value of the attribute will be a
- face_interfaces.UnaryUnarySyncAsync with which to invoke the RPC method. If
- the requested attribute is the name of a unary-stream RPC method, the value
- of the attribute will be a callable with the semantics of
- face_interfaces.Stub.inline_value_in_stream_out, minus the "name" parameter,
- with which to invoke the RPC method. If the requested attribute is the name
- of a stream-unary RPC method, the value of the attribute will be a
- face_interfaces.StreamUnarySyncAsync with which to invoke the RPC method. If
- the requested attribute is the name of a stream-stream RPC method, the value
- of the attribute will be a callable with the semantics of
- face_interfaces.Stub.inline_stream_in_stream_out, minus the "name" parameter,
- with which to invoke the RPC method.
-
- Args:
- implementations: A dictionary from RPC method name to
- interfaces.MethodImplementation.
- activated_rear_link: An object that is both a tickets_interfaces.RearLink
- and an activated.Activated. The object should be in the inactive state
- when passed to this method.
-
- Returns:
- A stub on which, in context, RPCs can be invoked.
- """
- return _DynamicInlineStub(implementations, activated_rear_link)
-
-
-def assemble_service(implementations, activated_fore_link):
- """Assembles the service-side of the RPC Framework stack.
-
- Args:
- implementations: A dictionary from RPC method name to
- interfaces.MethodImplementation.
- activated_fore_link: An object that is both a tickets_interfaces.ForeLink
- and an activated.Activated. The object should be in the inactive state
- when passed to this method.
-
- Returns:
- An interfaces.Server encapsulating RPC service.
- """
- return _ServiceAssembly(implementations, activated_fore_link)
diff --git a/src/python/src/grpc/framework/assembly/implementations_test.py b/src/python/src/grpc/framework/assembly/implementations_test.py
deleted file mode 100644
index 74dc02ed83..0000000000
--- a/src/python/src/grpc/framework/assembly/implementations_test.py
+++ /dev/null
@@ -1,284 +0,0 @@
-# Copyright 2015, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-# TODO(nathaniel): Expand this test coverage.
-
-"""Test of the GRPC-backed ForeLink and RearLink."""
-
-import threading
-import unittest
-
-from grpc.framework.assembly import implementations
-from grpc.framework.assembly import utilities
-from grpc.framework.base import interfaces
-from grpc.framework.base.packets import packets as tickets
-from grpc.framework.base.packets import interfaces as tickets_interfaces
-from grpc.framework.base.packets import null
-from grpc.framework.foundation import logging_pool
-from grpc._junkdrawer import math_pb2
-
-DIV = 'Div'
-DIV_MANY = 'DivMany'
-FIB = 'Fib'
-SUM = 'Sum'
-
-def _fibbonacci(limit):
- left, right = 0, 1
- for _ in xrange(limit):
- yield left
- left, right = right, left + right
-
-
-def _div(request, unused_context):
- return math_pb2.DivReply(
- quotient=request.dividend / request.divisor,
- remainder=request.dividend % request.divisor)
-
-
-def _div_many(request_iterator, unused_context):
- for request in request_iterator:
- yield math_pb2.DivReply(
- quotient=request.dividend / request.divisor,
- remainder=request.dividend % request.divisor)
-
-
-def _fib(request, unused_context):
- for number in _fibbonacci(request.limit):
- yield math_pb2.Num(num=number)
-
-
-def _sum(request_iterator, unused_context):
- accumulation = 0
- for request in request_iterator:
- accumulation += request.num
- return math_pb2.Num(num=accumulation)
-
-
-_IMPLEMENTATIONS = {
- DIV: utilities.unary_unary_inline(_div),
- DIV_MANY: utilities.stream_stream_inline(_div_many),
- FIB: utilities.unary_stream_inline(_fib),
- SUM: utilities.stream_unary_inline(_sum),
-}
-
-_TIMEOUT = 10
-
-
-class PipeLink(tickets_interfaces.ForeLink, tickets_interfaces.RearLink):
-
- def __init__(self):
- self._fore_lock = threading.Lock()
- self._fore_link = null.NULL_FORE_LINK
- self._rear_lock = threading.Lock()
- self._rear_link = null.NULL_REAR_LINK
-
- def __enter__(self):
- return self
-
- def __exit__(self, exc_type, exc_val, exc_tb):
- return False
-
- def start(self):
- pass
-
- def stop(self):
- pass
-
- def accept_back_to_front_ticket(self, ticket):
- with self._fore_lock:
- self._fore_link.accept_back_to_front_ticket(ticket)
-
- def join_rear_link(self, rear_link):
- with self._rear_lock:
- self._rear_link = null.NULL_REAR_LINK if rear_link is None else rear_link
-
- def accept_front_to_back_ticket(self, ticket):
- with self._rear_lock:
- self._rear_link.accept_front_to_back_ticket(ticket)
-
- def join_fore_link(self, fore_link):
- with self._fore_lock:
- self._fore_link = null.NULL_FORE_LINK if fore_link is None else fore_link
-
-
-class FaceStubTest(unittest.TestCase):
-
- def testUnaryUnary(self):
- divisor = 7
- dividend = 13
- expected_quotient = 1
- expected_remainder = 6
- pipe = PipeLink()
- service = implementations.assemble_service(_IMPLEMENTATIONS, pipe)
- face_stub = implementations.assemble_face_stub(pipe)
-
- service.start()
- try:
- with face_stub:
- response = face_stub.blocking_value_in_value_out(
- DIV, math_pb2.DivArgs(divisor=divisor, dividend=dividend),
- _TIMEOUT)
- self.assertEqual(expected_quotient, response.quotient)
- self.assertEqual(expected_remainder, response.remainder)
- finally:
- service.stop()
-
- def testUnaryStream(self):
- stream_length = 29
- pipe = PipeLink()
- service = implementations.assemble_service(_IMPLEMENTATIONS, pipe)
- face_stub = implementations.assemble_face_stub(pipe)
-
- with service, face_stub:
- responses = list(
- face_stub.inline_value_in_stream_out(
- FIB, math_pb2.FibArgs(limit=stream_length), _TIMEOUT))
- numbers = [response.num for response in responses]
- for early, middle, later in zip(numbers, numbers[1:], numbers[2:]):
- self.assertEqual(early + middle, later)
-
- def testStreamUnary(self):
- stream_length = 13
- pipe = PipeLink()
- service = implementations.assemble_service(_IMPLEMENTATIONS, pipe)
- face_stub = implementations.assemble_face_stub(pipe)
-
- with service, face_stub:
- sync_async = face_stub.stream_unary_sync_async(SUM)
- response_future = sync_async.async(
- (math_pb2.Num(num=index) for index in range(stream_length)),
- _TIMEOUT)
- self.assertEqual(
- (stream_length * (stream_length - 1)) / 2,
- response_future.result().num)
-
- def testStreamStream(self):
- stream_length = 17
- divisor_offset = 7
- dividend_offset = 17
- pipe = PipeLink()
- service = implementations.assemble_service(_IMPLEMENTATIONS, pipe)
- face_stub = implementations.assemble_face_stub(pipe)
-
- with service, face_stub:
- response_iterator = face_stub.inline_stream_in_stream_out(
- DIV_MANY,
- (math_pb2.DivArgs(
- divisor=divisor_offset + index,
- dividend=dividend_offset + index)
- for index in range(stream_length)),
- _TIMEOUT)
- for index, response in enumerate(response_iterator):
- self.assertEqual(
- (dividend_offset + index) / (divisor_offset + index),
- response.quotient)
- self.assertEqual(
- (dividend_offset + index) % (divisor_offset + index),
- response.remainder)
- self.assertEqual(stream_length, index + 1)
-
-
-class DynamicInlineStubTest(unittest.TestCase):
-
- def testUnaryUnary(self):
- divisor = 59
- dividend = 973
- expected_quotient = dividend / divisor
- expected_remainder = dividend % divisor
- pipe = PipeLink()
- service = implementations.assemble_service(_IMPLEMENTATIONS, pipe)
- dynamic_stub = implementations.assemble_dynamic_inline_stub(
- _IMPLEMENTATIONS, pipe)
-
- service.start()
- with dynamic_stub:
- response = dynamic_stub.Div(
- math_pb2.DivArgs(divisor=divisor, dividend=dividend), _TIMEOUT)
- self.assertEqual(expected_quotient, response.quotient)
- self.assertEqual(expected_remainder, response.remainder)
- service.stop()
-
- def testUnaryStream(self):
- stream_length = 43
- pipe = PipeLink()
- service = implementations.assemble_service(_IMPLEMENTATIONS, pipe)
- dynamic_stub = implementations.assemble_dynamic_inline_stub(
- _IMPLEMENTATIONS, pipe)
-
- with service, dynamic_stub:
- response_iterator = dynamic_stub.Fib(
- math_pb2.FibArgs(limit=stream_length), _TIMEOUT)
- numbers = tuple(response.num for response in response_iterator)
- for early, middle, later in zip(numbers, numbers[:1], numbers[:2]):
- self.assertEqual(early + middle, later)
- self.assertEqual(stream_length, len(numbers))
-
- def testStreamUnary(self):
- stream_length = 127
- pipe = PipeLink()
- service = implementations.assemble_service(_IMPLEMENTATIONS, pipe)
- dynamic_stub = implementations.assemble_dynamic_inline_stub(
- _IMPLEMENTATIONS, pipe)
-
- with service, dynamic_stub:
- response_future = dynamic_stub.Sum.async(
- (math_pb2.Num(num=index) for index in range(stream_length)),
- _TIMEOUT)
- self.assertEqual(
- (stream_length * (stream_length - 1)) / 2,
- response_future.result().num)
-
- def testStreamStream(self):
- stream_length = 179
- divisor_offset = 71
- dividend_offset = 1763
- pipe = PipeLink()
- service = implementations.assemble_service(_IMPLEMENTATIONS, pipe)
- dynamic_stub = implementations.assemble_dynamic_inline_stub(
- _IMPLEMENTATIONS, pipe)
-
- with service, dynamic_stub:
- response_iterator = dynamic_stub.DivMany(
- (math_pb2.DivArgs(
- divisor=divisor_offset + index,
- dividend=dividend_offset + index)
- for index in range(stream_length)),
- _TIMEOUT)
- for index, response in enumerate(response_iterator):
- self.assertEqual(
- (dividend_offset + index) / (divisor_offset + index),
- response.quotient)
- self.assertEqual(
- (dividend_offset + index) % (divisor_offset + index),
- response.remainder)
- self.assertEqual(stream_length, index + 1)
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/src/python/src/grpc/framework/assembly/interfaces.py b/src/python/src/grpc/framework/assembly/interfaces.py
deleted file mode 100644
index d1a6aad29e..0000000000
--- a/src/python/src/grpc/framework/assembly/interfaces.py
+++ /dev/null
@@ -1,114 +0,0 @@
-# Copyright 2015, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-# TODO(nathaniel): The assembly layer only exists to smooth out wrinkles in
-# the face layer. The two should be squashed together as soon as manageable.
-"""Interfaces for assembling RPC Framework values."""
-
-import abc
-
-# cardinality, style, and stream are referenced from specification in this
-# module.
-from grpc.framework.common import cardinality # pylint: disable=unused-import
-from grpc.framework.common import style # pylint: disable=unused-import
-from grpc.framework.foundation import activated
-from grpc.framework.foundation import stream # pylint: disable=unused-import
-
-
-class MethodImplementation(object):
- """A sum type that describes an RPC method implementation.
-
- Attributes:
- cardinality: A cardinality.Cardinality value.
- style: A style.Service value.
- unary_unary_inline: The implementation of the RPC method as a callable
- value that takes a request value and a face_interfaces.RpcContext object
- and returns a response value. Only non-None if cardinality is
- cardinality.Cardinality.UNARY_UNARY and style is style.Service.INLINE.
- unary_stream_inline: The implementation of the RPC method as a callable
- value that takes a request value and a face_interfaces.RpcContext object
- and returns an iterator of response values. Only non-None if cardinality
- is cardinality.Cardinality.UNARY_STREAM and style is
- style.Service.INLINE.
- stream_unary_inline: The implementation of the RPC method as a callable
- value that takes an iterator of request values and a
- face_interfaces.RpcContext object and returns a response value. Only
- non-None if cardinality is cardinality.Cardinality.STREAM_UNARY and style
- is style.Service.INLINE.
- stream_stream_inline: The implementation of the RPC method as a callable
- value that takes an iterator of request values and a
- face_interfaces.RpcContext object and returns an iterator of response
- values. Only non-None if cardinality is
- cardinality.Cardinality.STREAM_STREAM and style is style.Service.INLINE.
- unary_unary_event: The implementation of the RPC method as a callable value
- that takes a request value, a response callback to which to pass the
- response value of the RPC, and a face_interfaces.RpcContext. Only
- non-None if cardinality is cardinality.Cardinality.UNARY_UNARY and style
- is style.Service.EVENT.
- unary_stream_event: The implementation of the RPC method as a callable
- value that takes a request value, a stream.Consumer to which to pass the
- the response values of the RPC, and a face_interfaces.RpcContext. Only
- non-None if cardinality is cardinality.Cardinality.UNARY_STREAM and style
- is style.Service.EVENT.
- stream_unary_event: The implementation of the RPC method as a callable
- value that takes a response callback to which to pass the response value
- of the RPC and a face_interfaces.RpcContext and returns a stream.Consumer
- to which the request values of the RPC should be passed. Only non-None if
- cardinality is cardinality.Cardinality.STREAM_UNARY and style is
- style.Service.EVENT.
- stream_stream_event: The implementation of the RPC method as a callable
- value that takes a stream.Consumer to which to pass the response values
- of the RPC and a face_interfaces.RpcContext and returns a stream.Consumer
- to which the request values of the RPC should be passed. Only non-None if
- cardinality is cardinality.Cardinality.STREAM_STREAM and style is
- style.Service.EVENT.
- """
- __metaclass__ = abc.ABCMeta
-
-
-class Server(activated.Activated):
- """The server interface.
-
- Aside from being able to be activated and deactivated, objects of this type
- are able to report the port on which they are servicing RPCs.
- """
- __metaclass__ = abc.ABCMeta
-
- # TODO(issue 726): This is an abstraction violation; not every Server is
- # necessarily serving over a network at all.
- @abc.abstractmethod
- def port(self):
- """Identifies the port on which this Server is servicing RPCs.
-
- This method may only be called while the server is active.
-
- Returns:
- The number of the port on which this Server is servicing RPCs.
- """
- raise NotImplementedError()
diff --git a/src/python/src/grpc/framework/assembly/utilities.py b/src/python/src/grpc/framework/assembly/utilities.py
deleted file mode 100644
index 80e7f59c03..0000000000
--- a/src/python/src/grpc/framework/assembly/utilities.py
+++ /dev/null
@@ -1,179 +0,0 @@
-# Copyright 2015, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-"""Utilities for assembling RPC framework values."""
-
-import collections
-
-from grpc.framework.assembly import interfaces
-from grpc.framework.common import cardinality
-from grpc.framework.common import style
-from grpc.framework.face import interfaces as face_interfaces
-from grpc.framework.foundation import stream
-
-
-class _MethodImplementation(
- interfaces.MethodImplementation,
- collections.namedtuple(
- '_MethodImplementation',
- ['cardinality', 'style', 'unary_unary_inline', 'unary_stream_inline',
- 'stream_unary_inline', 'stream_stream_inline', 'unary_unary_event',
- 'unary_stream_event', 'stream_unary_event', 'stream_stream_event',])):
- pass
-
-
-def unary_unary_inline(behavior):
- """Creates an interfaces.MethodImplementation for the given behavior.
-
- Args:
- behavior: The implementation of a unary-unary RPC method as a callable value
- that takes a request value and a face_interfaces.RpcContext object and
- returns a response value.
-
- Returns:
- An interfaces.MethodImplementation derived from the given behavior.
- """
- return _MethodImplementation(
- cardinality.Cardinality.UNARY_UNARY, style.Service.INLINE, behavior,
- None, None, None, None, None, None, None)
-
-
-def unary_stream_inline(behavior):
- """Creates an interfaces.MethodImplementation for the given behavior.
-
- Args:
- behavior: The implementation of a unary-stream RPC method as a callable
- value that takes a request value and a face_interfaces.RpcContext object
- and returns an iterator of response values.
-
- Returns:
- An interfaces.MethodImplementation derived from the given behavior.
- """
- return _MethodImplementation(
- cardinality.Cardinality.UNARY_STREAM, style.Service.INLINE, None,
- behavior, None, None, None, None, None, None)
-
-
-def stream_unary_inline(behavior):
- """Creates an interfaces.MethodImplementation for the given behavior.
-
- Args:
- behavior: The implementation of a stream-unary RPC method as a callable
- value that takes an iterator of request values and a
- face_interfaces.RpcContext object and returns a response value.
-
- Returns:
- An interfaces.MethodImplementation derived from the given behavior.
- """
- return _MethodImplementation(
- cardinality.Cardinality.STREAM_UNARY, style.Service.INLINE, None, None,
- behavior, None, None, None, None, None)
-
-
-def stream_stream_inline(behavior):
- """Creates an interfaces.MethodImplementation for the given behavior.
-
- Args:
- behavior: The implementation of a stream-stream RPC method as a callable
- value that takes an iterator of request values and a
- face_interfaces.RpcContext object and returns an iterator of response
- values.
-
- Returns:
- An interfaces.MethodImplementation derived from the given behavior.
- """
- return _MethodImplementation(
- cardinality.Cardinality.STREAM_STREAM, style.Service.INLINE, None, None,
- None, behavior, None, None, None, None)
-
-
-def unary_unary_event(behavior):
- """Creates an interfaces.MethodImplementation for the given behavior.
-
- Args:
- behavior: The implementation of a unary-unary RPC method as a callable
- value that takes a request value, a response callback to which to pass
- the response value of the RPC, and a face_interfaces.RpcContext.
-
- Returns:
- An interfaces.MethodImplementation derived from the given behavior.
- """
- return _MethodImplementation(
- cardinality.Cardinality.UNARY_UNARY, style.Service.EVENT, None, None,
- None, None, behavior, None, None, None)
-
-
-def unary_stream_event(behavior):
- """Creates an interfaces.MethodImplementation for the given behavior.
-
- Args:
- behavior: The implementation of a unary-stream RPC method as a callable
- value that takes a request value, a stream.Consumer to which to pass the
- the response values of the RPC, and a face_interfaces.RpcContext.
-
- Returns:
- An interfaces.MethodImplementation derived from the given behavior.
- """
- return _MethodImplementation(
- cardinality.Cardinality.UNARY_STREAM, style.Service.EVENT, None, None,
- None, None, None, behavior, None, None)
-
-
-def stream_unary_event(behavior):
- """Creates an interfaces.MethodImplementation for the given behavior.
-
- Args:
- behavior: The implementation of a stream-unary RPC method as a callable
- value that takes a response callback to which to pass the response value
- of the RPC and a face_interfaces.RpcContext and returns a stream.Consumer
- to which the request values of the RPC should be passed.
-
- Returns:
- An interfaces.MethodImplementation derived from the given behavior.
- """
- return _MethodImplementation(
- cardinality.Cardinality.STREAM_UNARY, style.Service.EVENT, None, None,
- None, None, None, None, behavior, None)
-
-
-def stream_stream_event(behavior):
- """Creates an interfaces.MethodImplementation for the given behavior.
-
- Args:
- behavior: The implementation of a stream-stream RPC method as a callable
- value that takes a stream.Consumer to which to pass the response values
- of the RPC and a face_interfaces.RpcContext and returns a stream.Consumer
- to which the request values of the RPC should be passed.
-
- Returns:
- An interfaces.MethodImplementation derived from the given behavior.
- """
- return _MethodImplementation(
- cardinality.Cardinality.STREAM_STREAM, style.Service.EVENT, None, None,
- None, None, None, None, None, behavior)
diff --git a/src/python/src/grpc/framework/base/packets/_cancellation.py b/src/python/src/grpc/framework/base/_cancellation.py
index 2373c78842..ffbc90668f 100644
--- a/src/python/src/grpc/framework/base/packets/_cancellation.py
+++ b/src/python/src/grpc/framework/base/_cancellation.py
@@ -29,8 +29,8 @@
"""State and behavior for operation cancellation."""
-from grpc.framework.base.packets import _interfaces
-from grpc.framework.base.packets import packets
+from grpc.framework.base import _interfaces
+from grpc.framework.base import interfaces
class CancellationManager(_interfaces.CancellationManager):
@@ -58,7 +58,7 @@ class CancellationManager(_interfaces.CancellationManager):
def cancel(self):
"""See _interfaces.CancellationManager.cancel for specification."""
with self._lock:
- self._termination_manager.abort(packets.Kind.CANCELLATION)
- self._transmission_manager.abort(packets.Kind.CANCELLATION)
+ self._termination_manager.abort(interfaces.Outcome.CANCELLED)
+ self._transmission_manager.abort(interfaces.Outcome.CANCELLED)
self._ingestion_manager.abort()
self._expiration_manager.abort()
diff --git a/src/python/src/grpc/framework/base/packets/_constants.py b/src/python/src/grpc/framework/base/_constants.py
index 8fbdc82782..8fbdc82782 100644
--- a/src/python/src/grpc/framework/base/packets/_constants.py
+++ b/src/python/src/grpc/framework/base/_constants.py
diff --git a/src/python/src/grpc/framework/base/packets/_context.py b/src/python/src/grpc/framework/base/_context.py
index e09d4a60c9..d84871d639 100644
--- a/src/python/src/grpc/framework/base/packets/_context.py
+++ b/src/python/src/grpc/framework/base/_context.py
@@ -31,14 +31,13 @@
import time
-# _interfaces and packets are referenced from specification in this module.
-from grpc.framework.base import interfaces as base_interfaces
-from grpc.framework.base.packets import _interfaces # pylint: disable=unused-import
-from grpc.framework.base.packets import packets # pylint: disable=unused-import
+# _interfaces is referenced from specification in this module.
+from grpc.framework.base import interfaces
+from grpc.framework.base import _interfaces # pylint: disable=unused-import
-class OperationContext(base_interfaces.OperationContext):
- """An implementation of base_interfaces.OperationContext."""
+class OperationContext(interfaces.OperationContext):
+ """An implementation of interfaces.OperationContext."""
def __init__(
self, lock, operation_id, local_failure, termination_manager,
@@ -48,8 +47,9 @@ class OperationContext(base_interfaces.OperationContext):
Args:
lock: The operation-wide lock.
operation_id: An object identifying the operation.
- local_failure: Whichever one of packets.Kind.SERVICED_FAILURE or
- packets.Kind.SERVICER_FAILURE describes local failure of customer code.
+ local_failure: Whichever one of interfaces.Outcome.SERVICED_FAILURE or
+ interfaces.Outcome.SERVICER_FAILURE describes local failure of
+ customer code.
termination_manager: The _interfaces.TerminationManager for the operation.
transmission_manager: The _interfaces.TransmissionManager for the
operation.
@@ -75,12 +75,12 @@ class OperationContext(base_interfaces.OperationContext):
self._expiration_manager = expiration_manager
def is_active(self):
- """See base_interfaces.OperationContext.is_active for specification."""
+ """See interfaces.OperationContext.is_active for specification."""
with self._lock:
return self._termination_manager.is_active()
def add_termination_callback(self, callback):
- """See base_interfaces.OperationContext.add_termination_callback."""
+ """See interfaces.OperationContext.add_termination_callback."""
with self._lock:
self._termination_manager.add_callback(callback)
diff --git a/src/python/src/grpc/framework/base/packets/_emission.py b/src/python/src/grpc/framework/base/_emission.py
index 9446b8665d..1829669a72 100644
--- a/src/python/src/grpc/framework/base/packets/_emission.py
+++ b/src/python/src/grpc/framework/base/_emission.py
@@ -29,29 +29,28 @@
"""State and behavior for handling emitted values."""
-# packets is referenced from specifications in this module.
-from grpc.framework.base.packets import _interfaces
-from grpc.framework.base.packets import packets # pylint: disable=unused-import
+from grpc.framework.base import interfaces
+from grpc.framework.base import _interfaces
class _EmissionManager(_interfaces.EmissionManager):
"""An implementation of _interfaces.EmissionManager."""
def __init__(
- self, lock, failure_kind, termination_manager, transmission_manager):
+ self, lock, failure_outcome, termination_manager, transmission_manager):
"""Constructor.
Args:
lock: The operation-wide lock.
- failure_kind: Whichever one of packets.Kind.SERVICED_FAILURE or
- packets.Kind.SERVICER_FAILURE describes this object's methods being
- called inappropriately by customer code.
+ failure_outcome: Whichever one of interfaces.Outcome.SERVICED_FAILURE or
+ interfaces.Outcome.SERVICER_FAILURE describes this object's methods
+ being called inappropriately by customer code.
termination_manager: The _interfaces.TerminationManager for the operation.
transmission_manager: The _interfaces.TransmissionManager for the
operation.
"""
self._lock = lock
- self._failure_kind = failure_kind
+ self._failure_outcome = failure_outcome
self._termination_manager = termination_manager
self._transmission_manager = transmission_manager
self._ingestion_manager = None
@@ -65,8 +64,8 @@ class _EmissionManager(_interfaces.EmissionManager):
self._expiration_manager = expiration_manager
def _abort(self):
- self._termination_manager.abort(self._failure_kind)
- self._transmission_manager.abort(self._failure_kind)
+ self._termination_manager.abort(self._failure_outcome)
+ self._transmission_manager.abort(self._failure_outcome)
self._ingestion_manager.abort()
self._expiration_manager.abort()
@@ -106,7 +105,7 @@ def front_emission_manager(lock, termination_manager, transmission_manager):
An _interfaces.EmissionManager appropriate for front-side use.
"""
return _EmissionManager(
- lock, packets.Kind.SERVICED_FAILURE, termination_manager,
+ lock, interfaces.Outcome.SERVICED_FAILURE, termination_manager,
transmission_manager)
@@ -122,5 +121,5 @@ def back_emission_manager(lock, termination_manager, transmission_manager):
An _interfaces.EmissionManager appropriate for back-side use.
"""
return _EmissionManager(
- lock, packets.Kind.SERVICER_FAILURE, termination_manager,
+ lock, interfaces.Outcome.SERVICER_FAILURE, termination_manager,
transmission_manager)
diff --git a/src/python/src/grpc/framework/base/packets/_ends.py b/src/python/src/grpc/framework/base/_ends.py
index ac369c4fbd..176f3ac06e 100644
--- a/src/python/src/grpc/framework/base/packets/_ends.py
+++ b/src/python/src/grpc/framework/base/_ends.py
@@ -27,42 +27,30 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-"""Implementations of Fronts and Backs."""
+"""Implementations of FrontLinks and BackLinks."""
import collections
import threading
import uuid
-# _interfaces and packets are referenced from specification in this module.
-from grpc.framework.base import interfaces as base_interfaces
-from grpc.framework.base.packets import _cancellation
-from grpc.framework.base.packets import _context
-from grpc.framework.base.packets import _emission
-from grpc.framework.base.packets import _expiration
-from grpc.framework.base.packets import _ingestion
-from grpc.framework.base.packets import _interfaces # pylint: disable=unused-import
-from grpc.framework.base.packets import _reception
-from grpc.framework.base.packets import _termination
-from grpc.framework.base.packets import _transmission
-from grpc.framework.base.packets import interfaces
-from grpc.framework.base.packets import packets # pylint: disable=unused-import
+# _interfaces is referenced from specification in this module.
+from grpc.framework.base import _cancellation
+from grpc.framework.base import _context
+from grpc.framework.base import _emission
+from grpc.framework.base import _expiration
+from grpc.framework.base import _ingestion
+from grpc.framework.base import _interfaces # pylint: disable=unused-import
+from grpc.framework.base import _reception
+from grpc.framework.base import _termination
+from grpc.framework.base import _transmission
+from grpc.framework.base import interfaces
from grpc.framework.foundation import callable_util
_IDLE_ACTION_EXCEPTION_LOG_MESSAGE = 'Exception calling idle action!'
-_OPERATION_OUTCOMES = (
- base_interfaces.Outcome.COMPLETED,
- base_interfaces.Outcome.CANCELLED,
- base_interfaces.Outcome.EXPIRED,
- base_interfaces.Outcome.RECEPTION_FAILURE,
- base_interfaces.Outcome.TRANSMISSION_FAILURE,
- base_interfaces.Outcome.SERVICER_FAILURE,
- base_interfaces.Outcome.SERVICED_FAILURE,
- )
-
-class _EasyOperation(base_interfaces.Operation):
- """A trivial implementation of base_interfaces.Operation."""
+class _EasyOperation(interfaces.Operation):
+ """A trivial implementation of interfaces.Operation."""
def __init__(self, emission_manager, context, cancellation_manager):
"""Constructor.
@@ -70,7 +58,7 @@ class _EasyOperation(base_interfaces.Operation):
Args:
emission_manager: The _interfaces.EmissionManager for the operation that
will accept values emitted by customer code.
- context: The base_interfaces.OperationContext for use by the customer
+ context: The interfaces.OperationContext for use by the customer
during the operation.
cancellation_manager: The _interfaces.CancellationManager for the
operation.
@@ -98,7 +86,7 @@ class _Endlette(object):
# indicates an in-progress fire-and-forget operation for which the customer
# has chosen to ignore results.
self._operations = {}
- self._stats = {outcome: 0 for outcome in _OPERATION_OUTCOMES}
+ self._stats = {outcome: 0 for outcome in interfaces.Outcome}
self._idle_actions = []
def terminal_action(self, operation_id):
@@ -162,9 +150,9 @@ def _front_operate(
"""Constructs objects necessary for front-side operation management.
Args:
- callback: A callable that accepts packets.FrontToBackPackets and delivers
- them to the other side of the operation. Execution of this callable may
- take any arbitrary length of time.
+ callback: A callable that accepts interfaces.FrontToBackTickets and
+ delivers them to the other side of the operation. Execution of this
+ callable may take any arbitrary length of time.
work_pool: A thread pool in which to execute customer code.
transmission_pool: A thread pool to use for transmitting to the other side
of the operation.
@@ -179,7 +167,7 @@ def _front_operate(
complete: A boolean indicating whether or not additional payloads will be
supplied by the customer.
timeout: A length of time in seconds to allow for the operation.
- subscription: A base_interfaces.ServicedSubscription describing the
+ subscription: A interfaces.ServicedSubscription describing the
customer's interest in the results of the operation.
trace_id: A uuid.UUID identifying a set of related operations to which this
operation belongs. May be None.
@@ -198,7 +186,7 @@ def _front_operate(
lock, transmission_pool, callback, operation_id, name,
subscription.kind, trace_id, timeout, termination_manager)
operation_context = _context.OperationContext(
- lock, operation_id, packets.Kind.SERVICED_FAILURE,
+ lock, operation_id, interfaces.Outcome.SERVICED_FAILURE,
termination_manager, transmission_manager)
emission_manager = _emission.front_emission_manager(
lock, termination_manager, transmission_manager)
@@ -226,7 +214,7 @@ def _front_operate(
transmission_manager.inmit(payload, complete)
- if subscription.kind is base_interfaces.ServicedSubscription.Kind.NONE:
+ if subscription.kind is interfaces.ServicedSubscription.Kind.NONE:
returned_reception_manager = None
else:
returned_reception_manager = reception_manager
@@ -236,8 +224,8 @@ def _front_operate(
cancellation_manager)
-class Front(interfaces.Front):
- """An implementation of interfaces.Front."""
+class FrontLink(interfaces.FrontLink):
+ """An implementation of interfaces.FrontLink."""
def __init__(self, work_pool, transmission_pool, utility_pool):
"""Constructor.
@@ -262,16 +250,16 @@ class Front(interfaces.Front):
self._callback = rear_link.accept_front_to_back_ticket
def operation_stats(self):
- """See base_interfaces.End.operation_stats for specification."""
+ """See interfaces.End.operation_stats for specification."""
return self._endlette.operation_stats()
def add_idle_action(self, action):
- """See base_interfaces.End.add_idle_action for specification."""
+ """See interfaces.End.add_idle_action for specification."""
self._endlette.add_idle_action(action)
def operate(
self, name, payload, complete, timeout, subscription, trace_id):
- """See base_interfaces.Front.operate for specification."""
+ """See interfaces.Front.operate for specification."""
operation_id = uuid.uuid4()
with self._endlette:
management = _front_operate(
@@ -288,7 +276,7 @@ class Front(interfaces.Front):
with self._endlette:
reception_manager = self._endlette.get_operation(ticket.operation_id)
if reception_manager:
- reception_manager.receive_packet(ticket)
+ reception_manager.receive_ticket(ticket)
def _back_operate(
@@ -301,16 +289,16 @@ def _back_operate(
Args:
servicer: An interfaces.Servicer for servicing operations.
- callback: A callable that accepts packets.BackToFrontPackets and delivers
- them to the other side of the operation. Execution of this callable may
- take any arbitrary length of time.
+ callback: A callable that accepts interfaces.BackToFrontTickets and
+ delivers them to the other side of the operation. Execution of this
+ callable may take any arbitrary length of time.
work_pool: A thread pool in which to execute customer code.
transmission_pool: A thread pool to use for transmitting to the other side
of the operation.
utility_pool: A thread pool for utility tasks.
termination_action: A no-arg behavior to be called upon operation
completion.
- ticket: The first packets.FrontToBackPacket received for the operation.
+ ticket: The first interfaces.FrontToBackTicket received for the operation.
default_timeout: A length of time in seconds to be used as the default
time alloted for a single operation.
maximum_timeout: A length of time in seconds to be used as the maximum
@@ -327,7 +315,7 @@ def _back_operate(
lock, transmission_pool, callback, ticket.operation_id,
termination_manager, ticket.subscription)
operation_context = _context.OperationContext(
- lock, ticket.operation_id, packets.Kind.SERVICER_FAILURE,
+ lock, ticket.operation_id, interfaces.Outcome.SERVICER_FAILURE,
termination_manager, transmission_manager)
emission_manager = _emission.back_emission_manager(
lock, termination_manager, transmission_manager)
@@ -350,13 +338,13 @@ def _back_operate(
ingestion_manager, expiration_manager)
ingestion_manager.set_expiration_manager(expiration_manager)
- reception_manager.receive_packet(ticket)
+ reception_manager.receive_ticket(ticket)
return reception_manager
-class Back(interfaces.Back):
- """An implementation of interfaces.Back."""
+class BackLink(interfaces.BackLink):
+ """An implementation of interfaces.BackLink."""
def __init__(
self, servicer, work_pool, transmission_pool, utility_pool,
@@ -400,12 +388,12 @@ class Back(interfaces.Back):
self._default_timeout, self._maximum_timeout)
self._endlette.add_operation(ticket.operation_id, reception_manager)
else:
- reception_manager.receive_packet(ticket)
+ reception_manager.receive_ticket(ticket)
def operation_stats(self):
- """See base_interfaces.End.operation_stats for specification."""
+ """See interfaces.End.operation_stats for specification."""
return self._endlette.operation_stats()
def add_idle_action(self, action):
- """See base_interfaces.End.add_idle_action for specification."""
+ """See interfaces.End.add_idle_action for specification."""
self._endlette.add_idle_action(action)
diff --git a/src/python/src/grpc/framework/base/packets/_expiration.py b/src/python/src/grpc/framework/base/_expiration.py
index f58db28aa2..17acbef4c1 100644
--- a/src/python/src/grpc/framework/base/packets/_expiration.py
+++ b/src/python/src/grpc/framework/base/_expiration.py
@@ -31,8 +31,8 @@
import time
-from grpc.framework.base.packets import _interfaces
-from grpc.framework.base.packets import packets
+from grpc.framework.base import _interfaces
+from grpc.framework.base import interfaces
from grpc.framework.foundation import later
@@ -73,8 +73,8 @@ class _ExpirationManager(_interfaces.ExpirationManager):
with self._lock:
if self._future is not None and index == self._index:
self._future = None
- self._termination_manager.abort(packets.Kind.EXPIRATION)
- self._transmission_manager.abort(packets.Kind.EXPIRATION)
+ self._termination_manager.abort(interfaces.Outcome.EXPIRED)
+ self._transmission_manager.abort(interfaces.Outcome.EXPIRED)
self._ingestion_manager.abort()
def start(self):
diff --git a/src/python/src/grpc/framework/base/packets/_ingestion.py b/src/python/src/grpc/framework/base/_ingestion.py
index a750195ccb..06d5b92f0b 100644
--- a/src/python/src/grpc/framework/base/packets/_ingestion.py
+++ b/src/python/src/grpc/framework/base/_ingestion.py
@@ -32,11 +32,10 @@
import abc
import collections
+from grpc.framework.base import _constants
+from grpc.framework.base import _interfaces
from grpc.framework.base import exceptions
from grpc.framework.base import interfaces
-from grpc.framework.base.packets import _constants
-from grpc.framework.base.packets import _interfaces
-from grpc.framework.base.packets import packets
from grpc.framework.foundation import abandonment
from grpc.framework.foundation import callable_util
from grpc.framework.foundation import stream
@@ -206,7 +205,7 @@ class _IngestionManager(_interfaces.IngestionManager):
"""An implementation of _interfaces.IngestionManager."""
def __init__(
- self, lock, pool, consumer_creator, failure_kind, termination_manager,
+ self, lock, pool, consumer_creator, failure_outcome, termination_manager,
transmission_manager):
"""Constructor.
@@ -216,8 +215,10 @@ class _IngestionManager(_interfaces.IngestionManager):
consumer_creator: A _ConsumerCreator wrapping the portion of customer code
that when called returns the stream.Consumer with which the customer
code will ingest payload values.
- failure_kind: Whichever one of packets.Kind.SERVICED_FAILURE or
- packets.Kind.SERVICER_FAILURE describes local failure of customer code.
+ failure_outcome: Whichever one of
+ interfaces.Outcome.SERVICED_FAILURE or
+ interfaces.Outcome.SERVICER_FAILURE describes local failure of
+ customer code.
termination_manager: The _interfaces.TerminationManager for the operation.
transmission_manager: The _interfaces.TransmissionManager for the
operation.
@@ -225,7 +226,7 @@ class _IngestionManager(_interfaces.IngestionManager):
self._lock = lock
self._pool = pool
self._consumer_creator = consumer_creator
- self._failure_kind = failure_kind
+ self._failure_outcome = failure_outcome
self._termination_manager = termination_manager
self._transmission_manager = transmission_manager
self._expiration_manager = None
@@ -299,12 +300,12 @@ class _IngestionManager(_interfaces.IngestionManager):
else:
with self._lock:
if self._pending_ingestion is not None:
- self._abort_and_notify(self._failure_kind)
+ self._abort_and_notify(self._failure_outcome)
self._processing = False
return
else:
with self._lock:
- self._abort_and_notify(self._failure_kind)
+ self._abort_and_notify(self._failure_outcome)
self._processing = False
return
@@ -316,16 +317,16 @@ class _IngestionManager(_interfaces.IngestionManager):
_CREATE_CONSUMER_EXCEPTION_LOG_MESSAGE, requirement)
if consumer_creation_outcome.return_value is None:
with self._lock:
- self._abort_and_notify(self._failure_kind)
+ self._abort_and_notify(self._failure_outcome)
self._processing = False
elif consumer_creation_outcome.return_value.remote_error:
with self._lock:
- self._abort_and_notify(packets.Kind.RECEPTION_FAILURE)
+ self._abort_and_notify(interfaces.Outcome.RECEPTION_FAILURE)
self._processing = False
elif consumer_creation_outcome.return_value.abandoned:
with self._lock:
if self._pending_ingestion is not None:
- self._abort_and_notify(self._failure_kind)
+ self._abort_and_notify(self._failure_outcome)
self._processing = False
else:
wrapped_ingestion_consumer = _WrappedConsumer(
@@ -346,7 +347,7 @@ class _IngestionManager(_interfaces.IngestionManager):
def consume(self, payload):
if self._ingestion_complete:
- self._abort_and_notify(self._failure_kind)
+ self._abort_and_notify(self._failure_outcome)
elif self._pending_ingestion is not None:
if self._processing:
self._pending_ingestion.append(payload)
@@ -359,7 +360,7 @@ class _IngestionManager(_interfaces.IngestionManager):
def terminate(self):
if self._ingestion_complete:
- self._abort_and_notify(self._failure_kind)
+ self._abort_and_notify(self._failure_outcome)
else:
self._ingestion_complete = True
if self._pending_ingestion is not None and not self._processing:
@@ -371,7 +372,7 @@ class _IngestionManager(_interfaces.IngestionManager):
def consume_and_terminate(self, payload):
if self._ingestion_complete:
- self._abort_and_notify(self._failure_kind)
+ self._abort_and_notify(self._failure_outcome)
else:
self._ingestion_complete = True
if self._pending_ingestion is not None:
@@ -397,19 +398,20 @@ def front_ingestion_manager(
Args:
lock: The operation-wide lock.
pool: A thread pool in which to execute customer code.
- subscription: A base_interfaces.ServicedSubscription indicating the
+ subscription: A interfaces.ServicedSubscription indicating the
customer's interest in the results of the operation.
termination_manager: The _interfaces.TerminationManager for the operation.
transmission_manager: The _interfaces.TransmissionManager for the
operation.
- operation_context: A base_interfaces.OperationContext for the operation.
+ operation_context: A interfaces.OperationContext for the operation.
Returns:
An IngestionManager appropriate for front-side use.
"""
ingestion_manager = _IngestionManager(
lock, pool, _FrontConsumerCreator(subscription, operation_context),
- packets.Kind.SERVICED_FAILURE, termination_manager, transmission_manager)
+ interfaces.Outcome.SERVICED_FAILURE, termination_manager,
+ transmission_manager)
ingestion_manager.start(None)
return ingestion_manager
@@ -422,11 +424,11 @@ def back_ingestion_manager(
Args:
lock: The operation-wide lock.
pool: A thread pool in which to execute customer code.
- servicer: A base_interfaces.Servicer for servicing the operation.
+ servicer: A interfaces.Servicer for servicing the operation.
termination_manager: The _interfaces.TerminationManager for the operation.
transmission_manager: The _interfaces.TransmissionManager for the
operation.
- operation_context: A base_interfaces.OperationContext for the operation.
+ operation_context: A interfaces.OperationContext for the operation.
emission_consumer: The _interfaces.EmissionConsumer for the operation.
Returns:
@@ -435,5 +437,6 @@ def back_ingestion_manager(
ingestion_manager = _IngestionManager(
lock, pool, _BackConsumerCreator(
servicer, operation_context, emission_consumer),
- packets.Kind.SERVICER_FAILURE, termination_manager, transmission_manager)
+ interfaces.Outcome.SERVICER_FAILURE, termination_manager,
+ transmission_manager)
return ingestion_manager
diff --git a/src/python/src/grpc/framework/base/packets/_interfaces.py b/src/python/src/grpc/framework/base/_interfaces.py
index 64dc33e8d5..d88cf76590 100644
--- a/src/python/src/grpc/framework/base/packets/_interfaces.py
+++ b/src/python/src/grpc/framework/base/_interfaces.py
@@ -31,9 +31,8 @@
import abc
-# base_interfaces and packets are referenced from specification in this module.
-from grpc.framework.base import interfaces as base_interfaces # pylint: disable=unused-import
-from grpc.framework.base.packets import packets # pylint: disable=unused-import
+# interfaces is referenced from specification in this module.
+from grpc.framework.base import interfaces # pylint: disable=unused-import
from grpc.framework.foundation import stream
@@ -63,7 +62,7 @@ class TerminationManager(object):
immediately.
Args:
- callback: A callable that will be passed a base_interfaces.Outcome value.
+ callback: A callable that will be passed an interfaces.Outcome value.
"""
raise NotImplementedError()
@@ -83,11 +82,11 @@ class TerminationManager(object):
raise NotImplementedError()
@abc.abstractmethod
- def abort(self, kind):
+ def abort(self, outcome):
"""Indicates that the operation must abort for the indicated reason.
Args:
- kind: A value of packets.Kind indicating operation abortion.
+ outcome: An interfaces.Outcome indicating operation abortion.
"""
raise NotImplementedError()
@@ -109,11 +108,11 @@ class TransmissionManager(object):
raise NotImplementedError()
@abc.abstractmethod
- def abort(self, kind):
+ def abort(self, outcome):
"""Indicates that the operation has aborted for the indicated reason.
Args:
- kind: A value of packets.Kind indicating operation abortion.
+ outcome: An interfaces.Outcome indicating operation abortion.
"""
raise NotImplementedError()
@@ -248,15 +247,15 @@ class ExpirationManager(object):
class ReceptionManager(object):
- """A manager responsible for receiving packets from the other end."""
+ """A manager responsible for receiving tickets from the other end."""
__metaclass__ = abc.ABCMeta
@abc.abstractmethod
- def receive_packet(self, packet):
- """Handle a packet from the other side of the operation.
+ def receive_ticket(self, ticket):
+ """Handle a ticket from the other side of the operation.
Args:
- packet: A packets.BackToFrontPacket or packets.FrontToBackPacket
+ ticket: An interfaces.BackToFrontTicket or interfaces.FrontToBackTicket
appropriate to this end of the operation and this object.
"""
raise NotImplementedError()
diff --git a/src/python/src/grpc/framework/base/packets/_reception.py b/src/python/src/grpc/framework/base/_reception.py
index 6e2c9c0a4e..dd428964f1 100644
--- a/src/python/src/grpc/framework/base/packets/_reception.py
+++ b/src/python/src/grpc/framework/base/_reception.py
@@ -27,41 +27,46 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-"""State and behavior for packet reception."""
+"""State and behavior for ticket reception."""
import abc
-from grpc.framework.base.packets import _interfaces
-from grpc.framework.base.packets import packets
+from grpc.framework.base import interfaces
+from grpc.framework.base import _interfaces
+
+_INITIAL_FRONT_TO_BACK_TICKET_KINDS = (
+ interfaces.FrontToBackTicket.Kind.COMMENCEMENT,
+ interfaces.FrontToBackTicket.Kind.ENTIRE,
+)
class _Receiver(object):
- """Common specification of different packet-handling behavior."""
+ """Common specification of different ticket-handling behavior."""
__metaclass__ = abc.ABCMeta
@abc.abstractmethod
- def abort_if_abortive(self, packet):
- """Aborts the operation if the packet is abortive.
+ def abort_if_abortive(self, ticket):
+ """Aborts the operation if the ticket is abortive.
Args:
- packet: A just-arrived packet.
+ ticket: A just-arrived ticket.
Returns:
A boolean indicating whether or not this Receiver aborted the operation
- based on the packet.
+ based on the ticket.
"""
raise NotImplementedError()
@abc.abstractmethod
- def receive(self, packet):
- """Handles a just-arrived packet.
+ def receive(self, ticket):
+ """Handles a just-arrived ticket.
Args:
- packet: A just-arrived packet.
+ ticket: A just-arrived ticket.
Returns:
- A boolean indicating whether or not the packet was terminal (i.e. whether
- or not non-abortive packets are legal after this one).
+ A boolean indicating whether or not the ticket was terminal (i.e. whether
+ or not non-abortive tickets are legal after this one).
"""
raise NotImplementedError()
@@ -72,23 +77,23 @@ class _Receiver(object):
def _abort(
- category, termination_manager, transmission_manager, ingestion_manager,
+ outcome, termination_manager, transmission_manager, ingestion_manager,
expiration_manager):
- """Indicates abortion with the given category to the given managers."""
- termination_manager.abort(category)
- transmission_manager.abort(category)
+ """Indicates abortion with the given outcome to the given managers."""
+ termination_manager.abort(outcome)
+ transmission_manager.abort(outcome)
ingestion_manager.abort()
expiration_manager.abort()
def _abort_if_abortive(
- packet, abortive, termination_manager, transmission_manager,
+ ticket, abortive, termination_manager, transmission_manager,
ingestion_manager, expiration_manager):
- """Determines a packet's being abortive and if so aborts the operation.
+ """Determines a ticket's being abortive and if so aborts the operation.
Args:
- packet: A just-arrived packet.
- abortive: A callable that takes a packet and returns an operation category
+ ticket: A just-arrived ticket.
+ abortive: A callable that takes a ticket and returns an interfaces.Outcome
indicating that the operation should be aborted or None indicating that
the operation should not be aborted.
termination_manager: The operation's _interfaces.TerminationManager.
@@ -99,12 +104,12 @@ def _abort_if_abortive(
Returns:
True if the operation was aborted; False otherwise.
"""
- abort_category = abortive(packet)
- if abort_category is None:
+ abortion_outcome = abortive(ticket)
+ if abortion_outcome is None:
return False
else:
_abort(
- abort_category, termination_manager, transmission_manager,
+ abortion_outcome, termination_manager, transmission_manager,
ingestion_manager, expiration_manager)
return True
@@ -114,12 +119,12 @@ def _reception_failure(
expiration_manager):
"""Aborts the operation with an indication of reception failure."""
_abort(
- packets.Kind.RECEPTION_FAILURE, termination_manager, transmission_manager,
- ingestion_manager, expiration_manager)
+ interfaces.Outcome.RECEPTION_FAILURE, termination_manager,
+ transmission_manager, ingestion_manager, expiration_manager)
class _BackReceiver(_Receiver):
- """Packet-handling specific to the back side of an operation."""
+ """Ticket-handling specific to the back side of an operation."""
def __init__(
self, termination_manager, transmission_manager, ingestion_manager,
@@ -137,69 +142,68 @@ class _BackReceiver(_Receiver):
self._ingestion_manager = ingestion_manager
self._expiration_manager = expiration_manager
- self._first_packet_seen = False
- self._last_packet_seen = False
+ self._first_ticket_seen = False
+ self._last_ticket_seen = False
- def _abortive(self, packet):
- """Determines whether or not (and if so, how) a packet is abortive.
+ def _abortive(self, ticket):
+ """Determines whether or not (and if so, how) a ticket is abortive.
Args:
- packet: A just-arrived packet.
+ ticket: A just-arrived ticket.
Returns:
- One of packets.Kind.CANCELLATION, packets.Kind.SERVICED_FAILURE, or
- packets.Kind.RECEPTION_FAILURE, indicating that the packet is abortive
- and how, or None, indicating that the packet is not abortive.
+ An interfaces.Outcome value describing operation abortion if the
+ ticket is abortive or None if the ticket is not abortive.
"""
- if packet.kind is packets.Kind.CANCELLATION:
- return packets.Kind.CANCELLATION
- elif packet.kind is packets.Kind.EXPIRATION:
- return packets.Kind.EXPIRATION
- elif packet.kind is packets.Kind.SERVICED_FAILURE:
- return packets.Kind.SERVICED_FAILURE
- elif packet.kind is packets.Kind.RECEPTION_FAILURE:
- return packets.Kind.SERVICED_FAILURE
- elif (packet.kind in (packets.Kind.COMMENCEMENT, packets.Kind.ENTIRE) and
- self._first_packet_seen):
- return packets.Kind.RECEPTION_FAILURE
- elif self._last_packet_seen:
- return packets.Kind.RECEPTION_FAILURE
+ if ticket.kind is interfaces.FrontToBackTicket.Kind.CANCELLATION:
+ return interfaces.Outcome.CANCELLED
+ elif ticket.kind is interfaces.FrontToBackTicket.Kind.EXPIRATION:
+ return interfaces.Outcome.EXPIRED
+ elif ticket.kind is interfaces.FrontToBackTicket.Kind.SERVICED_FAILURE:
+ return interfaces.Outcome.SERVICED_FAILURE
+ elif ticket.kind is interfaces.FrontToBackTicket.Kind.RECEPTION_FAILURE:
+ return interfaces.Outcome.SERVICED_FAILURE
+ elif (ticket.kind in _INITIAL_FRONT_TO_BACK_TICKET_KINDS and
+ self._first_ticket_seen):
+ return interfaces.Outcome.RECEPTION_FAILURE
+ elif self._last_ticket_seen:
+ return interfaces.Outcome.RECEPTION_FAILURE
else:
return None
- def abort_if_abortive(self, packet):
+ def abort_if_abortive(self, ticket):
"""See _Receiver.abort_if_abortive for specification."""
return _abort_if_abortive(
- packet, self._abortive, self._termination_manager,
+ ticket, self._abortive, self._termination_manager,
self._transmission_manager, self._ingestion_manager,
self._expiration_manager)
- def receive(self, packet):
+ def receive(self, ticket):
"""See _Receiver.receive for specification."""
- if packet.timeout is not None:
- self._expiration_manager.change_timeout(packet.timeout)
-
- if packet.kind is packets.Kind.COMMENCEMENT:
- self._first_packet_seen = True
- self._ingestion_manager.start(packet.name)
- if packet.payload is not None:
- self._ingestion_manager.consume(packet.payload)
- elif packet.kind is packets.Kind.CONTINUATION:
- self._ingestion_manager.consume(packet.payload)
- elif packet.kind is packets.Kind.COMPLETION:
- self._last_packet_seen = True
- if packet.payload is None:
+ if ticket.timeout is not None:
+ self._expiration_manager.change_timeout(ticket.timeout)
+
+ if ticket.kind is interfaces.FrontToBackTicket.Kind.COMMENCEMENT:
+ self._first_ticket_seen = True
+ self._ingestion_manager.start(ticket.name)
+ if ticket.payload is not None:
+ self._ingestion_manager.consume(ticket.payload)
+ elif ticket.kind is interfaces.FrontToBackTicket.Kind.CONTINUATION:
+ self._ingestion_manager.consume(ticket.payload)
+ elif ticket.kind is interfaces.FrontToBackTicket.Kind.COMPLETION:
+ self._last_ticket_seen = True
+ if ticket.payload is None:
self._ingestion_manager.terminate()
else:
- self._ingestion_manager.consume_and_terminate(packet.payload)
+ self._ingestion_manager.consume_and_terminate(ticket.payload)
else:
- self._first_packet_seen = True
- self._last_packet_seen = True
- self._ingestion_manager.start(packet.name)
- if packet.payload is None:
+ self._first_ticket_seen = True
+ self._last_ticket_seen = True
+ self._ingestion_manager.start(ticket.name)
+ if ticket.payload is None:
self._ingestion_manager.terminate()
else:
- self._ingestion_manager.consume_and_terminate(packet.payload)
+ self._ingestion_manager.consume_and_terminate(ticket.payload)
def reception_failure(self):
"""See _Receiver.reception_failure for specification."""
@@ -209,7 +213,7 @@ class _BackReceiver(_Receiver):
class _FrontReceiver(_Receiver):
- """Packet-handling specific to the front side of an operation."""
+ """Ticket-handling specific to the front side of an operation."""
def __init__(
self, termination_manager, transmission_manager, ingestion_manager,
@@ -227,47 +231,48 @@ class _FrontReceiver(_Receiver):
self._ingestion_manager = ingestion_manager
self._expiration_manager = expiration_manager
- self._last_packet_seen = False
+ self._last_ticket_seen = False
- def _abortive(self, packet):
- """Determines whether or not (and if so, how) a packet is abortive.
+ def _abortive(self, ticket):
+ """Determines whether or not (and if so, how) a ticket is abortive.
Args:
- packet: A just-arrived packet.
+ ticket: A just-arrived ticket.
Returns:
- One of packets.Kind.EXPIRATION, packets.Kind.SERVICER_FAILURE, or
- packets.Kind.RECEPTION_FAILURE, indicating that the packet is abortive
- and how, or None, indicating that the packet is not abortive.
+ An interfaces.Outcome value describing operation abortion if the ticket
+ is abortive or None if the ticket is not abortive.
"""
- if packet.kind is packets.Kind.EXPIRATION:
- return packets.Kind.EXPIRATION
- elif packet.kind is packets.Kind.SERVICER_FAILURE:
- return packets.Kind.SERVICER_FAILURE
- elif packet.kind is packets.Kind.RECEPTION_FAILURE:
- return packets.Kind.SERVICER_FAILURE
- elif self._last_packet_seen:
- return packets.Kind.RECEPTION_FAILURE
+ if ticket.kind is interfaces.BackToFrontTicket.Kind.CANCELLATION:
+ return interfaces.Outcome.CANCELLED
+ elif ticket.kind is interfaces.BackToFrontTicket.Kind.EXPIRATION:
+ return interfaces.Outcome.EXPIRED
+ elif ticket.kind is interfaces.BackToFrontTicket.Kind.SERVICER_FAILURE:
+ return interfaces.Outcome.SERVICER_FAILURE
+ elif ticket.kind is interfaces.BackToFrontTicket.Kind.RECEPTION_FAILURE:
+ return interfaces.Outcome.SERVICER_FAILURE
+ elif self._last_ticket_seen:
+ return interfaces.Outcome.RECEPTION_FAILURE
else:
return None
- def abort_if_abortive(self, packet):
+ def abort_if_abortive(self, ticket):
"""See _Receiver.abort_if_abortive for specification."""
return _abort_if_abortive(
- packet, self._abortive, self._termination_manager,
+ ticket, self._abortive, self._termination_manager,
self._transmission_manager, self._ingestion_manager,
self._expiration_manager)
- def receive(self, packet):
+ def receive(self, ticket):
"""See _Receiver.receive for specification."""
- if packet.kind is packets.Kind.CONTINUATION:
- self._ingestion_manager.consume(packet.payload)
- elif packet.kind is packets.Kind.COMPLETION:
- self._last_packet_seen = True
- if packet.payload is None:
+ if ticket.kind is interfaces.BackToFrontTicket.Kind.CONTINUATION:
+ self._ingestion_manager.consume(ticket.payload)
+ elif ticket.kind is interfaces.BackToFrontTicket.Kind.COMPLETION:
+ self._last_ticket_seen = True
+ if ticket.payload is None:
self._ingestion_manager.terminate()
else:
- self._ingestion_manager.consume_and_terminate(packet.payload)
+ self._ingestion_manager.consume_and_terminate(ticket.payload)
def reception_failure(self):
"""See _Receiver.reception_failure for specification."""
@@ -284,72 +289,72 @@ class _ReceptionManager(_interfaces.ReceptionManager):
Args:
lock: The operation-servicing-wide lock object.
- receiver: A _Receiver responsible for handling received packets.
+ receiver: A _Receiver responsible for handling received tickets.
"""
self._lock = lock
self._receiver = receiver
self._lowest_unseen_sequence_number = 0
- self._out_of_sequence_packets = {}
+ self._out_of_sequence_tickets = {}
self._completed_sequence_number = None
self._aborted = False
- def _sequence_failure(self, packet):
- """Determines a just-arrived packet's sequential legitimacy.
+ def _sequence_failure(self, ticket):
+ """Determines a just-arrived ticket's sequential legitimacy.
Args:
- packet: A just-arrived packet.
+ ticket: A just-arrived ticket.
Returns:
- True if the packet is sequentially legitimate; False otherwise.
+ True if the ticket is sequentially legitimate; False otherwise.
"""
- if packet.sequence_number < self._lowest_unseen_sequence_number:
+ if ticket.sequence_number < self._lowest_unseen_sequence_number:
return True
- elif packet.sequence_number in self._out_of_sequence_packets:
+ elif ticket.sequence_number in self._out_of_sequence_tickets:
return True
elif (self._completed_sequence_number is not None and
- self._completed_sequence_number <= packet.sequence_number):
+ self._completed_sequence_number <= ticket.sequence_number):
return True
else:
return False
- def _process(self, packet):
- """Process those packets ready to be processed.
+ def _process(self, ticket):
+ """Process those tickets ready to be processed.
Args:
- packet: A just-arrived packet the sequence number of which matches this
+ ticket: A just-arrived ticket the sequence number of which matches this
_ReceptionManager's _lowest_unseen_sequence_number field.
"""
while True:
- completed = self._receiver.receive(packet)
+ completed = self._receiver.receive(ticket)
if completed:
- self._out_of_sequence_packets.clear()
- self._completed_sequence_number = packet.sequence_number
- self._lowest_unseen_sequence_number = packet.sequence_number + 1
+ self._out_of_sequence_tickets.clear()
+ self._completed_sequence_number = ticket.sequence_number
+ self._lowest_unseen_sequence_number = ticket.sequence_number + 1
return
else:
- next_packet = self._out_of_sequence_packets.pop(
- packet.sequence_number + 1, None)
- if next_packet is None:
- self._lowest_unseen_sequence_number = packet.sequence_number + 1
+ next_ticket = self._out_of_sequence_tickets.pop(
+ ticket.sequence_number + 1, None)
+ if next_ticket is None:
+ self._lowest_unseen_sequence_number = ticket.sequence_number + 1
return
else:
- packet = next_packet
+ ticket = next_ticket
- def receive_packet(self, packet):
- """See _interfaces.ReceptionManager.receive_packet for specification."""
+ def receive_ticket(self, ticket):
+ """See _interfaces.ReceptionManager.receive_ticket for specification."""
with self._lock:
if self._aborted:
return
- elif self._sequence_failure(packet):
+ elif self._sequence_failure(ticket):
self._receiver.reception_failure()
self._aborted = True
- elif self._receiver.abort_if_abortive(packet):
+ elif self._receiver.abort_if_abortive(ticket):
self._aborted = True
- elif packet.sequence_number == self._lowest_unseen_sequence_number:
- self._process(packet)
+ elif ticket.sequence_number == self._lowest_unseen_sequence_number:
+ self._process(ticket)
else:
- self._out_of_sequence_packets[packet.sequence_number] = packet
+ self._out_of_sequence_tickets[ticket.sequence_number] = ticket
def front_reception_manager(
diff --git a/src/python/src/grpc/framework/base/packets/_termination.py b/src/python/src/grpc/framework/base/_termination.py
index 575eee65a8..ddcbc60293 100644
--- a/src/python/src/grpc/framework/base/packets/_termination.py
+++ b/src/python/src/grpc/framework/base/_termination.py
@@ -31,24 +31,13 @@
import enum
+from grpc.framework.base import _constants
+from grpc.framework.base import _interfaces
from grpc.framework.base import interfaces
-from grpc.framework.base.packets import _constants
-from grpc.framework.base.packets import _interfaces
-from grpc.framework.base.packets import packets
from grpc.framework.foundation import callable_util
_CALLBACK_EXCEPTION_LOG_MESSAGE = 'Exception calling termination callback!'
-_KINDS_TO_OUTCOMES = {
- packets.Kind.COMPLETION: interfaces.Outcome.COMPLETED,
- packets.Kind.CANCELLATION: interfaces.Outcome.CANCELLED,
- packets.Kind.EXPIRATION: interfaces.Outcome.EXPIRED,
- packets.Kind.RECEPTION_FAILURE: interfaces.Outcome.RECEPTION_FAILURE,
- packets.Kind.TRANSMISSION_FAILURE: interfaces.Outcome.TRANSMISSION_FAILURE,
- packets.Kind.SERVICER_FAILURE: interfaces.Outcome.SERVICER_FAILURE,
- packets.Kind.SERVICED_FAILURE: interfaces.Outcome.SERVICED_FAILURE,
- }
-
@enum.unique
class _Requirement(enum.Enum):
@@ -78,8 +67,8 @@ class _TerminationManager(_interfaces.TerminationManager):
action: An action to call on operation termination.
requirements: A combination of _Requirement values identifying what
must finish for the operation to be considered completed.
- local_failure: A packets.Kind specifying what constitutes local failure of
- customer work.
+ local_failure: An interfaces.Outcome specifying what constitutes local
+ failure of customer work.
"""
self._work_pool = work_pool
self._utility_pool = utility_pool
@@ -89,27 +78,23 @@ class _TerminationManager(_interfaces.TerminationManager):
self._expiration_manager = None
self._outstanding_requirements = set(requirements)
- self._kind = None
+ self._outcome = None
self._callbacks = []
def set_expiration_manager(self, expiration_manager):
self._expiration_manager = expiration_manager
- def _terminate(self, kind):
+ def _terminate(self, outcome):
"""Terminates the operation.
Args:
- kind: One of packets.Kind.COMPLETION, packets.Kind.CANCELLATION,
- packets.Kind.EXPIRATION, packets.Kind.RECEPTION_FAILURE,
- packets.Kind.TRANSMISSION_FAILURE, packets.Kind.SERVICER_FAILURE, or
- packets.Kind.SERVICED_FAILURE.
+ outcome: An interfaces.Outcome describing the outcome of the operation.
"""
self._expiration_manager.abort()
self._outstanding_requirements = None
callbacks = list(self._callbacks)
self._callbacks = None
- self._kind = kind
- outcome = _KINDS_TO_OUTCOMES[kind]
+ self._outcome = outcome
act = callable_util.with_exceptions_logged(
self._action, _constants.INTERNAL_ERROR_LOG_MESSAGE)
@@ -122,7 +107,7 @@ class _TerminationManager(_interfaces.TerminationManager):
callback_outcome = callable_util.call_logging_exceptions(
callback, _CALLBACK_EXCEPTION_LOG_MESSAGE, outcome)
if callback_outcome.exception is not None:
- outcome = _KINDS_TO_OUTCOMES[self._local_failure]
+ outcome = self._local_failure
break
self._utility_pool.submit(act, outcome)
@@ -141,8 +126,7 @@ class _TerminationManager(_interfaces.TerminationManager):
if self._outstanding_requirements is None:
self._work_pool.submit(
callable_util.with_exceptions_logged(
- callback, _CALLBACK_EXCEPTION_LOG_MESSAGE),
- _KINDS_TO_OUTCOMES[self._kind])
+ callback, _CALLBACK_EXCEPTION_LOG_MESSAGE), self._outcome)
else:
self._callbacks.append(callback)
@@ -151,28 +135,28 @@ class _TerminationManager(_interfaces.TerminationManager):
if self._outstanding_requirements is not None:
self._outstanding_requirements.discard(_Requirement.EMISSION)
if not self._outstanding_requirements:
- self._terminate(packets.Kind.COMPLETION)
+ self._terminate(interfaces.Outcome.COMPLETED)
def transmission_complete(self):
"""See superclass method for specification."""
if self._outstanding_requirements is not None:
self._outstanding_requirements.discard(_Requirement.TRANSMISSION)
if not self._outstanding_requirements:
- self._terminate(packets.Kind.COMPLETION)
+ self._terminate(interfaces.Outcome.COMPLETED)
def ingestion_complete(self):
"""See superclass method for specification."""
if self._outstanding_requirements is not None:
self._outstanding_requirements.discard(_Requirement.INGESTION)
if not self._outstanding_requirements:
- self._terminate(packets.Kind.COMPLETION)
+ self._terminate(interfaces.Outcome.COMPLETED)
- def abort(self, kind):
+ def abort(self, outcome):
"""See _interfaces.TerminationManager.abort for specification."""
- if kind == self._local_failure:
+ if outcome is self._local_failure:
self._has_failed_locally = True
if self._outstanding_requirements is not None:
- self._terminate(kind)
+ self._terminate(outcome)
def front_termination_manager(
@@ -195,7 +179,7 @@ def front_termination_manager(
return _TerminationManager(
work_pool, utility_pool, action, requirements,
- packets.Kind.SERVICED_FAILURE)
+ interfaces.Outcome.SERVICED_FAILURE)
def back_termination_manager(work_pool, utility_pool, action, subscription_kind):
@@ -217,4 +201,4 @@ def back_termination_manager(work_pool, utility_pool, action, subscription_kind)
return _TerminationManager(
work_pool, utility_pool, action, requirements,
- packets.Kind.SERVICER_FAILURE)
+ interfaces.Outcome.SERVICER_FAILURE)
diff --git a/src/python/src/grpc/framework/base/packets/_transmission.py b/src/python/src/grpc/framework/base/_transmission.py
index ac7f4509db..6845129234 100644
--- a/src/python/src/grpc/framework/base/packets/_transmission.py
+++ b/src/python/src/grpc/framework/base/_transmission.py
@@ -27,43 +27,72 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-"""State and behavior for packet transmission during an operation."""
+"""State and behavior for ticket transmission during an operation."""
import abc
+from grpc.framework.base import _constants
+from grpc.framework.base import _interfaces
from grpc.framework.base import interfaces
-from grpc.framework.base.packets import _constants
-from grpc.framework.base.packets import _interfaces
-from grpc.framework.base.packets import packets
from grpc.framework.foundation import callable_util
_TRANSMISSION_EXCEPTION_LOG_MESSAGE = 'Exception during transmission!'
-_FRONT_TO_BACK_NO_TRANSMISSION_KINDS = (
- packets.Kind.SERVICER_FAILURE,
+_FRONT_TO_BACK_NO_TRANSMISSION_OUTCOMES = (
+ interfaces.Outcome.SERVICER_FAILURE,
)
-_BACK_TO_FRONT_NO_TRANSMISSION_KINDS = (
- packets.Kind.CANCELLATION,
- packets.Kind.SERVICED_FAILURE,
+_BACK_TO_FRONT_NO_TRANSMISSION_OUTCOMES = (
+ interfaces.Outcome.CANCELLED,
+ interfaces.Outcome.SERVICED_FAILURE,
)
-
-class _Packetizer(object):
- """Common specification of different packet-creating behavior."""
+_ABORTION_OUTCOME_TO_FRONT_TO_BACK_TICKET_KIND = {
+ interfaces.Outcome.CANCELLED:
+ interfaces.FrontToBackTicket.Kind.CANCELLATION,
+ interfaces.Outcome.EXPIRED:
+ interfaces.FrontToBackTicket.Kind.EXPIRATION,
+ interfaces.Outcome.RECEPTION_FAILURE:
+ interfaces.FrontToBackTicket.Kind.RECEPTION_FAILURE,
+ interfaces.Outcome.TRANSMISSION_FAILURE:
+ interfaces.FrontToBackTicket.Kind.TRANSMISSION_FAILURE,
+ interfaces.Outcome.SERVICED_FAILURE:
+ interfaces.FrontToBackTicket.Kind.SERVICED_FAILURE,
+ interfaces.Outcome.SERVICER_FAILURE:
+ interfaces.FrontToBackTicket.Kind.SERVICER_FAILURE,
+}
+
+_ABORTION_OUTCOME_TO_BACK_TO_FRONT_TICKET_KIND = {
+ interfaces.Outcome.CANCELLED:
+ interfaces.BackToFrontTicket.Kind.CANCELLATION,
+ interfaces.Outcome.EXPIRED:
+ interfaces.BackToFrontTicket.Kind.EXPIRATION,
+ interfaces.Outcome.RECEPTION_FAILURE:
+ interfaces.BackToFrontTicket.Kind.RECEPTION_FAILURE,
+ interfaces.Outcome.TRANSMISSION_FAILURE:
+ interfaces.BackToFrontTicket.Kind.TRANSMISSION_FAILURE,
+ interfaces.Outcome.SERVICED_FAILURE:
+ interfaces.BackToFrontTicket.Kind.SERVICED_FAILURE,
+ interfaces.Outcome.SERVICER_FAILURE:
+ interfaces.BackToFrontTicket.Kind.SERVICER_FAILURE,
+}
+
+
+class _Ticketizer(object):
+ """Common specification of different ticket-creating behavior."""
__metaclass__ = abc.ABCMeta
@abc.abstractmethod
- def packetize(self, operation_id, sequence_number, payload, complete):
- """Creates a packet indicating ordinary operation progress.
+ def ticketize(self, operation_id, sequence_number, payload, complete):
+ """Creates a ticket indicating ordinary operation progress.
Args:
operation_id: The operation ID for the current operation.
- sequence_number: A sequence number for the packet.
+ sequence_number: A sequence number for the ticket.
payload: A customer payload object. May be None if sequence_number is
zero or complete is true.
- complete: A boolean indicating whether or not the packet should describe
+ complete: A boolean indicating whether or not the ticket should describe
itself as (but for a later indication of operation abortion) the last
- packet to be sent.
+ ticket to be sent.
Returns:
An object of an appropriate type suitable for transmission to the other
@@ -72,24 +101,24 @@ class _Packetizer(object):
raise NotImplementedError()
@abc.abstractmethod
- def packetize_abortion(self, operation_id, sequence_number, kind):
- """Creates a packet indicating that the operation is aborted.
+ def ticketize_abortion(self, operation_id, sequence_number, outcome):
+ """Creates a ticket indicating that the operation is aborted.
Args:
operation_id: The operation ID for the current operation.
- sequence_number: A sequence number for the packet.
- kind: One of the values of packets.Kind indicating operational abortion.
+ sequence_number: A sequence number for the ticket.
+ outcome: An interfaces.Outcome value describing the operation abortion.
Returns:
An object of an appropriate type suitable for transmission to the other
side of the operation, or None if transmission is not appropriate for
- the given kind.
+ the given outcome.
"""
raise NotImplementedError()
-class _FrontPacketizer(_Packetizer):
- """Front-side packet-creating behavior."""
+class _FrontTicketizer(_Ticketizer):
+ """Front-side ticket-creating behavior."""
def __init__(self, name, subscription_kind, trace_id, timeout):
"""Constructor.
@@ -97,7 +126,7 @@ class _FrontPacketizer(_Packetizer):
Args:
name: The name of the operation.
subscription_kind: An interfaces.ServicedSubscription.Kind value
- describing the interest the front has in packets sent from the back.
+ describing the interest the front has in tickets sent from the back.
trace_id: A uuid.UUID identifying a set of related operations to which
this operation belongs.
timeout: A length of time in seconds to allow for the entire operation.
@@ -107,46 +136,54 @@ class _FrontPacketizer(_Packetizer):
self._trace_id = trace_id
self._timeout = timeout
- def packetize(self, operation_id, sequence_number, payload, complete):
- """See _Packetizer.packetize for specification."""
+ def ticketize(self, operation_id, sequence_number, payload, complete):
+ """See _Ticketizer.ticketize for specification."""
if sequence_number:
- return packets.FrontToBackPacket(
- operation_id, sequence_number,
- packets.Kind.COMPLETION if complete else packets.Kind.CONTINUATION,
- self._name, self._subscription_kind, self._trace_id, payload,
- self._timeout)
+ if complete:
+ kind = interfaces.FrontToBackTicket.Kind.COMPLETION
+ else:
+ kind = interfaces.FrontToBackTicket.Kind.CONTINUATION
+ return interfaces.FrontToBackTicket(
+ operation_id, sequence_number, kind, self._name,
+ self._subscription_kind, self._trace_id, payload, self._timeout)
else:
- return packets.FrontToBackPacket(
- operation_id, 0,
- packets.Kind.ENTIRE if complete else packets.Kind.COMMENCEMENT,
- self._name, self._subscription_kind, self._trace_id, payload,
- self._timeout)
-
- def packetize_abortion(self, operation_id, sequence_number, kind):
- """See _Packetizer.packetize_abortion for specification."""
- if kind in _FRONT_TO_BACK_NO_TRANSMISSION_KINDS:
+ if complete:
+ kind = interfaces.FrontToBackTicket.Kind.ENTIRE
+ else:
+ kind = interfaces.FrontToBackTicket.Kind.COMMENCEMENT
+ return interfaces.FrontToBackTicket(
+ operation_id, 0, kind, self._name, self._subscription_kind,
+ self._trace_id, payload, self._timeout)
+
+ def ticketize_abortion(self, operation_id, sequence_number, outcome):
+ """See _Ticketizer.ticketize_abortion for specification."""
+ if outcome in _FRONT_TO_BACK_NO_TRANSMISSION_OUTCOMES:
return None
else:
- return packets.FrontToBackPacket(
+ kind = _ABORTION_OUTCOME_TO_FRONT_TO_BACK_TICKET_KIND[outcome]
+ return interfaces.FrontToBackTicket(
operation_id, sequence_number, kind, None, None, None, None, None)
-class _BackPacketizer(_Packetizer):
- """Back-side packet-creating behavior."""
+class _BackTicketizer(_Ticketizer):
+ """Back-side ticket-creating behavior."""
- def packetize(self, operation_id, sequence_number, payload, complete):
- """See _Packetizer.packetize for specification."""
- return packets.BackToFrontPacket(
- operation_id, sequence_number,
- packets.Kind.COMPLETION if complete else packets.Kind.CONTINUATION,
- payload)
+ def ticketize(self, operation_id, sequence_number, payload, complete):
+ """See _Ticketizer.ticketize for specification."""
+ if complete:
+ kind = interfaces.BackToFrontTicket.Kind.COMPLETION
+ else:
+ kind = interfaces.BackToFrontTicket.Kind.CONTINUATION
+ return interfaces.BackToFrontTicket(
+ operation_id, sequence_number, kind, payload)
- def packetize_abortion(self, operation_id, sequence_number, kind):
- """See _Packetizer.packetize_abortion for specification."""
- if kind in _BACK_TO_FRONT_NO_TRANSMISSION_KINDS:
+ def ticketize_abortion(self, operation_id, sequence_number, outcome):
+ """See _Ticketizer.ticketize_abortion for specification."""
+ if outcome in _BACK_TO_FRONT_NO_TRANSMISSION_OUTCOMES:
return None
else:
- return packets.BackToFrontPacket(
+ kind = _ABORTION_OUTCOME_TO_BACK_TO_FRONT_TICKET_KIND[outcome]
+ return interfaces.BackToFrontTicket(
operation_id, sequence_number, kind, None)
@@ -178,26 +215,26 @@ class _EmptyTransmissionManager(TransmissionManager):
def inmit(self, emission, complete):
"""See _interfaces.TransmissionManager.inmit for specification."""
- def abort(self, category):
+ def abort(self, outcome):
"""See _interfaces.TransmissionManager.abort for specification."""
class _TransmittingTransmissionManager(TransmissionManager):
- """A TransmissionManager implementation that sends packets."""
+ """A TransmissionManager implementation that sends tickets."""
def __init__(
- self, lock, pool, callback, operation_id, packetizer,
+ self, lock, pool, callback, operation_id, ticketizer,
termination_manager):
"""Constructor.
Args:
lock: The operation-servicing-wide lock object.
- pool: A thread pool in which the work of transmitting packets will be
+ pool: A thread pool in which the work of transmitting tickets will be
performed.
- callback: A callable that accepts packets and sends them to the other side
+ callback: A callable that accepts tickets and sends them to the other side
of the operation.
operation_id: The operation's ID.
- packetizer: A _Packetizer for packet creation.
+ ticketizer: A _Ticketizer for ticket creation.
termination_manager: The _interfaces.TerminationManager associated with
this operation.
"""
@@ -205,14 +242,14 @@ class _TransmittingTransmissionManager(TransmissionManager):
self._pool = pool
self._callback = callback
self._operation_id = operation_id
- self._packetizer = packetizer
+ self._ticketizer = ticketizer
self._termination_manager = termination_manager
self._ingestion_manager = None
self._expiration_manager = None
self._emissions = []
self._emission_complete = False
- self._kind = None
+ self._outcome = None
self._lowest_unused_sequence_number = 0
self._transmitting = False
@@ -222,8 +259,8 @@ class _TransmittingTransmissionManager(TransmissionManager):
self._ingestion_manager = ingestion_manager
self._expiration_manager = expiration_manager
- def _lead_packet(self, emission, complete):
- """Creates a packet suitable for leading off the transmission loop.
+ def _lead_ticket(self, emission, complete):
+ """Creates a ticket suitable for leading off the transmission loop.
Args:
emission: A customer payload object to be sent to the other side of the
@@ -232,70 +269,70 @@ class _TransmittingTransmissionManager(TransmissionManager):
the passed object.
Returns:
- A packet with which to lead off the transmission loop.
+ A ticket with which to lead off the transmission loop.
"""
sequence_number = self._lowest_unused_sequence_number
self._lowest_unused_sequence_number += 1
- return self._packetizer.packetize(
+ return self._ticketizer.ticketize(
self._operation_id, sequence_number, emission, complete)
- def _abortive_response_packet(self, kind):
- """Creates a packet indicating operation abortion.
+ def _abortive_response_ticket(self, outcome):
+ """Creates a ticket indicating operation abortion.
Args:
- kind: One of the values of packets.Kind indicating operational abortion.
+ outcome: An interfaces.Outcome value describing operation abortion.
Returns:
- A packet indicating operation abortion.
+ A ticket indicating operation abortion.
"""
- packet = self._packetizer.packetize_abortion(
- self._operation_id, self._lowest_unused_sequence_number, kind)
- if packet is None:
+ ticket = self._ticketizer.ticketize_abortion(
+ self._operation_id, self._lowest_unused_sequence_number, outcome)
+ if ticket is None:
return None
else:
self._lowest_unused_sequence_number += 1
- return packet
+ return ticket
- def _next_packet(self):
- """Creates the next packet to be sent to the other side of the operation.
+ def _next_ticket(self):
+ """Creates the next ticket to be sent to the other side of the operation.
Returns:
- A (completed, packet) tuple comprised of a boolean indicating whether or
- not the sequence of packets has completed normally and a packet to send
- to the other side if the sequence of packets hasn't completed. The tuple
+ A (completed, ticket) tuple comprised of a boolean indicating whether or
+ not the sequence of tickets has completed normally and a ticket to send
+ to the other side if the sequence of tickets hasn't completed. The tuple
will never have both a True first element and a non-None second element.
"""
if self._emissions is None:
return False, None
- elif self._kind is None:
+ elif self._outcome is None:
if self._emissions:
payload = self._emissions.pop(0)
complete = self._emission_complete and not self._emissions
sequence_number = self._lowest_unused_sequence_number
self._lowest_unused_sequence_number += 1
- return complete, self._packetizer.packetize(
+ return complete, self._ticketizer.ticketize(
self._operation_id, sequence_number, payload, complete)
else:
return self._emission_complete, None
else:
- packet = self._abortive_response_packet(self._kind)
+ ticket = self._abortive_response_ticket(self._outcome)
self._emissions = None
- return False, None if packet is None else packet
+ return False, None if ticket is None else ticket
- def _transmit(self, packet):
- """Commences the transmission loop sending packets.
+ def _transmit(self, ticket):
+ """Commences the transmission loop sending tickets.
Args:
- packet: A packet to be sent to the other side of the operation.
+ ticket: A ticket to be sent to the other side of the operation.
"""
- def transmit(packet):
+ def transmit(ticket):
while True:
transmission_outcome = callable_util.call_logging_exceptions(
- self._callback, _TRANSMISSION_EXCEPTION_LOG_MESSAGE, packet)
+ self._callback, _TRANSMISSION_EXCEPTION_LOG_MESSAGE, ticket)
if transmission_outcome.exception is None:
with self._lock:
- complete, packet = self._next_packet()
- if packet is None:
+ complete, ticket = self._next_ticket()
+ if ticket is None:
if complete:
self._termination_manager.transmission_complete()
self._transmitting = False
@@ -303,34 +340,35 @@ class _TransmittingTransmissionManager(TransmissionManager):
else:
with self._lock:
self._emissions = None
- self._termination_manager.abort(packets.Kind.TRANSMISSION_FAILURE)
+ self._termination_manager.abort(
+ interfaces.Outcome.TRANSMISSION_FAILURE)
self._ingestion_manager.abort()
self._expiration_manager.abort()
self._transmitting = False
return
self._pool.submit(callable_util.with_exceptions_logged(
- transmit, _constants.INTERNAL_ERROR_LOG_MESSAGE), packet)
+ transmit, _constants.INTERNAL_ERROR_LOG_MESSAGE), ticket)
self._transmitting = True
def inmit(self, emission, complete):
"""See _interfaces.TransmissionManager.inmit for specification."""
- if self._emissions is not None and self._kind is None:
+ if self._emissions is not None and self._outcome is None:
self._emission_complete = complete
if self._transmitting:
self._emissions.append(emission)
else:
- self._transmit(self._lead_packet(emission, complete))
+ self._transmit(self._lead_ticket(emission, complete))
- def abort(self, kind):
+ def abort(self, outcome):
"""See _interfaces.TransmissionManager.abort for specification."""
- if self._emissions is not None and self._kind is None:
- self._kind = kind
+ if self._emissions is not None and self._outcome is None:
+ self._outcome = outcome
if not self._transmitting:
- packet = self._abortive_response_packet(kind)
+ ticket = self._abortive_response_ticket(outcome)
self._emissions = None
- if packet is not None:
- self._transmit(packet)
+ if ticket is not None:
+ self._transmit(ticket)
def front_transmission_manager(
@@ -340,14 +378,14 @@ def front_transmission_manager(
Args:
lock: The operation-servicing-wide lock object.
- pool: A thread pool in which the work of transmitting packets will be
+ pool: A thread pool in which the work of transmitting tickets will be
performed.
- callback: A callable that accepts packets and sends them to the other side
+ callback: A callable that accepts tickets and sends them to the other side
of the operation.
operation_id: The operation's ID.
name: The name of the operation.
subscription_kind: An interfaces.ServicedSubscription.Kind value
- describing the interest the front has in packets sent from the back.
+ describing the interest the front has in tickets sent from the back.
trace_id: A uuid.UUID identifying a set of related operations to which
this operation belongs.
timeout: A length of time in seconds to allow for the entire operation.
@@ -358,7 +396,7 @@ def front_transmission_manager(
A TransmissionManager appropriate for front-side use.
"""
return _TransmittingTransmissionManager(
- lock, pool, callback, operation_id, _FrontPacketizer(
+ lock, pool, callback, operation_id, _FrontTicketizer(
name, subscription_kind, trace_id, timeout),
termination_manager)
@@ -370,15 +408,15 @@ def back_transmission_manager(
Args:
lock: The operation-servicing-wide lock object.
- pool: A thread pool in which the work of transmitting packets will be
+ pool: A thread pool in which the work of transmitting tickets will be
performed.
- callback: A callable that accepts packets and sends them to the other side
+ callback: A callable that accepts tickets and sends them to the other side
of the operation.
operation_id: The operation's ID.
termination_manager: The _interfaces.TerminationManager associated with
this operation.
subscription_kind: An interfaces.ServicedSubscription.Kind value
- describing the interest the front has in packets sent from the back.
+ describing the interest the front has in tickets sent from the back.
Returns:
A TransmissionManager appropriate for back-side use.
@@ -387,5 +425,5 @@ def back_transmission_manager(
return _EmptyTransmissionManager()
else:
return _TransmittingTransmissionManager(
- lock, pool, callback, operation_id, _BackPacketizer(),
+ lock, pool, callback, operation_id, _BackTicketizer(),
termination_manager)
diff --git a/src/python/src/grpc/framework/base/packets/implementations.py b/src/python/src/grpc/framework/base/implementations.py
index 28688bcc0f..5656f9f981 100644
--- a/src/python/src/grpc/framework/base/packets/implementations.py
+++ b/src/python/src/grpc/framework/base/implementations.py
@@ -27,51 +27,51 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-"""Entry points into the packet-exchange-based implementation the base layer."""
+"""Entry points into the ticket-exchange-based base layer implementation."""
# interfaces is referenced from specification in this module.
-from grpc.framework.base.packets import _ends
-from grpc.framework.base.packets import interfaces # pylint: disable=unused-import
+from grpc.framework.base import _ends
+from grpc.framework.base import interfaces # pylint: disable=unused-import
-def front(work_pool, transmission_pool, utility_pool):
- """Factory function for creating interfaces.Fronts.
+def front_link(work_pool, transmission_pool, utility_pool):
+ """Factory function for creating interfaces.FrontLinks.
Args:
- work_pool: A thread pool to be used for doing work within the created Front
- object.
- transmission_pool: A thread pool to be used within the created Front object
- for transmitting values to some Back object.
- utility_pool: A thread pool to be used within the created Front object for
- utility tasks.
+ work_pool: A thread pool to be used for doing work within the created
+ FrontLink object.
+ transmission_pool: A thread pool to be used within the created FrontLink
+ object for transmitting values to a joined RearLink object.
+ utility_pool: A thread pool to be used within the created FrontLink object
+ for utility tasks.
Returns:
- An interfaces.Front.
+ An interfaces.FrontLink.
"""
- return _ends.Front(work_pool, transmission_pool, utility_pool)
+ return _ends.FrontLink(work_pool, transmission_pool, utility_pool)
-def back(
+def back_link(
servicer, work_pool, transmission_pool, utility_pool, default_timeout,
maximum_timeout):
- """Factory function for creating interfaces.Backs.
+ """Factory function for creating interfaces.BackLinks.
Args:
servicer: An interfaces.Servicer for servicing operations.
- work_pool: A thread pool to be used for doing work within the created Back
- object.
- transmission_pool: A thread pool to be used within the created Back object
- for transmitting values to some Front object.
- utility_pool: A thread pool to be used within the created Back object for
- utility tasks.
+ work_pool: A thread pool to be used for doing work within the created
+ BackLink object.
+ transmission_pool: A thread pool to be used within the created BackLink
+ object for transmitting values to a joined ForeLink object.
+ utility_pool: A thread pool to be used within the created BackLink object
+ for utility tasks.
default_timeout: A length of time in seconds to be used as the default
time alloted for a single operation.
maximum_timeout: A length of time in seconds to be used as the maximum
time alloted for a single operation.
Returns:
- An interfaces.Back.
+ An interfaces.BackLink.
"""
- return _ends.Back(
+ return _ends.BackLink(
servicer, work_pool, transmission_pool, utility_pool, default_timeout,
maximum_timeout)
diff --git a/src/python/src/grpc/framework/base/packets/implementations_test.py b/src/python/src/grpc/framework/base/implementations_test.py
index e5855700c7..11e49caf75 100644
--- a/src/python/src/grpc/framework/base/packets/implementations_test.py
+++ b/src/python/src/grpc/framework/base/implementations_test.py
@@ -27,13 +27,13 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-"""Tests for _framework.base.packets.implementations."""
+"""Tests for grpc.framework.base.implementations."""
import unittest
+from grpc.framework.base import implementations
from grpc.framework.base import interfaces_test_case
from grpc.framework.base import util
-from grpc.framework.base.packets import implementations
from grpc.framework.foundation import logging_pool
POOL_MAX_WORKERS = 100
@@ -54,10 +54,10 @@ class ImplementationsTest(
self.back_utility_pool = logging_pool.pool(POOL_MAX_WORKERS)
self.test_pool = logging_pool.pool(POOL_MAX_WORKERS)
self.test_servicer = interfaces_test_case.TestServicer(self.test_pool)
- self.front = implementations.front(
+ self.front = implementations.front_link(
self.front_work_pool, self.front_transmission_pool,
self.front_utility_pool)
- self.back = implementations.back(
+ self.back = implementations.back_link(
self.test_servicer, self.back_work_pool, self.back_transmission_pool,
self.back_utility_pool, DEFAULT_TIMEOUT, MAXIMUM_TIMEOUT)
self.front.join_rear_link(self.back)
diff --git a/src/python/src/grpc/framework/base/packets/in_memory.py b/src/python/src/grpc/framework/base/in_memory.py
index 453fd3b38a..c92d0bc663 100644
--- a/src/python/src/grpc/framework/base/packets/in_memory.py
+++ b/src/python/src/grpc/framework/base/in_memory.py
@@ -27,12 +27,12 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-"""Entry points into the packet-exchange-based implementation the base layer."""
+"""In-memory implementations of base layer interfaces."""
import threading
-from grpc.framework.base.packets import _constants
-from grpc.framework.base.packets import interfaces
+from grpc.framework.base import _constants
+from grpc.framework.base import interfaces
from grpc.framework.foundation import callable_util
diff --git a/src/python/src/grpc/framework/base/interfaces.py b/src/python/src/grpc/framework/base/interfaces.py
index ed43b253fe..e22c10d975 100644
--- a/src/python/src/grpc/framework/base/interfaces.py
+++ b/src/python/src/grpc/framework/base/interfaces.py
@@ -30,6 +30,7 @@
"""Interfaces defined and used by the base layer of RPC Framework."""
import abc
+import collections
import enum
# stream is referenced from specification in this module.
@@ -230,3 +231,133 @@ class Front(End):
class Back(End):
"""Serverish objects that perform the work of operations."""
__metaclass__ = abc.ABCMeta
+
+
+class FrontToBackTicket(
+ collections.namedtuple(
+ 'FrontToBackTicket',
+ ['operation_id', 'sequence_number', 'kind', 'name', 'subscription',
+ 'trace_id', 'payload', 'timeout'])):
+ """A sum type for all values sent from a front to a back.
+
+ Attributes:
+ operation_id: A unique-with-respect-to-equality hashable object identifying
+ a particular operation.
+ sequence_number: A zero-indexed integer sequence number identifying the
+ ticket's place among all the tickets sent from front to back for this
+ particular operation. Must be zero if kind is Kind.COMMENCEMENT or
+ Kind.ENTIRE. Must be positive for any other kind.
+ kind: A Kind value describing the overall kind of ticket.
+ name: The name of an operation. Must be present if kind is Kind.COMMENCEMENT
+ or Kind.ENTIRE. Must be None for any other kind.
+ subscription: An ServicedSubscription.Kind value describing the interest
+ the front has in tickets sent from the back. Must be present if
+ kind is Kind.COMMENCEMENT or Kind.ENTIRE. Must be None for any other kind.
+ trace_id: A uuid.UUID identifying a set of related operations to which this
+ operation belongs. May be None.
+ payload: A customer payload object. Must be present if kind is
+ Kind.CONTINUATION. Must be None if kind is Kind.CANCELLATION. May be None
+ for any other kind.
+ timeout: An optional length of time (measured from the beginning of the
+ operation) to allow for the entire operation. If None, a default value on
+ the back will be used. If present and excessively large, the back may
+ limit the operation to a smaller duration of its choice. May be present
+ for any ticket kind; setting a value on a later ticket allows fronts
+ to request time extensions (or even time reductions!) on in-progress
+ operations.
+ """
+
+ @enum.unique
+ class Kind(enum.Enum):
+ """Identifies the overall kind of a FrontToBackTicket."""
+
+ COMMENCEMENT = 'commencement'
+ CONTINUATION = 'continuation'
+ COMPLETION = 'completion'
+ ENTIRE = 'entire'
+ CANCELLATION = 'cancellation'
+ EXPIRATION = 'expiration'
+ SERVICER_FAILURE = 'servicer failure'
+ SERVICED_FAILURE = 'serviced failure'
+ RECEPTION_FAILURE = 'reception failure'
+ TRANSMISSION_FAILURE = 'transmission failure'
+
+
+class BackToFrontTicket(
+ collections.namedtuple(
+ 'BackToFrontTicket',
+ ['operation_id', 'sequence_number', 'kind', 'payload'])):
+ """A sum type for all values sent from a back to a front.
+
+ Attributes:
+ operation_id: A unique-with-respect-to-equality hashable object identifying
+ a particular operation.
+ sequence_number: A zero-indexed integer sequence number identifying the
+ ticket's place among all the tickets sent from back to front for this
+ particular operation.
+ kind: A Kind value describing the overall kind of ticket.
+ payload: A customer payload object. Must be present if kind is
+ Kind.CONTINUATION. May be None if kind is Kind.COMPLETION. Must be None
+ otherwise.
+ """
+
+ @enum.unique
+ class Kind(enum.Enum):
+ """Identifies the overall kind of a BackToFrontTicket."""
+
+ CONTINUATION = 'continuation'
+ COMPLETION = 'completion'
+ CANCELLATION = 'cancellation'
+ EXPIRATION = 'expiration'
+ SERVICER_FAILURE = 'servicer failure'
+ SERVICED_FAILURE = 'serviced failure'
+ RECEPTION_FAILURE = 'reception failure'
+ TRANSMISSION_FAILURE = 'transmission failure'
+
+
+class ForeLink(object):
+ """Accepts back-to-front tickets and emits front-to-back tickets."""
+ __metaclass__ = abc.ABCMeta
+
+ @abc.abstractmethod
+ def accept_back_to_front_ticket(self, ticket):
+ """Accept a BackToFrontTicket.
+
+ Args:
+ ticket: Any BackToFrontTicket.
+ """
+ raise NotImplementedError()
+
+ @abc.abstractmethod
+ def join_rear_link(self, rear_link):
+ """Mates this object with a peer with which it will exchange tickets."""
+ raise NotImplementedError()
+
+
+class RearLink(object):
+ """Accepts front-to-back tickets and emits back-to-front tickets."""
+ __metaclass__ = abc.ABCMeta
+
+ @abc.abstractmethod
+ def accept_front_to_back_ticket(self, ticket):
+ """Accepts a FrontToBackTicket.
+
+ Args:
+ ticket: Any FrontToBackTicket.
+ """
+ raise NotImplementedError()
+
+ @abc.abstractmethod
+ def join_fore_link(self, fore_link):
+ """Mates this object with a peer with which it will exchange tickets."""
+ raise NotImplementedError()
+
+
+class FrontLink(Front, ForeLink):
+ """Clientish objects that operate by sending and receiving tickets."""
+ __metaclass__ = abc.ABCMeta
+
+
+class BackLink(Back, RearLink):
+ """Serverish objects that operate by sending and receiving tickets."""
+ __metaclass__ = abc.ABCMeta
diff --git a/src/python/src/grpc/framework/base/interfaces_test_case.py b/src/python/src/grpc/framework/base/interfaces_test_case.py
index b86011c449..dec10c2924 100644
--- a/src/python/src/grpc/framework/base/interfaces_test_case.py
+++ b/src/python/src/grpc/framework/base/interfaces_test_case.py
@@ -164,7 +164,7 @@ class FrontAndBackTest(object):
# pylint: disable=invalid-name
def testSimplestCall(self):
- """Tests the absolute simplest call - a one-packet fire-and-forget."""
+ """Tests the absolute simplest call - a one-ticket fire-and-forget."""
self.front.operate(
SYNCHRONOUS_ECHO, None, True, SMALL_TIMEOUT,
util.none_serviced_subscription(), 'test trace ID')
@@ -175,25 +175,25 @@ class FrontAndBackTest(object):
# Assuming nothing really pathological (such as pauses on the order of
# SMALL_TIMEOUT interfering with this test) there are a two different ways
# the back could have experienced execution up to this point:
- # (1) The packet is still either in the front waiting to be transmitted
+ # (1) The ticket is still either in the front waiting to be transmitted
# or is somewhere on the link between the front and the back. The back has
# no idea that this test is even happening. Calling wait_for_idle on it
# would do no good because in this case the back is idle and the call would
- # return with the packet bound for it still in the front or on the link.
+ # return with the ticket bound for it still in the front or on the link.
back_operation_stats = self.back.operation_stats()
first_back_possibility = EMPTY_OUTCOME_DICT
- # (2) The packet arrived at the back and the back completed the operation.
+ # (2) The ticket arrived at the back and the back completed the operation.
second_back_possibility = dict(EMPTY_OUTCOME_DICT)
second_back_possibility[interfaces.Outcome.COMPLETED] = 1
self.assertIn(
back_operation_stats, (first_back_possibility, second_back_possibility))
- # It's true that if the packet had arrived at the back and the back had
+ # It's true that if the ticket had arrived at the back and the back had
# begun processing that wait_for_idle could hold test execution until the
# back completed the operation, but that doesn't really collapse the
# possibility space down to one solution.
def testEntireEcho(self):
- """Tests a very simple one-packet-each-way round-trip."""
+ """Tests a very simple one-ticket-each-way round-trip."""
test_payload = 'test payload'
test_consumer = stream_testing.TestConsumer()
subscription = util.full_serviced_subscription(
@@ -212,7 +212,7 @@ class FrontAndBackTest(object):
self.assertListEqual([(test_payload, True)], test_consumer.calls)
def testBidirectionalStreamingEcho(self):
- """Tests sending multiple packets each way."""
+ """Tests sending multiple tickets each way."""
test_payload_template = 'test_payload: %03d'
test_payloads = [test_payload_template % i for i in range(STREAM_LENGTH)]
test_consumer = stream_testing.TestConsumer()
@@ -255,16 +255,16 @@ class FrontAndBackTest(object):
# Assuming nothing really pathological (such as pauses on the order of
# SMALL_TIMEOUT interfering with this test) there are a two different ways
# the back could have experienced execution up to this point:
- # (1) Both packets are still either in the front waiting to be transmitted
+ # (1) Both tickets are still either in the front waiting to be transmitted
# or are somewhere on the link between the front and the back. The back has
# no idea that this test is even happening. Calling wait_for_idle on it
# would do no good because in this case the back is idle and the call would
- # return with the packets bound for it still in the front or on the link.
+ # return with the tickets bound for it still in the front or on the link.
back_operation_stats = self.back.operation_stats()
first_back_possibility = EMPTY_OUTCOME_DICT
- # (2) Both packets arrived within SMALL_TIMEOUT of one another at the back.
- # The back started processing based on the first packet and then stopped
- # upon receiving the cancellation packet.
+ # (2) Both tickets arrived within SMALL_TIMEOUT of one another at the back.
+ # The back started processing based on the first ticket and then stopped
+ # upon receiving the cancellation ticket.
second_back_possibility = dict(EMPTY_OUTCOME_DICT)
second_back_possibility[interfaces.Outcome.CANCELLED] = 1
self.assertIn(
diff --git a/src/python/src/grpc/framework/base/packets/null.py b/src/python/src/grpc/framework/base/null.py
index 5a2121243b..1e30d4557b 100644
--- a/src/python/src/grpc/framework/base/packets/null.py
+++ b/src/python/src/grpc/framework/base/null.py
@@ -29,7 +29,7 @@
"""Null links that ignore tickets passed to them."""
-from grpc.framework.base.packets import interfaces
+from grpc.framework.base import interfaces
class _NullForeLink(interfaces.ForeLink):
diff --git a/src/python/src/grpc/framework/base/packets/interfaces.py b/src/python/src/grpc/framework/base/packets/interfaces.py
deleted file mode 100644
index 7c48956ba5..0000000000
--- a/src/python/src/grpc/framework/base/packets/interfaces.py
+++ /dev/null
@@ -1,84 +0,0 @@
-# Copyright 2015, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-"""Interfaces defined and used by the base layer of RPC Framework."""
-
-import abc
-
-# packets is referenced from specifications in this module.
-from grpc.framework.base import interfaces
-from grpc.framework.base.packets import packets # pylint: disable=unused-import
-
-
-class ForeLink(object):
- """Accepts back-to-front tickets and emits front-to-back tickets."""
- __metaclass__ = abc.ABCMeta
-
- @abc.abstractmethod
- def accept_back_to_front_ticket(self, ticket):
- """Accept a packets.BackToFrontPacket.
-
- Args:
- ticket: Any packets.BackToFrontPacket.
- """
- raise NotImplementedError()
-
- @abc.abstractmethod
- def join_rear_link(self, rear_link):
- """Mates this object with a peer with which it will exchange tickets."""
- raise NotImplementedError()
-
-
-class RearLink(object):
- """Accepts front-to-back tickets and emits back-to-front tickets."""
- __metaclass__ = abc.ABCMeta
-
- @abc.abstractmethod
- def accept_front_to_back_ticket(self, ticket):
- """Accepts a packets.FrontToBackPacket.
-
- Args:
- ticket: Any packets.FrontToBackPacket.
- """
- raise NotImplementedError()
-
- @abc.abstractmethod
- def join_fore_link(self, fore_link):
- """Mates this object with a peer with which it will exchange tickets."""
- raise NotImplementedError()
-
-
-class Front(ForeLink, interfaces.Front):
- """Clientish objects that operate by sending and receiving tickets."""
- __metaclass__ = abc.ABCMeta
-
-
-class Back(RearLink, interfaces.Back):
- """Serverish objects that operate by sending and receiving tickets."""
- __metaclass__ = abc.ABCMeta
diff --git a/src/python/src/grpc/framework/base/packets/packets.py b/src/python/src/grpc/framework/base/packets/packets.py
deleted file mode 100644
index 9e2d4080b8..0000000000
--- a/src/python/src/grpc/framework/base/packets/packets.py
+++ /dev/null
@@ -1,111 +0,0 @@
-# Copyright 2015, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-"""Packets used between fronts and backs."""
-
-import collections
-import enum
-
-# interfaces is referenced from specifications in this module.
-from grpc.framework.base import interfaces # pylint: disable=unused-import
-
-
-@enum.unique
-class Kind(enum.Enum):
- """Identifies the overall kind of a ticket."""
-
- COMMENCEMENT = 'commencement'
- CONTINUATION = 'continuation'
- COMPLETION = 'completion'
- ENTIRE = 'entire'
- CANCELLATION = 'cancellation'
- EXPIRATION = 'expiration'
- SERVICER_FAILURE = 'servicer failure'
- SERVICED_FAILURE = 'serviced failure'
- RECEPTION_FAILURE = 'reception failure'
- TRANSMISSION_FAILURE = 'transmission failure'
-
-
-class FrontToBackPacket(
- collections.namedtuple(
- 'FrontToBackPacket',
- ['operation_id', 'sequence_number', 'kind', 'name', 'subscription',
- 'trace_id', 'payload', 'timeout'])):
- """A sum type for all values sent from a front to a back.
-
- Attributes:
- operation_id: A unique-with-respect-to-equality hashable object identifying
- a particular operation.
- sequence_number: A zero-indexed integer sequence number identifying the
- packet's place among all the packets sent from front to back for this
- particular operation. Must be zero if kind is Kind.COMMENCEMENT or
- Kind.ENTIRE. Must be positive for any other kind.
- kind: One of Kind.COMMENCEMENT, Kind.CONTINUATION, Kind.COMPLETION,
- Kind.ENTIRE, Kind.CANCELLATION, Kind.EXPIRATION, Kind.SERVICED_FAILURE,
- Kind.RECEPTION_FAILURE, or Kind.TRANSMISSION_FAILURE.
- name: The name of an operation. Must be present if kind is Kind.COMMENCEMENT
- or Kind.ENTIRE. Must be None for any other kind.
- subscription: An interfaces.ServicedSubscription.Kind value describing the
- interest the front has in packets sent from the back. Must be present if
- kind is Kind.COMMENCEMENT or Kind.ENTIRE. Must be None for any other kind.
- trace_id: A uuid.UUID identifying a set of related operations to which this
- operation belongs. May be None.
- payload: A customer payload object. Must be present if kind is
- Kind.CONTINUATION. Must be None if kind is Kind.CANCELLATION. May be None
- for any other kind.
- timeout: An optional length of time (measured from the beginning of the
- operation) to allow for the entire operation. If None, a default value on
- the back will be used. If present and excessively large, the back may
- limit the operation to a smaller duration of its choice. May be present
- for any ticket kind; setting a value on a later ticket allows fronts
- to request time extensions (or even time reductions!) on in-progress
- operations.
- """
-
-
-class BackToFrontPacket(
- collections.namedtuple(
- 'BackToFrontPacket',
- ['operation_id', 'sequence_number', 'kind', 'payload'])):
- """A sum type for all values sent from a back to a front.
-
- Attributes:
- operation_id: A unique-with-respect-to-equality hashable object identifying
- a particular operation.
- sequence_number: A zero-indexed integer sequence number identifying the
- packet's place among all the packets sent from back to front for this
- particular operation.
- kind: One of Kind.CONTINUATION, Kind.COMPLETION, Kind.EXPIRATION,
- Kind.SERVICER_FAILURE, Kind.RECEPTION_FAILURE, or
- Kind.TRANSMISSION_FAILURE.
- payload: A customer payload object. Must be present if kind is
- Kind.CONTINUATION. May be None if kind is Kind.COMPLETION. Must be None if
- kind is Kind.EXPIRATION, Kind.SERVICER_FAILURE, Kind.RECEPTION_FAILURE, or
- Kind.TRANSMISSION_FAILURE.
- """
diff --git a/src/python/src/grpc/framework/face/_service.py b/src/python/src/grpc/framework/face/_service.py
index 26bde12968..cdf413356a 100644
--- a/src/python/src/grpc/framework/face/_service.py
+++ b/src/python/src/grpc/framework/face/_service.py
@@ -105,15 +105,14 @@ def adapt_inline_value_in_value_out(method):
def adaptation(response_consumer, operation_context):
rpc_context = _control.RpcContext(operation_context)
return stream_util.TransformingConsumer(
- lambda request: method.service(request, rpc_context), response_consumer)
+ lambda request: method(request, rpc_context), response_consumer)
return adaptation
def adapt_inline_value_in_stream_out(method):
def adaptation(response_consumer, operation_context):
rpc_context = _control.RpcContext(operation_context)
- return _ValueInStreamOutConsumer(
- method.service, rpc_context, response_consumer)
+ return _ValueInStreamOutConsumer(method, rpc_context, response_consumer)
return adaptation
@@ -123,7 +122,7 @@ def adapt_inline_stream_in_value_out(method, pool):
operation_context.add_termination_callback(rendezvous.set_outcome)
def in_pool_thread():
response_consumer.consume_and_terminate(
- method.service(rendezvous, _control.RpcContext(operation_context)))
+ method(rendezvous, _control.RpcContext(operation_context)))
pool.submit(_pool_wrap(in_pool_thread, operation_context))
return rendezvous
return adaptation
@@ -149,7 +148,7 @@ def adapt_inline_stream_in_stream_out(method, pool):
operation_context.add_termination_callback(rendezvous.set_outcome)
def in_pool_thread():
_control.pipe_iterator_to_consumer(
- method.service(rendezvous, _control.RpcContext(operation_context)),
+ method(rendezvous, _control.RpcContext(operation_context)),
response_consumer, operation_context.is_active, True)
pool.submit(_pool_wrap(in_pool_thread, operation_context))
return rendezvous
@@ -159,7 +158,7 @@ def adapt_inline_stream_in_stream_out(method, pool):
def adapt_event_value_in_value_out(method):
def adaptation(response_consumer, operation_context):
def on_payload(payload):
- method.service(
+ method(
payload, response_consumer.consume_and_terminate,
_control.RpcContext(operation_context))
return _control.UnaryConsumer(on_payload)
@@ -169,7 +168,7 @@ def adapt_event_value_in_value_out(method):
def adapt_event_value_in_stream_out(method):
def adaptation(response_consumer, operation_context):
def on_payload(payload):
- method.service(
+ method(
payload, response_consumer, _control.RpcContext(operation_context))
return _control.UnaryConsumer(on_payload)
return adaptation
@@ -178,12 +177,11 @@ def adapt_event_value_in_stream_out(method):
def adapt_event_stream_in_value_out(method):
def adaptation(response_consumer, operation_context):
rpc_context = _control.RpcContext(operation_context)
- return method.service(response_consumer.consume_and_terminate, rpc_context)
+ return method(response_consumer.consume_and_terminate, rpc_context)
return adaptation
def adapt_event_stream_in_stream_out(method):
def adaptation(response_consumer, operation_context):
- return method.service(
- response_consumer, _control.RpcContext(operation_context))
+ return method(response_consumer, _control.RpcContext(operation_context))
return adaptation
diff --git a/src/python/src/grpc/framework/face/_test_case.py b/src/python/src/grpc/framework/face/_test_case.py
index a4e17c464c..b3a012db00 100644
--- a/src/python/src/grpc/framework/face/_test_case.py
+++ b/src/python/src/grpc/framework/face/_test_case.py
@@ -42,37 +42,17 @@ class FaceTestCase(test_case.FaceTestCase):
"""Provides abstract Face-layer tests an in-memory implementation."""
def set_up_implementation(
- self,
- name,
- methods,
- inline_value_in_value_out_methods,
- inline_value_in_stream_out_methods,
- inline_stream_in_value_out_methods,
- inline_stream_in_stream_out_methods,
- event_value_in_value_out_methods,
- event_value_in_stream_out_methods,
- event_stream_in_value_out_methods,
- event_stream_in_stream_out_methods,
- multi_method):
+ self, name, methods, method_implementations,
+ multi_method_implementation):
servicer_pool = logging_pool.pool(_MAXIMUM_POOL_SIZE)
stub_pool = logging_pool.pool(_MAXIMUM_POOL_SIZE)
servicer = implementations.servicer(
- servicer_pool,
- inline_value_in_value_out_methods=inline_value_in_value_out_methods,
- inline_value_in_stream_out_methods=inline_value_in_stream_out_methods,
- inline_stream_in_value_out_methods=inline_stream_in_value_out_methods,
- inline_stream_in_stream_out_methods=inline_stream_in_stream_out_methods,
- event_value_in_value_out_methods=event_value_in_value_out_methods,
- event_value_in_stream_out_methods=event_value_in_stream_out_methods,
- event_stream_in_value_out_methods=event_stream_in_value_out_methods,
- event_stream_in_stream_out_methods=event_stream_in_stream_out_methods,
- multi_method=multi_method)
+ servicer_pool, method_implementations, multi_method_implementation)
linked_pair = base_util.linked_pair(servicer, _TIMEOUT)
- server = implementations.server()
- stub = implementations.stub(linked_pair.front, stub_pool)
- return server, stub, (servicer_pool, stub_pool, linked_pair)
+ stub = implementations.generic_stub(linked_pair.front, stub_pool)
+ return stub, (servicer_pool, stub_pool, linked_pair)
def tear_down_implementation(self, memo):
servicer_pool, stub_pool, linked_pair = memo
diff --git a/src/python/src/grpc/framework/face/demonstration.py b/src/python/src/grpc/framework/face/demonstration.py
index d922f6e5ef..eabeac4569 100644
--- a/src/python/src/grpc/framework/face/demonstration.py
+++ b/src/python/src/grpc/framework/face/demonstration.py
@@ -30,7 +30,7 @@
"""Demonstration-suitable implementation of the face layer of RPC Framework."""
from grpc.framework.base import util as _base_util
-from grpc.framework.base.packets import implementations as _tickets_implementations
+from grpc.framework.base import implementations as _base_implementations
from grpc.framework.face import implementations
from grpc.framework.foundation import logging_pool
@@ -105,9 +105,9 @@ def server_and_stub(
event_stream_in_stream_out_methods=event_stream_in_stream_out_methods,
multi_method=multi_method)
- front = _tickets_implementations.front(
+ front = _base_implementations.front_link(
front_work_pool, front_transmission_pool, front_utility_pool)
- back = _tickets_implementations.back(
+ back = _base_implementations.back_link(
servicer, back_work_pool, back_transmission_pool, back_utility_pool,
default_timeout, _MAXIMUM_TIMEOUT)
front.join_rear_link(back)
diff --git a/src/python/src/grpc/framework/face/implementations.py b/src/python/src/grpc/framework/face/implementations.py
index 86948b386f..4a6de52974 100644
--- a/src/python/src/grpc/framework/face/implementations.py
+++ b/src/python/src/grpc/framework/face/implementations.py
@@ -29,6 +29,8 @@
"""Entry points into the Face layer of RPC Framework."""
+from grpc.framework.common import cardinality
+from grpc.framework.common import style
from grpc.framework.base import exceptions as _base_exceptions
from grpc.framework.base import interfaces as base_interfaces
from grpc.framework.face import _calls
@@ -56,7 +58,7 @@ class _BaseServicer(base_interfaces.Servicer):
raise _base_exceptions.NoSuchMethodError()
-class _UnaryUnarySyncAsync(interfaces.UnaryUnarySyncAsync):
+class _UnaryUnaryMultiCallable(interfaces.UnaryUnaryMultiCallable):
def __init__(self, front, name):
self._front = front
@@ -66,12 +68,33 @@ class _UnaryUnarySyncAsync(interfaces.UnaryUnarySyncAsync):
return _calls.blocking_value_in_value_out(
self._front, self._name, request, timeout, 'unused trace ID')
- def async(self, request, timeout):
+ def future(self, request, timeout):
return _calls.future_value_in_value_out(
self._front, self._name, request, timeout, 'unused trace ID')
+ def event(self, request, response_callback, abortion_callback, timeout):
+ return _calls.event_value_in_value_out(
+ self._front, self._name, request, response_callback, abortion_callback,
+ timeout, 'unused trace ID')
+
+
+class _UnaryStreamMultiCallable(interfaces.UnaryStreamMultiCallable):
+
+ def __init__(self, front, name):
+ self._front = front
+ self._name = name
-class _StreamUnarySyncAsync(interfaces.StreamUnarySyncAsync):
+ def __call__(self, request, timeout):
+ return _calls.inline_value_in_stream_out(
+ self._front, self._name, request, timeout, 'unused trace ID')
+
+ def event(self, request, response_consumer, abortion_callback, timeout):
+ return _calls.event_value_in_stream_out(
+ self._front, self._name, request, response_consumer, abortion_callback,
+ timeout, 'unused trace ID')
+
+
+class _StreamUnaryMultiCallable(interfaces.StreamUnaryMultiCallable):
def __init__(self, front, name, pool):
self._front = front
@@ -82,18 +105,37 @@ class _StreamUnarySyncAsync(interfaces.StreamUnarySyncAsync):
return _calls.blocking_stream_in_value_out(
self._front, self._name, request_iterator, timeout, 'unused trace ID')
- def async(self, request_iterator, timeout):
+ def future(self, request_iterator, timeout):
return _calls.future_stream_in_value_out(
self._front, self._name, request_iterator, timeout, 'unused trace ID',
self._pool)
+ def event(self, response_callback, abortion_callback, timeout):
+ return _calls.event_stream_in_value_out(
+ self._front, self._name, response_callback, abortion_callback, timeout,
+ 'unused trace ID')
-class _Server(interfaces.Server):
- """An interfaces.Server implementation."""
+class _StreamStreamMultiCallable(interfaces.StreamStreamMultiCallable):
-class _Stub(interfaces.Stub):
- """An interfaces.Stub implementation."""
+ def __init__(self, front, name, pool):
+ self._front = front
+ self._name = name
+ self._pool = pool
+
+ def __call__(self, request_iterator, timeout):
+ return _calls.inline_stream_in_stream_out(
+ self._front, self._name, request_iterator, timeout, 'unused trace ID',
+ self._pool)
+
+ def event(self, response_consumer, abortion_callback, timeout):
+ return _calls.event_stream_in_stream_out(
+ self._front, self._name, response_consumer, abortion_callback, timeout,
+ 'unused trace ID')
+
+
+class _GenericStub(interfaces.GenericStub):
+ """An interfaces.GenericStub implementation."""
def __init__(self, front, pool):
self._front = front
@@ -149,136 +191,128 @@ class _Stub(interfaces.Stub):
self._front, name, response_consumer, abortion_callback, timeout,
'unused trace ID')
- def unary_unary_sync_async(self, name):
- return _UnaryUnarySyncAsync(self._front, name)
-
- def stream_unary_sync_async(self, name):
- return _StreamUnarySyncAsync(self._front, name, self._pool)
-
-
-def _aggregate_methods(
- pool,
- inline_value_in_value_out_methods,
- inline_value_in_stream_out_methods,
- inline_stream_in_value_out_methods,
- inline_stream_in_stream_out_methods,
- event_value_in_value_out_methods,
- event_value_in_stream_out_methods,
- event_stream_in_value_out_methods,
- event_stream_in_stream_out_methods):
- """Aggregates methods coded in according to different interfaces."""
- methods = {}
-
- def adapt_unpooled_methods(adapted_methods, unadapted_methods, adaptation):
- if unadapted_methods is not None:
- for name, unadapted_method in unadapted_methods.iteritems():
- adapted_methods[name] = adaptation(unadapted_method)
-
- def adapt_pooled_methods(adapted_methods, unadapted_methods, adaptation):
- if unadapted_methods is not None:
- for name, unadapted_method in unadapted_methods.iteritems():
- adapted_methods[name] = adaptation(unadapted_method, pool)
-
- adapt_unpooled_methods(
- methods, inline_value_in_value_out_methods,
- _service.adapt_inline_value_in_value_out)
- adapt_unpooled_methods(
- methods, inline_value_in_stream_out_methods,
- _service.adapt_inline_value_in_stream_out)
- adapt_pooled_methods(
- methods, inline_stream_in_value_out_methods,
- _service.adapt_inline_stream_in_value_out)
- adapt_pooled_methods(
- methods, inline_stream_in_stream_out_methods,
- _service.adapt_inline_stream_in_stream_out)
- adapt_unpooled_methods(
- methods, event_value_in_value_out_methods,
- _service.adapt_event_value_in_value_out)
- adapt_unpooled_methods(
- methods, event_value_in_stream_out_methods,
- _service.adapt_event_value_in_stream_out)
- adapt_unpooled_methods(
- methods, event_stream_in_value_out_methods,
- _service.adapt_event_stream_in_value_out)
- adapt_unpooled_methods(
- methods, event_stream_in_stream_out_methods,
- _service.adapt_event_stream_in_stream_out)
-
- return methods
-
-
-def servicer(
- pool,
- inline_value_in_value_out_methods=None,
- inline_value_in_stream_out_methods=None,
- inline_stream_in_value_out_methods=None,
- inline_stream_in_stream_out_methods=None,
- event_value_in_value_out_methods=None,
- event_value_in_stream_out_methods=None,
- event_stream_in_value_out_methods=None,
- event_stream_in_stream_out_methods=None,
- multi_method=None):
+ def unary_unary_multi_callable(self, name):
+ return _UnaryUnaryMultiCallable(self._front, name)
+
+ def unary_stream_multi_callable(self, name):
+ return _UnaryStreamMultiCallable(self._front, name)
+
+ def stream_unary_multi_callable(self, name):
+ return _StreamUnaryMultiCallable(self._front, name, self._pool)
+
+ def stream_stream_multi_callable(self, name):
+ return _StreamStreamMultiCallable(self._front, name, self._pool)
+
+
+class _DynamicStub(interfaces.DynamicStub):
+ """An interfaces.DynamicStub implementation."""
+
+ def __init__(self, cardinalities, front, pool):
+ self._cardinalities = cardinalities
+ self._front = front
+ self._pool = pool
+
+ def __getattr__(self, attr):
+ method_cardinality = self._cardinalities.get(attr)
+ if method_cardinality is cardinality.Cardinality.UNARY_UNARY:
+ return _UnaryUnaryMultiCallable(self._front, attr)
+ elif method_cardinality is cardinality.Cardinality.UNARY_STREAM:
+ return _UnaryStreamMultiCallable(self._front, attr)
+ elif method_cardinality is cardinality.Cardinality.STREAM_UNARY:
+ return _StreamUnaryMultiCallable(self._front, attr, self._pool)
+ elif method_cardinality is cardinality.Cardinality.STREAM_STREAM:
+ return _StreamStreamMultiCallable(self._front, attr, self._pool)
+ else:
+ raise AttributeError('_DynamicStub object has no attribute "%s"!' % attr)
+
+
+def _adapt_method_implementations(method_implementations, pool):
+ adapted_implementations = {}
+ for name, method_implementation in method_implementations.iteritems():
+ if method_implementation.style is style.Service.INLINE:
+ if method_implementation.cardinality is cardinality.Cardinality.UNARY_UNARY:
+ adapted_implementations[name] = _service.adapt_inline_value_in_value_out(
+ method_implementation.unary_unary_inline)
+ elif method_implementation.cardinality is cardinality.Cardinality.UNARY_STREAM:
+ adapted_implementations[name] = _service.adapt_inline_value_in_stream_out(
+ method_implementation.unary_stream_inline)
+ elif method_implementation.cardinality is cardinality.Cardinality.STREAM_UNARY:
+ adapted_implementations[name] = _service.adapt_inline_stream_in_value_out(
+ method_implementation.stream_unary_inline, pool)
+ elif method_implementation.cardinality is cardinality.Cardinality.STREAM_STREAM:
+ adapted_implementations[name] = _service.adapt_inline_stream_in_stream_out(
+ method_implementation.stream_stream_inline, pool)
+ elif method_implementation.style is style.Service.EVENT:
+ if method_implementation.cardinality is cardinality.Cardinality.UNARY_UNARY:
+ adapted_implementations[name] = _service.adapt_event_value_in_value_out(
+ method_implementation.unary_unary_event)
+ elif method_implementation.cardinality is cardinality.Cardinality.UNARY_STREAM:
+ adapted_implementations[name] = _service.adapt_event_value_in_stream_out(
+ method_implementation.unary_stream_event)
+ elif method_implementation.cardinality is cardinality.Cardinality.STREAM_UNARY:
+ adapted_implementations[name] = _service.adapt_event_stream_in_value_out(
+ method_implementation.stream_unary_event)
+ elif method_implementation.cardinality is cardinality.Cardinality.STREAM_STREAM:
+ adapted_implementations[name] = _service.adapt_event_stream_in_stream_out(
+ method_implementation.stream_stream_event)
+ return adapted_implementations
+
+
+def servicer(pool, method_implementations, multi_method_implementation):
"""Creates a base_interfaces.Servicer.
- The key sets of the passed dictionaries must be disjoint. It is guaranteed
- that any passed MultiMethod implementation will only be called to service an
- RPC if the RPC method name is not present in the key sets of the passed
- dictionaries.
+ It is guaranteed that any passed interfaces.MultiMethodImplementation will
+ only be called to service an RPC if there is no
+ interfaces.MethodImplementation for the RPC method in the passed
+ method_implementations dictionary.
Args:
pool: A thread pool.
- inline_value_in_value_out_methods: A dictionary mapping method names to
- interfaces.InlineValueInValueOutMethod implementations.
- inline_value_in_stream_out_methods: A dictionary mapping method names to
- interfaces.InlineValueInStreamOutMethod implementations.
- inline_stream_in_value_out_methods: A dictionary mapping method names to
- interfaces.InlineStreamInValueOutMethod implementations.
- inline_stream_in_stream_out_methods: A dictionary mapping method names to
- interfaces.InlineStreamInStreamOutMethod implementations.
- event_value_in_value_out_methods: A dictionary mapping method names to
- interfaces.EventValueInValueOutMethod implementations.
- event_value_in_stream_out_methods: A dictionary mapping method names to
- interfaces.EventValueInStreamOutMethod implementations.
- event_stream_in_value_out_methods: A dictionary mapping method names to
- interfaces.EventStreamInValueOutMethod implementations.
- event_stream_in_stream_out_methods: A dictionary mapping method names to
- interfaces.EventStreamInStreamOutMethod implementations.
- multi_method: An implementation of interfaces.MultiMethod.
+ method_implementations: A dictionary from RPC method name to
+ interfaces.MethodImplementation object to be used to service the named
+ RPC method.
+ multi_method_implementation: An interfaces.MultiMethodImplementation to be
+ used to service any RPCs not serviced by the
+ interfaces.MethodImplementations given in the method_implementations
+ dictionary, or None.
Returns:
A base_interfaces.Servicer that services RPCs via the given implementations.
"""
- methods = _aggregate_methods(
- pool,
- inline_value_in_value_out_methods,
- inline_value_in_stream_out_methods,
- inline_stream_in_value_out_methods,
- inline_stream_in_stream_out_methods,
- event_value_in_value_out_methods,
- event_value_in_stream_out_methods,
- event_stream_in_value_out_methods,
- event_stream_in_stream_out_methods)
+ adapted_implementations = _adapt_method_implementations(
+ method_implementations, pool)
+ return _BaseServicer(adapted_implementations, multi_method_implementation)
- return _BaseServicer(methods, multi_method)
+def generic_stub(front, pool):
+ """Creates an interfaces.GenericStub.
-def server():
- """Creates an interfaces.Server.
+ Args:
+ front: A base_interfaces.Front.
+ pool: A futures.ThreadPoolExecutor.
Returns:
- An interfaces.Server.
+ An interfaces.GenericStub that performs RPCs via the given
+ base_interfaces.Front.
"""
- return _Server()
+ return _GenericStub(front, pool)
-def stub(front, pool):
- """Creates an interfaces.Stub.
+def dynamic_stub(cardinalities, front, pool, prefix):
+ """Creates an interfaces.DynamicStub.
Args:
+ cardinalities: A dict from RPC method name to cardinality.Cardinality
+ value identifying the cardinality of every RPC method to be supported by
+ the created interfaces.DynamicStub.
front: A base_interfaces.Front.
pool: A futures.ThreadPoolExecutor.
+ prefix: A string to prepend when mapping requested attribute name to RPC
+ method name during attribute access on the created
+ interfaces.DynamicStub.
Returns:
- An interfaces.Stub that performs RPCs via the given base_interfaces.Front.
+ An interfaces.DynamicStub that performs RPCs via the given
+ base_interfaces.Front.
"""
- return _Stub(front, pool)
+ return _DynamicStub(cardinalities, front, pool)
diff --git a/src/python/src/grpc/framework/face/interfaces.py b/src/python/src/grpc/framework/face/interfaces.py
index 9e19106e6f..b7cc4c1169 100644
--- a/src/python/src/grpc/framework/face/interfaces.py
+++ b/src/python/src/grpc/framework/face/interfaces.py
@@ -32,11 +32,24 @@
import abc
import enum
-# exceptions, abandonment, and future are referenced from specification in this
-# module.
+# cardinality, style, exceptions, abandonment, future, and stream are
+# referenced from specification in this module.
+from grpc.framework.common import cardinality # pylint: disable=unused-import
+from grpc.framework.common import style # pylint: disable=unused-import
from grpc.framework.face import exceptions # pylint: disable=unused-import
from grpc.framework.foundation import abandonment # pylint: disable=unused-import
from grpc.framework.foundation import future # pylint: disable=unused-import
+from grpc.framework.foundation import stream # pylint: disable=unused-import
+
+
+@enum.unique
+class Abortion(enum.Enum):
+ """Categories of RPC abortion."""
+ CANCELLED = 'cancelled'
+ EXPIRED = 'expired'
+ NETWORK_FAILURE = 'network failure'
+ SERVICED_FAILURE = 'serviced failure'
+ SERVICER_FAILURE = 'servicer failure'
class CancellableIterator(object):
@@ -59,69 +72,61 @@ class CancellableIterator(object):
raise NotImplementedError()
-class UnaryUnarySyncAsync(object):
- """Affords invoking a unary-unary RPC synchronously or asynchronously.
-
- Values implementing this interface are directly callable and present an
- "async" method. Both calls take a request value and a numeric timeout.
- Direct invocation of a value of this type invokes its associated RPC and
- blocks until the RPC's response is available. Calling the "async" method
- of a value of this type invokes its associated RPC and immediately returns a
- future.Future bound to the asynchronous execution of the RPC.
- """
+class RpcContext(object):
+ """Provides RPC-related information and action."""
__metaclass__ = abc.ABCMeta
@abc.abstractmethod
- def __call__(self, request, timeout):
- """Synchronously invokes the underlying RPC.
+ def is_active(self):
+ """Describes whether the RPC is active or has terminated."""
+ raise NotImplementedError()
- Args:
- request: The request value for the RPC.
- timeout: A duration of time in seconds to allow for the RPC.
+ @abc.abstractmethod
+ def time_remaining(self):
+ """Describes the length of allowed time remaining for the RPC.
Returns:
- The response value for the RPC.
-
- Raises:
- exceptions.RpcError: Indicating that the RPC was aborted.
+ A nonnegative float indicating the length of allowed time in seconds
+ remaining for the RPC to complete before it is considered to have timed
+ out.
"""
raise NotImplementedError()
@abc.abstractmethod
- def async(self, request, timeout):
- """Asynchronously invokes the underlying RPC.
+ def add_abortion_callback(self, abortion_callback):
+ """Registers a callback to be called if the RPC is aborted.
Args:
- request: The request value for the RPC.
- timeout: A duration of time in seconds to allow for the RPC.
-
- Returns:
- A future.Future representing the RPC. In the event of RPC completion, the
- returned Future's result value will be the response value of the RPC.
- In the event of RPC abortion, the returned Future's exception value
- will be an exceptions.RpcError.
+ abortion_callback: A callable to be called and passed an Abortion value
+ in the event of RPC abortion.
"""
raise NotImplementedError()
-class StreamUnarySyncAsync(object):
- """Affords invoking a stream-unary RPC synchronously or asynchronously.
+class Call(object):
+ """Invocation-side representation of an RPC.
- Values implementing this interface are directly callable and present an
- "async" method. Both calls take an iterator of request values and a numeric
- timeout. Direct invocation of a value of this type invokes its associated RPC
- and blocks until the RPC's response is available. Calling the "async" method
- of a value of this type invokes its associated RPC and immediately returns a
- future.Future bound to the asynchronous execution of the RPC.
+ Attributes:
+ context: An RpcContext affording information about the RPC.
"""
__metaclass__ = abc.ABCMeta
@abc.abstractmethod
- def __call__(self, request_iterator, timeout):
+ def cancel(self):
+ """Requests cancellation of the RPC."""
+ raise NotImplementedError()
+
+
+class UnaryUnaryMultiCallable(object):
+ """Affords invoking a unary-unary RPC in any call style."""
+ __metaclass__ = abc.ABCMeta
+
+ @abc.abstractmethod
+ def __call__(self, request, timeout):
"""Synchronously invokes the underlying RPC.
Args:
- request_iterator: An iterator that yields request values for the RPC.
+ request: The request value for the RPC.
timeout: A duration of time in seconds to allow for the RPC.
Returns:
@@ -133,11 +138,11 @@ class StreamUnarySyncAsync(object):
raise NotImplementedError()
@abc.abstractmethod
- def async(self, request, timeout):
+ def future(self, request, timeout):
"""Asynchronously invokes the underlying RPC.
Args:
- request_iterator: An iterator that yields request values for the RPC.
+ request: The request value for the RPC.
timeout: A duration of time in seconds to allow for the RPC.
Returns:
@@ -148,248 +153,204 @@ class StreamUnarySyncAsync(object):
"""
raise NotImplementedError()
-
-@enum.unique
-class Abortion(enum.Enum):
- """Categories of RPC abortion."""
-
- CANCELLED = 'cancelled'
- EXPIRED = 'expired'
- NETWORK_FAILURE = 'network failure'
- SERVICED_FAILURE = 'serviced failure'
- SERVICER_FAILURE = 'servicer failure'
-
-
-class RpcContext(object):
- """Provides RPC-related information and action."""
- __metaclass__ = abc.ABCMeta
-
- @abc.abstractmethod
- def is_active(self):
- """Describes whether the RPC is active or has terminated."""
- raise NotImplementedError()
-
- @abc.abstractmethod
- def time_remaining(self):
- """Describes the length of allowed time remaining for the RPC.
-
- Returns:
- A nonnegative float indicating the length of allowed time in seconds
- remaining for the RPC to complete before it is considered to have timed
- out.
- """
- raise NotImplementedError()
-
@abc.abstractmethod
- def add_abortion_callback(self, abortion_callback):
- """Registers a callback to be called if the RPC is aborted.
+ def event(self, request, response_callback, abortion_callback, timeout):
+ """Asynchronously invokes the underlying RPC.
Args:
- abortion_callback: A callable to be called and passed an Abortion value
+ request: The request value for the RPC.
+ response_callback: A callback to be called to accept the restponse value
+ of the RPC.
+ abortion_callback: A callback to be called and passed an Abortion value
in the event of RPC abortion.
- """
- raise NotImplementedError()
-
-
-class InlineValueInValueOutMethod(object):
- """A type for inline unary-request-unary-response RPC methods."""
- __metaclass__ = abc.ABCMeta
-
- @abc.abstractmethod
- def service(self, request, context):
- """Services an RPC that accepts one value and produces one value.
-
- Args:
- request: The single request value for the RPC.
- context: An RpcContext object.
+ timeout: A duration of time in seconds to allow for the RPC.
Returns:
- The single response value for the RPC.
-
- Raises:
- abandonment.Abandoned: If no response is necessary because the RPC has
- been aborted.
+ A Call object for the RPC.
"""
raise NotImplementedError()
-class InlineValueInStreamOutMethod(object):
- """A type for inline unary-request-stream-response RPC methods."""
+class UnaryStreamMultiCallable(object):
+ """Affords invoking a unary-stream RPC in any call style."""
__metaclass__ = abc.ABCMeta
@abc.abstractmethod
- def service(self, request, context):
- """Services an RPC that accepts one value and produces a stream of values.
+ def __call__(self, request, timeout):
+ """Synchronously invokes the underlying RPC.
Args:
- request: The single request value for the RPC.
- context: An RpcContext object.
-
- Yields:
- The values that comprise the response stream of the RPC.
+ request: The request value for the RPC.
+ timeout: A duration of time in seconds to allow for the RPC.
- Raises:
- abandonment.Abandoned: If completing the response stream is not necessary
- because the RPC has been aborted.
+ Returns:
+ A CancellableIterator that yields the response values of the RPC and
+ affords RPC cancellation. Drawing response values from the returned
+ CancellableIterator may raise exceptions.RpcError indicating abortion
+ of the RPC.
"""
raise NotImplementedError()
-
-class InlineStreamInValueOutMethod(object):
- """A type for inline stream-request-unary-response RPC methods."""
- __metaclass__ = abc.ABCMeta
-
@abc.abstractmethod
- def service(self, request_iterator, context):
- """Services an RPC that accepts a stream of values and produces one value.
+ def event(self, request, response_consumer, abortion_callback, timeout):
+ """Asynchronously invokes the underlying RPC.
Args:
- request_iterator: An iterator that yields the request values of the RPC.
- Drawing values from this iterator may also raise exceptions.RpcError to
- indicate abortion of the RPC.
- context: An RpcContext object.
-
- Yields:
- The values that comprise the response stream of the RPC.
+ request: The request value for the RPC.
+ response_consumer: A stream.Consumer to be called to accept the restponse
+ values of the RPC.
+ abortion_callback: A callback to be called and passed an Abortion value
+ in the event of RPC abortion.
+ timeout: A duration of time in seconds to allow for the RPC.
- Raises:
- abandonment.Abandoned: If no response is necessary because the RPC has
- been aborted.
- exceptions.RpcError: Implementations of this method must not deliberately
- raise exceptions.RpcError but may allow such errors raised by the
- request_iterator passed to them to propagate through their bodies
- uncaught.
+ Returns:
+ A Call object for the RPC.
"""
raise NotImplementedError()
-class InlineStreamInStreamOutMethod(object):
- """A type for inline stream-request-stream-response RPC methods."""
+class StreamUnaryMultiCallable(object):
+ """Affords invoking a stream-unary RPC in any call style."""
__metaclass__ = abc.ABCMeta
@abc.abstractmethod
- def service(self, request_iterator, context):
- """Services an RPC that accepts and produces streams of values.
+ def __call__(self, request_iterator, timeout):
+ """Synchronously invokes the underlying RPC.
Args:
- request_iterator: An iterator that yields the request values of the RPC.
- Drawing values from this iterator may also raise exceptions.RpcError to
- indicate abortion of the RPC.
- context: An RpcContext object.
+ request_iterator: An iterator that yields request values for the RPC.
+ timeout: A duration of time in seconds to allow for the RPC.
- Yields:
- The values that comprise the response stream of the RPC.
+ Returns:
+ The response value for the RPC.
Raises:
- abandonment.Abandoned: If completing the response stream is not necessary
- because the RPC has been aborted.
- exceptions.RpcError: Implementations of this method must not deliberately
- raise exceptions.RpcError but may allow such errors raised by the
- request_iterator passed to them to propagate through their bodies
- uncaught.
+ exceptions.RpcError: Indicating that the RPC was aborted.
"""
raise NotImplementedError()
-
-class EventValueInValueOutMethod(object):
- """A type for event-driven unary-request-unary-response RPC methods."""
- __metaclass__ = abc.ABCMeta
-
@abc.abstractmethod
- def service(self, request, response_callback, context):
- """Services an RPC that accepts one value and produces one value.
+ def future(self, request_iterator, timeout):
+ """Asynchronously invokes the underlying RPC.
Args:
- request: The single request value for the RPC.
- response_callback: A callback to be called to accept the response value of
- the RPC.
- context: An RpcContext object.
+ request_iterator: An iterator that yields request values for the RPC.
+ timeout: A duration of time in seconds to allow for the RPC.
- Raises:
- abandonment.Abandoned: May or may not be raised when the RPC has been
- aborted.
+ Returns:
+ A future.Future representing the RPC. In the event of RPC completion, the
+ returned Future's result value will be the response value of the RPC.
+ In the event of RPC abortion, the returned Future's exception value
+ will be an exceptions.RpcError.
"""
raise NotImplementedError()
-
-class EventValueInStreamOutMethod(object):
- """A type for event-driven unary-request-stream-response RPC methods."""
- __metaclass__ = abc.ABCMeta
-
@abc.abstractmethod
- def service(self, request, response_consumer, context):
- """Services an RPC that accepts one value and produces a stream of values.
+ def event(self, response_callback, abortion_callback, timeout):
+ """Asynchronously invokes the underlying RPC.
Args:
- request: The single request value for the RPC.
- response_consumer: A stream.Consumer to be called to accept the response
- values of the RPC.
- context: An RpcContext object.
+ request: The request value for the RPC.
+ response_callback: A callback to be called to accept the restponse value
+ of the RPC.
+ abortion_callback: A callback to be called and passed an Abortion value
+ in the event of RPC abortion.
+ timeout: A duration of time in seconds to allow for the RPC.
- Raises:
- abandonment.Abandoned: May or may not be raised when the RPC has been
- aborted.
+ Returns:
+ A pair of a Call object for the RPC and a stream.Consumer to which the
+ request values of the RPC should be passed.
"""
raise NotImplementedError()
-class EventStreamInValueOutMethod(object):
- """A type for event-driven stream-request-unary-response RPC methods."""
+class StreamStreamMultiCallable(object):
+ """Affords invoking a stream-stream RPC in any call style."""
__metaclass__ = abc.ABCMeta
@abc.abstractmethod
- def service(self, response_callback, context):
- """Services an RPC that accepts a stream of values and produces one value.
+ def __call__(self, request_iterator, timeout):
+ """Synchronously invokes the underlying RPC.
Args:
- response_callback: A callback to be called to accept the response value of
- the RPC.
- context: An RpcContext object.
+ request_iterator: An iterator that yields request values for the RPC.
+ timeout: A duration of time in seconds to allow for the RPC.
Returns:
- A stream.Consumer with which to accept the request values of the RPC. The
- consumer returned from this method may or may not be invoked to
- completion: in the case of RPC abortion, RPC Framework will simply stop
- passing values to this object. Implementations must not assume that this
- object will be called to completion of the request stream or even called
- at all.
-
- Raises:
- abandonment.Abandoned: May or may not be raised when the RPC has been
- aborted.
+ A CancellableIterator that yields the response values of the RPC and
+ affords RPC cancellation. Drawing response values from the returned
+ CancellableIterator may raise exceptions.RpcError indicating abortion
+ of the RPC.
"""
raise NotImplementedError()
-
-class EventStreamInStreamOutMethod(object):
- """A type for event-driven stream-request-stream-response RPC methods."""
- __metaclass__ = abc.ABCMeta
-
@abc.abstractmethod
- def service(self, response_consumer, context):
- """Services an RPC that accepts and produces streams of values.
+ def event(self, response_consumer, abortion_callback, timeout):
+ """Asynchronously invokes the underlying RPC.
- Args:
- response_consumer: A stream.Consumer to be called to accept the response
+l Args:
+ response_consumer: A stream.Consumer to be called to accept the restponse
values of the RPC.
- context: An RpcContext object.
+ abortion_callback: A callback to be called and passed an Abortion value
+ in the event of RPC abortion.
+ timeout: A duration of time in seconds to allow for the RPC.
Returns:
- A stream.Consumer with which to accept the request values of the RPC. The
- consumer returned from this method may or may not be invoked to
- completion: in the case of RPC abortion, RPC Framework will simply stop
- passing values to this object. Implementations must not assume that this
- object will be called to completion of the request stream or even called
- at all.
-
- Raises:
- abandonment.Abandoned: May or may not be raised when the RPC has been
- aborted.
+ A pair of a Call object for the RPC and a stream.Consumer to which the
+ request values of the RPC should be passed.
"""
raise NotImplementedError()
-class MultiMethod(object):
+class MethodImplementation(object):
+ """A sum type that describes an RPC method implementation.
+
+ Attributes:
+ cardinality: A cardinality.Cardinality value.
+ style: A style.Service value.
+ unary_unary_inline: The implementation of the RPC method as a callable
+ value that takes a request value and an RpcContext object and returns a
+ response value. Only non-None if cardinality is
+ cardinality.Cardinality.UNARY_UNARY and style is style.Service.INLINE.
+ unary_stream_inline: The implementation of the RPC method as a callable
+ value that takes a request value and an RpcContext object and returns an
+ iterator of response values. Only non-None if cardinality is
+ cardinality.Cardinality.UNARY_STREAM and style is style.Service.INLINE.
+ stream_unary_inline: The implementation of the RPC method as a callable
+ value that takes an iterator of request values and an RpcContext object
+ and returns a response value. Only non-None if cardinality is
+ cardinality.Cardinality.STREAM_UNARY and style is style.Service.INLINE.
+ stream_stream_inline: The implementation of the RPC method as a callable
+ value that takes an iterator of request values and an RpcContext object
+ and returns an iterator of response values. Only non-None if cardinality
+ is cardinality.Cardinality.STREAM_STREAM and style is
+ style.Service.INLINE.
+ unary_unary_event: The implementation of the RPC method as a callable value
+ that takes a request value, a response callback to which to pass the
+ response value of the RPC, and an RpcContext. Only non-None if
+ cardinality is cardinality.Cardinality.UNARY_UNARY and style is
+ style.Service.EVENT.
+ unary_stream_event: The implementation of the RPC method as a callable
+ value that takes a request value, a stream.Consumer to which to pass the
+ the response values of the RPC, and an RpcContext. Only non-None if
+ cardinality is cardinality.Cardinality.UNARY_STREAM and style is
+ style.Service.EVENT.
+ stream_unary_event: The implementation of the RPC method as a callable
+ value that takes a response callback to which to pass the response value
+ of the RPC and an RpcContext and returns a stream.Consumer to which the
+ request values of the RPC should be passed. Only non-None if cardinality
+ is cardinality.Cardinality.STREAM_UNARY and style is style.Service.EVENT.
+ stream_stream_event: The implementation of the RPC method as a callable
+ value that takes a stream.Consumer to which to pass the response values
+ of the RPC and an RpcContext and returns a stream.Consumer to which the
+ request values of the RPC should be passed. Only non-None if cardinality
+ is cardinality.Cardinality.STREAM_STREAM and style is
+ style.Service.EVENT.
+ """
+ __metaclass__ = abc.ABCMeta
+
+
+class MultiMethodImplementation(object):
"""A general type able to service many RPC methods."""
__metaclass__ = abc.ABCMeta
@@ -420,26 +381,7 @@ class MultiMethod(object):
raise NotImplementedError()
-class Server(object):
- """Specification of a running server that services RPCs."""
- __metaclass__ = abc.ABCMeta
-
-
-class Call(object):
- """Invocation-side representation of an RPC.
-
- Attributes:
- context: An RpcContext affording information about the RPC.
- """
- __metaclass__ = abc.ABCMeta
-
- @abc.abstractmethod
- def cancel(self):
- """Requests cancellation of the RPC."""
- raise NotImplementedError()
-
-
-class Stub(object):
+class GenericStub(object):
"""Affords RPC methods to callers."""
__metaclass__ = abc.ABCMeta
@@ -632,25 +574,67 @@ class Stub(object):
raise NotImplementedError()
@abc.abstractmethod
- def unary_unary_sync_async(self, name):
- """Creates a UnaryUnarySyncAsync value for a unary-unary RPC method.
+ def unary_unary_multi_callable(self, name):
+ """Creates a UnaryUnaryMultiCallable for a unary-unary RPC method.
+
+ Args:
+ name: The RPC method name.
+
+ Returns:
+ A UnaryUnaryMultiCallable value for the named unary-unary RPC method.
+ """
+ raise NotImplementedError()
+
+ @abc.abstractmethod
+ def unary_stream_multi_callable(self, name):
+ """Creates a UnaryStreamMultiCallable for a unary-stream RPC method.
Args:
name: The RPC method name.
Returns:
- A UnaryUnarySyncAsync value for the named unary-unary RPC method.
+ A UnaryStreamMultiCallable value for the name unary-stream RPC method.
"""
raise NotImplementedError()
@abc.abstractmethod
- def stream_unary_sync_async(self, name):
- """Creates a StreamUnarySyncAsync value for a stream-unary RPC method.
+ def stream_unary_multi_callable(self, name):
+ """Creates a StreamUnaryMultiCallable for a stream-unary RPC method.
Args:
name: The RPC method name.
Returns:
- A StreamUnarySyncAsync value for the named stream-unary RPC method.
+ A StreamUnaryMultiCallable value for the named stream-unary RPC method.
"""
raise NotImplementedError()
+
+ @abc.abstractmethod
+ def stream_stream_multi_callable(self, name):
+ """Creates a StreamStreamMultiCallable for a stream-stream RPC method.
+
+ Args:
+ name: The RPC method name.
+
+ Returns:
+ A StreamStreamMultiCallable value for the named stream-stream RPC method.
+ """
+ raise NotImplementedError()
+
+
+class DynamicStub(object):
+ """A stub with RPC-method-bound multi-callable attributes.
+
+ Instances of this type responsd to attribute access as follows: if the
+ requested attribute is the name of a unary-unary RPC method, the value of the
+ attribute will be a UnaryUnaryMultiCallable with which to invoke the RPC
+ method; if the requested attribute is the name of a unary-stream RPC method,
+ the value of the attribute will be a UnaryStreamMultiCallable with which to
+ invoke the RPC method; if the requested attribute is the name of a
+ stream-unary RPC method, the value of the attribute will be a
+ StreamUnaryMultiCallable with which to invoke the RPC method; and if the
+ requested attribute is the name of a stream-stream RPC method, the value of
+ the attribute will be a StreamStreamMultiCallable with which to invoke the
+ RPC method.
+ """
+ __metaclass__ = abc.ABCMeta
diff --git a/src/python/src/grpc/framework/face/testing/base_util.py b/src/python/src/grpc/framework/face/testing/base_util.py
index 7872a6b9e9..151d0ef793 100644
--- a/src/python/src/grpc/framework/face/testing/base_util.py
+++ b/src/python/src/grpc/framework/face/testing/base_util.py
@@ -33,9 +33,9 @@ import abc
# interfaces is referenced from specification in this module.
from grpc.framework.base import util as _base_util
-from grpc.framework.base.packets import implementations
-from grpc.framework.base.packets import in_memory
-from grpc.framework.base.packets import interfaces # pylint: disable=unused-import
+from grpc.framework.base import implementations
+from grpc.framework.base import in_memory
+from grpc.framework.base import interfaces # pylint: disable=unused-import
from grpc.framework.foundation import logging_pool
_POOL_SIZE_LIMIT = 20
@@ -89,9 +89,9 @@ def linked_pair(servicer, default_timeout):
back_work_pool, back_transmission_pool, back_utility_pool)
link = in_memory.Link(link_pool)
- front = implementations.front(
+ front = implementations.front_link(
front_work_pool, front_transmission_pool, front_utility_pool)
- back = implementations.back(
+ back = implementations.back_link(
servicer, back_work_pool, back_transmission_pool, back_utility_pool,
default_timeout, _MAXIMUM_TIMEOUT)
front.join_rear_link(link)
diff --git a/src/python/src/grpc/framework/face/testing/blocking_invocation_inline_service_test_case.py b/src/python/src/grpc/framework/face/testing/blocking_invocation_inline_service_test_case.py
index 233486f211..e57ee00104 100644
--- a/src/python/src/grpc/framework/face/testing/blocking_invocation_inline_service_test_case.py
+++ b/src/python/src/grpc/framework/face/testing/blocking_invocation_inline_service_test_case.py
@@ -61,13 +61,9 @@ class BlockingInvocationInlineServiceTestCase(
self.digest = digest.digest(
stock_service.STOCK_TEST_SERVICE, self.control, None)
- self.server, self.stub, self.memo = self.set_up_implementation(
+ self.stub, self.memo = self.set_up_implementation(
self.digest.name, self.digest.methods,
- self.digest.inline_unary_unary_methods,
- self.digest.inline_unary_stream_methods,
- self.digest.inline_stream_unary_methods,
- self.digest.inline_stream_stream_methods,
- {}, {}, {}, {}, None)
+ self.digest.inline_method_implementations, None)
def tearDown(self):
"""See unittest.TestCase.tearDown for full specification.
@@ -147,8 +143,8 @@ class BlockingInvocationInlineServiceTestCase(
with self.control.pause(), self.assertRaises(
exceptions.ExpirationError):
- sync_async = self.stub.unary_unary_sync_async(name)
- sync_async(request, _TIMEOUT)
+ multi_callable = self.stub.unary_unary_multi_callable(name)
+ multi_callable(request, _TIMEOUT)
def testExpiredUnaryRequestStreamResponse(self):
for name, test_messages_sequence in (
@@ -170,8 +166,8 @@ class BlockingInvocationInlineServiceTestCase(
with self.control.pause(), self.assertRaises(
exceptions.ExpirationError):
- sync_async = self.stub.stream_unary_sync_async(name)
- sync_async(iter(requests), _TIMEOUT)
+ multi_callable = self.stub.stream_unary_multi_callable(name)
+ multi_callable(iter(requests), _TIMEOUT)
def testExpiredStreamRequestStreamResponse(self):
for name, test_messages_sequence in (
diff --git a/src/python/src/grpc/framework/face/testing/digest.py b/src/python/src/grpc/framework/face/testing/digest.py
index b8fb573301..db8fcbb018 100644
--- a/src/python/src/grpc/framework/face/testing/digest.py
+++ b/src/python/src/grpc/framework/face/testing/digest.py
@@ -34,6 +34,8 @@ import threading
# testing_control, interfaces, and testing_service are referenced from
# specification in this module.
+from grpc.framework.common import cardinality
+from grpc.framework.common import style
from grpc.framework.face import exceptions
from grpc.framework.face import interfaces as face_interfaces
from grpc.framework.face.testing import control as testing_control # pylint: disable=unused-import
@@ -50,15 +52,9 @@ class TestServiceDigest(
'TestServiceDigest',
['name',
'methods',
- 'inline_unary_unary_methods',
- 'inline_unary_stream_methods',
- 'inline_stream_unary_methods',
- 'inline_stream_stream_methods',
- 'event_unary_unary_methods',
- 'event_unary_stream_methods',
- 'event_stream_unary_methods',
- 'event_stream_stream_methods',
- 'multi_method',
+ 'inline_method_implementations',
+ 'event_method_implementations',
+ 'multi_method_implementation',
'unary_unary_messages_sequences',
'unary_stream_messages_sequences',
'stream_unary_messages_sequences',
@@ -69,32 +65,14 @@ class TestServiceDigest(
name: The RPC service name to be used in the test.
methods: A sequence of interfaces.Method objects describing the RPC
methods that will be called during the test.
- inline_unary_unary_methods: A dict from method name to
- face_interfaces.InlineValueInValueOutMethod object to be used in tests of
+ inline_method_implementations: A dict from RPC method name to
+ face_interfaces.MethodImplementation object to be used in tests of
in-line calls to behaviors under test.
- inline_unary_stream_methods: A dict from method name to
- face_interfaces.InlineValueInStreamOutMethod object to be used in tests of
- in-line calls to behaviors under test.
- inline_stream_unary_methods: A dict from method name to
- face_interfaces.InlineStreamInValueOutMethod object to be used in tests of
- in-line calls to behaviors under test.
- inline_stream_stream_methods: A dict from method name to
- face_interfaces.InlineStreamInStreamOutMethod object to be used in tests
- of in-line calls to behaviors under test.
- event_unary_unary_methods: A dict from method name to
- face_interfaces.EventValueInValueOutMethod object to be used in tests of
- event-driven calls to behaviors under test.
- event_unary_stream_methods: A dict from method name to
- face_interfaces.EventValueInStreamOutMethod object to be used in tests of
- event-driven calls to behaviors under test.
- event_stream_unary_methods: A dict from method name to
- face_interfaces.EventStreamInValueOutMethod object to be used in tests of
+ event_method_implementations: A dict from RPC method name to
+ face_interfaces.MethodImplementation object to be used in tests of
event-driven calls to behaviors under test.
- event_stream_stream_methods: A dict from method name to
- face_interfaces.EventStreamInStreamOutMethod object to be used in tests of
- event-driven calls to behaviors under test.
- multi_method: A face_interfaces.MultiMethod to be used in tests of generic
- calls to behaviors under test.
+ multi_method_implementation: A face_interfaces.MultiMethodImplementation to
+ be used in tests of generic calls to behaviors under test.
unary_unary_messages_sequences: A dict from method name to sequence of
service.UnaryUnaryTestMessages objects to be used to test the method
with the given name.
@@ -130,27 +108,33 @@ class _BufferingConsumer(stream.Consumer):
self.terminated = True
-class _InlineUnaryUnaryMethod(face_interfaces.InlineValueInValueOutMethod):
+class _InlineUnaryUnaryMethod(face_interfaces.MethodImplementation):
def __init__(self, unary_unary_test_method, control):
self._test_method = unary_unary_test_method
self._control = control
- def service(self, request, context):
+ self.cardinality = cardinality.Cardinality.UNARY_UNARY
+ self.style = style.Service.INLINE
+
+ def unary_unary_inline(self, request, context):
response_list = []
self._test_method.service(
request, response_list.append, context, self._control)
return response_list.pop(0)
-class _EventUnaryUnaryMethod(face_interfaces.EventValueInValueOutMethod):
+class _EventUnaryUnaryMethod(face_interfaces.MethodImplementation):
def __init__(self, unary_unary_test_method, control, pool):
self._test_method = unary_unary_test_method
self._control = control
self._pool = pool
- def service(self, request, response_callback, context):
+ self.cardinality = cardinality.Cardinality.UNARY_UNARY
+ self.style = style.Service.EVENT
+
+ def unary_unary_event(self, request, response_callback, context):
if self._pool is None:
self._test_method.service(
request, response_callback, context, self._control)
@@ -160,13 +144,16 @@ class _EventUnaryUnaryMethod(face_interfaces.EventValueInValueOutMethod):
self._control)
-class _InlineUnaryStreamMethod(face_interfaces.InlineValueInStreamOutMethod):
+class _InlineUnaryStreamMethod(face_interfaces.MethodImplementation):
def __init__(self, unary_stream_test_method, control):
self._test_method = unary_stream_test_method
self._control = control
- def service(self, request, context):
+ self.cardinality = cardinality.Cardinality.UNARY_STREAM
+ self.style = style.Service.INLINE
+
+ def unary_stream_inline(self, request, context):
response_consumer = _BufferingConsumer()
self._test_method.service(
request, response_consumer, context, self._control)
@@ -174,14 +161,17 @@ class _InlineUnaryStreamMethod(face_interfaces.InlineValueInStreamOutMethod):
yield response
-class _EventUnaryStreamMethod(face_interfaces.EventValueInStreamOutMethod):
+class _EventUnaryStreamMethod(face_interfaces.MethodImplementation):
def __init__(self, unary_stream_test_method, control, pool):
self._test_method = unary_stream_test_method
self._control = control
self._pool = pool
- def service(self, request, response_consumer, context):
+ self.cardinality = cardinality.Cardinality.UNARY_STREAM
+ self.style = style.Service.EVENT
+
+ def unary_stream_event(self, request, response_consumer, context):
if self._pool is None:
self._test_method.service(
request, response_consumer, context, self._control)
@@ -191,13 +181,16 @@ class _EventUnaryStreamMethod(face_interfaces.EventValueInStreamOutMethod):
self._control)
-class _InlineStreamUnaryMethod(face_interfaces.InlineStreamInValueOutMethod):
+class _InlineStreamUnaryMethod(face_interfaces.MethodImplementation):
def __init__(self, stream_unary_test_method, control):
self._test_method = stream_unary_test_method
self._control = control
- def service(self, request_iterator, context):
+ self.cardinality = cardinality.Cardinality.STREAM_UNARY
+ self.style = style.Service.INLINE
+
+ def stream_unary_inline(self, request_iterator, context):
response_list = []
request_consumer = self._test_method.service(
response_list.append, context, self._control)
@@ -207,14 +200,17 @@ class _InlineStreamUnaryMethod(face_interfaces.InlineStreamInValueOutMethod):
return response_list.pop(0)
-class _EventStreamUnaryMethod(face_interfaces.EventStreamInValueOutMethod):
+class _EventStreamUnaryMethod(face_interfaces.MethodImplementation):
def __init__(self, stream_unary_test_method, control, pool):
self._test_method = stream_unary_test_method
self._control = control
self._pool = pool
- def service(self, response_callback, context):
+ self.cardinality = cardinality.Cardinality.STREAM_UNARY
+ self.style = style.Service.EVENT
+
+ def stream_unary_event(self, response_callback, context):
request_consumer = self._test_method.service(
response_callback, context, self._control)
if self._pool is None:
@@ -223,13 +219,16 @@ class _EventStreamUnaryMethod(face_interfaces.EventStreamInValueOutMethod):
return stream_util.ThreadSwitchingConsumer(request_consumer, self._pool)
-class _InlineStreamStreamMethod(face_interfaces.InlineStreamInStreamOutMethod):
+class _InlineStreamStreamMethod(face_interfaces.MethodImplementation):
def __init__(self, stream_stream_test_method, control):
self._test_method = stream_stream_test_method
self._control = control
- def service(self, request_iterator, context):
+ self.cardinality = cardinality.Cardinality.STREAM_STREAM
+ self.style = style.Service.INLINE
+
+ def stream_stream_inline(self, request_iterator, context):
response_consumer = _BufferingConsumer()
request_consumer = self._test_method.service(
response_consumer, context, self._control)
@@ -241,14 +240,17 @@ class _InlineStreamStreamMethod(face_interfaces.InlineStreamInStreamOutMethod):
response_consumer.terminate()
-class _EventStreamStreamMethod(face_interfaces.EventStreamInStreamOutMethod):
+class _EventStreamStreamMethod(face_interfaces.MethodImplementation):
def __init__(self, stream_stream_test_method, control, pool):
self._test_method = stream_stream_test_method
self._control = control
self._pool = pool
- def service(self, response_consumer, context):
+ self.cardinality = cardinality.Cardinality.STREAM_STREAM
+ self.style = style.Service.EVENT
+
+ def stream_stream_event(self, response_consumer, context):
request_consumer = self._test_method.service(
response_consumer, context, self._control)
if self._pool is None:
@@ -332,7 +334,7 @@ class _StreamUnaryAdaptation(object):
response_consumer.consume_and_terminate, context, control)
-class _MultiMethod(face_interfaces.MultiMethod):
+class _MultiMethodImplementation(face_interfaces.MultiMethodImplementation):
def __init__(self, methods, control, pool):
self._methods = methods
@@ -427,19 +429,21 @@ def digest(service, control, pool):
adaptations.update(unary_stream.adaptations)
adaptations.update(stream_unary.adaptations)
adaptations.update(stream_stream.adaptations)
+ inlines = dict(unary_unary.inlines)
+ inlines.update(unary_stream.inlines)
+ inlines.update(stream_unary.inlines)
+ inlines.update(stream_stream.inlines)
+ events = dict(unary_unary.events)
+ events.update(unary_stream.events)
+ events.update(stream_unary.events)
+ events.update(stream_stream.events)
return TestServiceDigest(
service.name(),
methods,
- unary_unary.inlines,
- unary_stream.inlines,
- stream_unary.inlines,
- stream_stream.inlines,
- unary_unary.events,
- unary_stream.events,
- stream_unary.events,
- stream_stream.events,
- _MultiMethod(adaptations, control, pool),
+ inlines,
+ events,
+ _MultiMethodImplementation(adaptations, control, pool),
unary_unary.messages,
unary_stream.messages,
stream_unary.messages,
diff --git a/src/python/src/grpc/framework/face/testing/event_invocation_synchronous_event_service_test_case.py b/src/python/src/grpc/framework/face/testing/event_invocation_synchronous_event_service_test_case.py
index 21e669b908..0f0b0e3d52 100644
--- a/src/python/src/grpc/framework/face/testing/event_invocation_synchronous_event_service_test_case.py
+++ b/src/python/src/grpc/framework/face/testing/event_invocation_synchronous_event_service_test_case.py
@@ -60,14 +60,9 @@ class EventInvocationSynchronousEventServiceTestCase(
self.digest = digest.digest(
stock_service.STOCK_TEST_SERVICE, self.control, None)
- self.server, self.stub, self.memo = self.set_up_implementation(
+ self.stub, self.memo = self.set_up_implementation(
self.digest.name, self.digest.methods,
- {}, {}, {}, {},
- self.digest.event_unary_unary_methods,
- self.digest.event_unary_stream_methods,
- self.digest.event_stream_unary_methods,
- self.digest.event_stream_stream_methods,
- None)
+ self.digest.event_method_implementations, None)
def tearDown(self):
"""See unittest.TestCase.tearDown for full specification.
diff --git a/src/python/src/grpc/framework/face/testing/future_invocation_asynchronous_event_service_test_case.py b/src/python/src/grpc/framework/face/testing/future_invocation_asynchronous_event_service_test_case.py
index c87846f2ef..0d51b64f1b 100644
--- a/src/python/src/grpc/framework/face/testing/future_invocation_asynchronous_event_service_test_case.py
+++ b/src/python/src/grpc/framework/face/testing/future_invocation_asynchronous_event_service_test_case.py
@@ -91,14 +91,9 @@ class FutureInvocationAsynchronousEventServiceTestCase(
self.digest = digest.digest(
stock_service.STOCK_TEST_SERVICE, self.control, self.digest_pool)
- self.server, self.stub, self.memo = self.set_up_implementation(
+ self.stub, self.memo = self.set_up_implementation(
self.digest.name, self.digest.methods,
- {}, {}, {}, {},
- self.digest.event_unary_unary_methods,
- self.digest.event_unary_stream_methods,
- self.digest.event_stream_unary_methods,
- self.digest.event_stream_stream_methods,
- None)
+ self.digest.event_method_implementations, None)
def tearDown(self):
"""See unittest.TestCase.tearDown for full specification.
@@ -190,8 +185,8 @@ class FutureInvocationAsynchronousEventServiceTestCase(
request = test_messages.request()
with self.control.pause():
- sync_async = self.stub.unary_unary_sync_async(name)
- response_future = sync_async.async(request, _TIMEOUT)
+ multi_callable = self.stub.unary_unary_multi_callable(name)
+ response_future = multi_callable.future(request, _TIMEOUT)
self.assertIsInstance(
response_future.exception(), exceptions.ExpirationError)
with self.assertRaises(exceptions.ExpirationError):
@@ -216,8 +211,8 @@ class FutureInvocationAsynchronousEventServiceTestCase(
requests = test_messages.requests()
with self.control.pause():
- sync_async = self.stub.stream_unary_sync_async(name)
- response_future = sync_async.async(iter(requests), _TIMEOUT)
+ multi_callable = self.stub.stream_unary_multi_callable(name)
+ response_future = multi_callable.future(iter(requests), _TIMEOUT)
self.assertIsInstance(
response_future.exception(), exceptions.ExpirationError)
with self.assertRaises(exceptions.ExpirationError):
diff --git a/src/python/src/grpc/framework/face/testing/service.py b/src/python/src/grpc/framework/face/testing/service.py
index a58e2ee42e..bf54d41d66 100644
--- a/src/python/src/grpc/framework/face/testing/service.py
+++ b/src/python/src/grpc/framework/face/testing/service.py
@@ -36,8 +36,8 @@ from grpc.framework.face import interfaces as face_interfaces # pylint: disable
from grpc.framework.face.testing import interfaces
-class UnaryUnaryTestMethod(interfaces.Method):
- """Like face_interfaces.EventValueInValueOutMethod but with a control."""
+class UnaryUnaryTestMethodImplementation(interfaces.Method):
+ """A controllable implementation of a unary-unary RPC method."""
__metaclass__ = abc.ABCMeta
@@ -93,8 +93,8 @@ class UnaryUnaryTestMessages(object):
raise NotImplementedError()
-class UnaryStreamTestMethod(interfaces.Method):
- """Like face_interfaces.EventValueInStreamOutMethod but with a control."""
+class UnaryStreamTestMethodImplementation(interfaces.Method):
+ """A controllable implementation of a unary-stream RPC method."""
__metaclass__ = abc.ABCMeta
@@ -106,7 +106,7 @@ class UnaryStreamTestMethod(interfaces.Method):
request: The single request message for the RPC.
response_consumer: A stream.Consumer to be called to accept the response
messages of the RPC.
- context: An RpcContext object.
+ context: A face_interfaces.RpcContext object.
control: A test_control.Control to control execution of this method.
Raises:
@@ -150,8 +150,8 @@ class UnaryStreamTestMessages(object):
raise NotImplementedError()
-class StreamUnaryTestMethod(interfaces.Method):
- """Like face_interfaces.EventStreamInValueOutMethod but with a control."""
+class StreamUnaryTestMethodImplementation(interfaces.Method):
+ """A controllable implementation of a stream-unary RPC method."""
__metaclass__ = abc.ABCMeta
@@ -162,7 +162,7 @@ class StreamUnaryTestMethod(interfaces.Method):
Args:
response_callback: A callback to be called to accept the response message
of the RPC.
- context: An RpcContext object.
+ context: A face_interfaces.RpcContext object.
control: A test_control.Control to control execution of this method.
Returns:
@@ -214,8 +214,8 @@ class StreamUnaryTestMessages(object):
raise NotImplementedError()
-class StreamStreamTestMethod(interfaces.Method):
- """Like face_interfaces.EventStreamInStreamOutMethod but with a control."""
+class StreamStreamTestMethodImplementation(interfaces.Method):
+ """A controllable implementation of a stream-stream RPC method."""
__metaclass__ = abc.ABCMeta
@@ -226,7 +226,7 @@ class StreamStreamTestMethod(interfaces.Method):
Args:
response_consumer: A stream.Consumer to be called to accept the response
messages of the RPC.
- context: An RpcContext object.
+ context: A face_interfaces.RpcContext object.
control: A test_control.Control to control execution of this method.
Returns:
@@ -298,8 +298,8 @@ class TestService(object):
Returns:
A dict from method name to pair. The first element of the pair
- is a UnaryUnaryTestMethod object and the second element is a sequence
- of UnaryUnaryTestMethodMessages objects.
+ is a UnaryUnaryTestMethodImplementation object and the second element
+ is a sequence of UnaryUnaryTestMethodMessages objects.
"""
raise NotImplementedError()
@@ -309,8 +309,8 @@ class TestService(object):
Returns:
A dict from method name to pair. The first element of the pair is a
- UnaryStreamTestMethod object and the second element is a sequence of
- UnaryStreamTestMethodMessages objects.
+ UnaryStreamTestMethodImplementation object and the second element is a
+ sequence of UnaryStreamTestMethodMessages objects.
"""
raise NotImplementedError()
@@ -320,8 +320,8 @@ class TestService(object):
Returns:
A dict from method name to pair. The first element of the pair is a
- StreamUnaryTestMethod object and the second element is a sequence of
- StreamUnaryTestMethodMessages objects.
+ StreamUnaryTestMethodImplementation object and the second element is a
+ sequence of StreamUnaryTestMethodMessages objects.
"""
raise NotImplementedError()
@@ -331,7 +331,7 @@ class TestService(object):
Returns:
A dict from method name to pair. The first element of the pair is a
- StreamStreamTestMethod object and the second element is a sequence of
- StreamStreamTestMethodMessages objects.
+ StreamStreamTestMethodImplementation object and the second element is a
+ sequence of StreamStreamTestMethodMessages objects.
"""
raise NotImplementedError()
diff --git a/src/python/src/grpc/framework/face/testing/stock_service.py b/src/python/src/grpc/framework/face/testing/stock_service.py
index 83c9418b07..61aaf444a0 100644
--- a/src/python/src/grpc/framework/face/testing/stock_service.py
+++ b/src/python/src/grpc/framework/face/testing/stock_service.py
@@ -139,7 +139,7 @@ def _get_highest_trade_price(stock_reply_callback, control, active):
return StockRequestConsumer()
-class GetLastTradePrice(service.UnaryUnaryTestMethod):
+class GetLastTradePrice(service.UnaryUnaryTestMethodImplementation):
"""GetLastTradePrice for use in tests."""
def name(self):
@@ -186,7 +186,7 @@ class GetLastTradePriceMessages(service.UnaryUnaryTestMessages):
test_case.assertEqual(_price(request.symbol), response.price)
-class GetLastTradePriceMultiple(service.StreamStreamTestMethod):
+class GetLastTradePriceMultiple(service.StreamStreamTestMethodImplementation):
"""GetLastTradePriceMultiple for use in tests."""
def name(self):
@@ -238,7 +238,7 @@ class GetLastTradePriceMultipleMessages(service.StreamStreamTestMessages):
test_case.assertEqual(_price(stock_request.symbol), stock_reply.price)
-class WatchFutureTrades(service.UnaryStreamTestMethod):
+class WatchFutureTrades(service.UnaryStreamTestMethodImplementation):
"""WatchFutureTrades for use in tests."""
def name(self):
@@ -288,7 +288,7 @@ class WatchFutureTradesMessages(service.UnaryStreamTestMessages):
test_case.assertEqual(base_price + index, response.price)
-class GetHighestTradePrice(service.StreamUnaryTestMethod):
+class GetHighestTradePrice(service.StreamUnaryTestMethodImplementation):
"""GetHighestTradePrice for use in tests."""
def name(self):
diff --git a/src/python/src/grpc/framework/face/testing/test_case.py b/src/python/src/grpc/framework/face/testing/test_case.py
index 218a2a8549..e60e3d1d40 100644
--- a/src/python/src/grpc/framework/face/testing/test_case.py
+++ b/src/python/src/grpc/framework/face/testing/test_case.py
@@ -46,55 +46,24 @@ class FaceTestCase(object):
@abc.abstractmethod
def set_up_implementation(
- self,
- name,
- methods,
- inline_value_in_value_out_methods,
- inline_value_in_stream_out_methods,
- inline_stream_in_value_out_methods,
- inline_stream_in_stream_out_methods,
- event_value_in_value_out_methods,
- event_value_in_stream_out_methods,
- event_stream_in_value_out_methods,
- event_stream_in_stream_out_methods,
- multi_method):
+ self, name, methods, method_implementations,
+ multi_method_implementation):
"""Instantiates the Face Layer implementation under test.
Args:
name: The service name to be used in the test.
methods: A sequence of interfaces.Method objects describing the RPC
methods that will be called during the test.
- inline_value_in_value_out_methods: A dictionary from string method names
- to face_interfaces.InlineValueInValueOutMethod implementations of those
- methods.
- inline_value_in_stream_out_methods: A dictionary from string method names
- to face_interfaces.InlineValueInStreamOutMethod implementations of those
- methods.
- inline_stream_in_value_out_methods: A dictionary from string method names
- to face_interfaces.InlineStreamInValueOutMethod implementations of those
- methods.
- inline_stream_in_stream_out_methods: A dictionary from string method names
- to face_interfaces.InlineStreamInStreamOutMethod implementations of
- those methods.
- event_value_in_value_out_methods: A dictionary from string method names
- to face_interfaces.EventValueInValueOutMethod implementations of those
- methods.
- event_value_in_stream_out_methods: A dictionary from string method names
- to face_interfaces.EventValueInStreamOutMethod implementations of those
- methods.
- event_stream_in_value_out_methods: A dictionary from string method names
- to face_interfaces.EventStreamInValueOutMethod implementations of those
- methods.
- event_stream_in_stream_out_methods: A dictionary from string method names
- to face_interfaces.EventStreamInStreamOutMethod implementations of those
- methods.
- multi_method: An face_interfaces.MultiMethod, or None.
+ method_implementations: A dictionary from string RPC method name to
+ face_interfaces.MethodImplementation object specifying
+ implementation of an RPC method.
+ multi_method_implementation: An face_interfaces.MultiMethodImplementation
+ or None.
Returns:
- A sequence of length three the first element of which is a
- face_interfaces.Server, the second element of which is a
- face_interfaces.Stub, (both of which are backed by the given method
- implementations), and the third element of which is an arbitrary memo
+ A sequence of length two the first element of which is a
+ face_interfaces.GenericStub (backed by the given method
+ implementations), and the second element of which is an arbitrary memo
object to be kept and passed to tearDownImplementation at the conclusion
of the test.
"""
@@ -105,7 +74,7 @@ class FaceTestCase(object):
"""Destroys the Face layer implementation under test.
Args:
- memo: The object from the third position of the return value of
+ memo: The object from the second position of the return value of
set_up_implementation.
"""
raise NotImplementedError()
diff --git a/src/python/src/grpc/framework/face/utilities.py b/src/python/src/grpc/framework/face/utilities.py
index 5e34be37da..a63fe8c60d 100644
--- a/src/python/src/grpc/framework/face/utilities.py
+++ b/src/python/src/grpc/framework/face/utilities.py
@@ -27,101 +27,44 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-"""Utilities for the face layer of RPC Framework."""
+"""Utilities for RPC framework's face layer."""
-# stream is referenced from specification in this module.
-from grpc.framework.face import interfaces
-from grpc.framework.foundation import stream # pylint: disable=unused-import
-
-
-class _InlineUnaryUnaryMethod(interfaces.InlineValueInValueOutMethod):
-
- def __init__(self, behavior):
- self._behavior = behavior
-
- def service(self, request, context):
- return self._behavior(request, context)
-
-
-class _InlineUnaryStreamMethod(interfaces.InlineValueInStreamOutMethod):
-
- def __init__(self, behavior):
- self._behavior = behavior
-
- def service(self, request, context):
- return self._behavior(request, context)
-
-
-class _InlineStreamUnaryMethod(interfaces.InlineStreamInValueOutMethod):
-
- def __init__(self, behavior):
- self._behavior = behavior
-
- def service(self, request_iterator, context):
- return self._behavior(request_iterator, context)
-
-
-class _InlineStreamStreamMethod(interfaces.InlineStreamInStreamOutMethod):
-
- def __init__(self, behavior):
- self._behavior = behavior
-
- def service(self, request_iterator, context):
- return self._behavior(request_iterator, context)
+import collections
+from grpc.framework.common import cardinality
+from grpc.framework.common import style
+from grpc.framework.face import interfaces
+from grpc.framework.foundation import stream
-class _EventUnaryUnaryMethod(interfaces.EventValueInValueOutMethod):
-
- def __init__(self, behavior):
- self._behavior = behavior
-
- def service(self, request, response_callback, context):
- return self._behavior(request, response_callback, context)
-
-
-class _EventUnaryStreamMethod(interfaces.EventValueInStreamOutMethod):
-
- def __init__(self, behavior):
- self._behavior = behavior
-
- def service(self, request, response_consumer, context):
- return self._behavior(request, response_consumer, context)
-
-
-class _EventStreamUnaryMethod(interfaces.EventStreamInValueOutMethod):
-
- def __init__(self, behavior):
- self._behavior = behavior
-
- def service(self, response_callback, context):
- return self._behavior(response_callback, context)
-
-
-class _EventStreamStreamMethod(interfaces.EventStreamInStreamOutMethod):
-
- def __init__(self, behavior):
- self._behavior = behavior
- def service(self, response_consumer, context):
- return self._behavior(response_consumer, context)
+class _MethodImplementation(
+ interfaces.MethodImplementation,
+ collections.namedtuple(
+ '_MethodImplementation',
+ ['cardinality', 'style', 'unary_unary_inline', 'unary_stream_inline',
+ 'stream_unary_inline', 'stream_stream_inline', 'unary_unary_event',
+ 'unary_stream_event', 'stream_unary_event', 'stream_stream_event',])):
+ pass
-def inline_unary_unary_method(behavior):
- """Creates an interfaces.InlineValueInValueOutMethod from a behavior.
+def unary_unary_inline(behavior):
+ """Creates an interfaces.MethodImplementation for the given behavior.
Args:
- behavior: The implementation of a unary-unary RPC method as a callable
- value that takes a request value and an interfaces.RpcContext object and
+ behavior: The implementation of a unary-unary RPC method as a callable value
+ that takes a request value and an interfaces.RpcContext object and
returns a response value.
Returns:
- An interfaces.InlineValueInValueOutMethod derived from the given behavior.
+ An interfaces.MethodImplementation derived from the given behavior.
"""
- return _InlineUnaryUnaryMethod(behavior)
+ return _MethodImplementation(
+ cardinality.Cardinality.UNARY_UNARY, style.Service.INLINE, behavior,
+ None, None, None, None, None, None, None)
-def inline_unary_stream_method(behavior):
- """Creates an interfaces.InlineValueInStreamOutMethod from a behavior.
+def unary_stream_inline(behavior):
+ """Creates an interfaces.MethodImplementation for the given behavior.
Args:
behavior: The implementation of a unary-stream RPC method as a callable
@@ -129,13 +72,15 @@ def inline_unary_stream_method(behavior):
returns an iterator of response values.
Returns:
- An interfaces.InlineValueInStreamOutMethod derived from the given behavior.
+ An interfaces.MethodImplementation derived from the given behavior.
"""
- return _InlineUnaryStreamMethod(behavior)
+ return _MethodImplementation(
+ cardinality.Cardinality.UNARY_STREAM, style.Service.INLINE, None,
+ behavior, None, None, None, None, None, None)
-def inline_stream_unary_method(behavior):
- """Creates an interfaces.InlineStreamInValueOutMethod from a behavior.
+def stream_unary_inline(behavior):
+ """Creates an interfaces.MethodImplementation for the given behavior.
Args:
behavior: The implementation of a stream-unary RPC method as a callable
@@ -143,13 +88,15 @@ def inline_stream_unary_method(behavior):
interfaces.RpcContext object and returns a response value.
Returns:
- An interfaces.InlineStreamInValueOutMethod derived from the given behavior.
+ An interfaces.MethodImplementation derived from the given behavior.
"""
- return _InlineStreamUnaryMethod(behavior)
+ return _MethodImplementation(
+ cardinality.Cardinality.STREAM_UNARY, style.Service.INLINE, None, None,
+ behavior, None, None, None, None, None)
-def inline_stream_stream_method(behavior):
- """Creates an interfaces.InlineStreamInStreamOutMethod from a behavior.
+def stream_stream_inline(behavior):
+ """Creates an interfaces.MethodImplementation for the given behavior.
Args:
behavior: The implementation of a stream-stream RPC method as a callable
@@ -157,14 +104,15 @@ def inline_stream_stream_method(behavior):
interfaces.RpcContext object and returns an iterator of response values.
Returns:
- An interfaces.InlineStreamInStreamOutMethod derived from the given
- behavior.
+ An interfaces.MethodImplementation derived from the given behavior.
"""
- return _InlineStreamStreamMethod(behavior)
+ return _MethodImplementation(
+ cardinality.Cardinality.STREAM_STREAM, style.Service.INLINE, None, None,
+ None, behavior, None, None, None, None)
-def event_unary_unary_method(behavior):
- """Creates an interfaces.EventValueInValueOutMethod from a behavior.
+def unary_unary_event(behavior):
+ """Creates an interfaces.MethodImplementation for the given behavior.
Args:
behavior: The implementation of a unary-unary RPC method as a callable
@@ -172,27 +120,31 @@ def event_unary_unary_method(behavior):
the response value of the RPC, and an interfaces.RpcContext.
Returns:
- An interfaces.EventValueInValueOutMethod derived from the given behavior.
+ An interfaces.MethodImplementation derived from the given behavior.
"""
- return _EventUnaryUnaryMethod(behavior)
+ return _MethodImplementation(
+ cardinality.Cardinality.UNARY_UNARY, style.Service.EVENT, None, None,
+ None, None, behavior, None, None, None)
-def event_unary_stream_method(behavior):
- """Creates an interfaces.EventValueInStreamOutMethod from a behavior.
+def unary_stream_event(behavior):
+ """Creates an interfaces.MethodImplementation for the given behavior.
Args:
behavior: The implementation of a unary-stream RPC method as a callable
value that takes a request value, a stream.Consumer to which to pass the
- response values of the RPC, and an interfaces.RpcContext.
+ the response values of the RPC, and an interfaces.RpcContext.
Returns:
- An interfaces.EventValueInStreamOutMethod derived from the given behavior.
+ An interfaces.MethodImplementation derived from the given behavior.
"""
- return _EventUnaryStreamMethod(behavior)
+ return _MethodImplementation(
+ cardinality.Cardinality.UNARY_STREAM, style.Service.EVENT, None, None,
+ None, None, None, behavior, None, None)
-def event_stream_unary_method(behavior):
- """Creates an interfaces.EventStreamInValueOutMethod from a behavior.
+def stream_unary_event(behavior):
+ """Creates an interfaces.MethodImplementation for the given behavior.
Args:
behavior: The implementation of a stream-unary RPC method as a callable
@@ -201,13 +153,15 @@ def event_stream_unary_method(behavior):
which the request values of the RPC should be passed.
Returns:
- An interfaces.EventStreamInValueOutMethod derived from the given behavior.
+ An interfaces.MethodImplementation derived from the given behavior.
"""
- return _EventStreamUnaryMethod(behavior)
+ return _MethodImplementation(
+ cardinality.Cardinality.STREAM_UNARY, style.Service.EVENT, None, None,
+ None, None, None, None, behavior, None)
-def event_stream_stream_method(behavior):
- """Creates an interfaces.EventStreamInStreamOutMethod from a behavior.
+def stream_stream_event(behavior):
+ """Creates an interfaces.MethodImplementation for the given behavior.
Args:
behavior: The implementation of a stream-stream RPC method as a callable
@@ -216,6 +170,8 @@ def event_stream_stream_method(behavior):
which the request values of the RPC should be passed.
Returns:
- An interfaces.EventStreamInStreamOutMethod derived from the given behavior.
+ An interfaces.MethodImplementation derived from the given behavior.
"""
- return _EventStreamStreamMethod(behavior)
+ return _MethodImplementation(
+ cardinality.Cardinality.STREAM_STREAM, style.Service.EVENT, None, None,
+ None, None, None, None, None, behavior)
diff --git a/src/python/src/grpc/framework/foundation/_logging_pool_test.py b/src/python/src/grpc/framework/foundation/_logging_pool_test.py
index 11463a8bec..c92cf8c0ab 100644
--- a/src/python/src/grpc/framework/foundation/_logging_pool_test.py
+++ b/src/python/src/grpc/framework/foundation/_logging_pool_test.py
@@ -27,7 +27,7 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-"""Tests for _framework.foundation.logging_pool."""
+"""Tests for grpc.framework.foundation.logging_pool."""
import unittest
diff --git a/src/python/src/setup.py b/src/python/src/setup.py
index cdb82a9dc3..bd70634b8f 100644
--- a/src/python/src/setup.py
+++ b/src/python/src/setup.py
@@ -54,8 +54,8 @@ _EXTENSION_LIBRARIES = (
_EXTENSION_MODULE = _core.Extension(
'grpc._adapter._c', sources=list(_EXTENSION_SOURCES),
- include_dirs=_EXTENSION_INCLUDE_DIRECTORIES,
- libraries=_EXTENSION_LIBRARIES,
+ include_dirs=list(_EXTENSION_INCLUDE_DIRECTORIES),
+ libraries=list(_EXTENSION_LIBRARIES),
)
_PACKAGES = (
@@ -64,9 +64,8 @@ _PACKAGES = (
'grpc._junkdrawer',
'grpc.early_adopter',
'grpc.framework',
- 'grpc.framework.assembly',
+ 'grpc.framework.alpha',
'grpc.framework.base',
- 'grpc.framework.base.packets',
'grpc.framework.common',
'grpc.framework.face',
'grpc.framework.face.testing',
@@ -83,5 +82,5 @@ _PACKAGE_DIRECTORIES = {
_core.setup(
name='grpc-2015', version='0.4.0',
- ext_modules=[_EXTENSION_MODULE], packages=_PACKAGES,
+ ext_modules=[_EXTENSION_MODULE], packages=list(_PACKAGES),
package_dir=_PACKAGE_DIRECTORIES)
diff --git a/src/ruby/Rakefile b/src/ruby/Rakefile
index b27305d16c..afb354e922 100755
--- a/src/ruby/Rakefile
+++ b/src/ruby/Rakefile
@@ -2,14 +2,17 @@
require 'rake/extensiontask'
require 'rspec/core/rake_task'
require 'rubocop/rake_task'
+require 'bundler/gem_tasks'
-desc 'Run Rubocop to check for style violations'
+# Add rubocop style checking tasks
RuboCop::RakeTask.new
+# Add the extension compiler task
Rake::ExtensionTask.new 'grpc' do |ext|
ext.lib_dir = File.join('lib', 'grpc')
end
+# Define the test suites
SPEC_SUITES = [
{ id: :wrapper, title: 'wrapper layer', files: %w(spec/*.rb) },
{ id: :idiomatic, title: 'idiomatic layer', dir: %w(spec/generic),
@@ -19,36 +22,34 @@ SPEC_SUITES = [
{ id: :server, title: 'rpc server thread tests', dir: %w(spec/generic),
tag: 'server' }
]
+namespace :suite do
+ SPEC_SUITES.each do |suite|
+ desc "Run all specs in the #{suite[:title]} spec suite"
+ RSpec::Core::RakeTask.new(suite[:id]) do |t|
+ spec_files = []
+ suite[:files].each { |f| spec_files += Dir[f] } if suite[:files]
+
+ if suite[:dir]
+ suite[:dir].each { |f| spec_files += Dir["#{f}/**/*_spec.rb"] }
+ end
+ helper = 'spec/spec_helper.rb'
+ spec_files << helper unless spec_files.include?(helper)
-desc 'Run all RSpec tests'
-namespace :spec do
- namespace :suite do
- SPEC_SUITES.each do |suite|
- desc "Run all specs in #{suite[:title]} spec suite"
- RSpec::Core::RakeTask.new(suite[:id]) do |t|
- spec_files = []
- suite[:files].each { |f| spec_files += Dir[f] } if suite[:files]
-
- if suite[:dirs]
- suite[:dirs].each { |f| spec_files += Dir["#{f}/**/*_spec.rb"] }
- end
-
- t.pattern = spec_files
- t.rspec_opts = "--tag #{suite[:tag]}" if suite[:tag]
- if suite[:tags]
- t.rspec_opts = suite[:tags].map { |x| "--tag #{x}" }.join(' ')
- end
+ t.pattern = spec_files
+ t.rspec_opts = "--tag #{suite[:tag]}" if suite[:tag]
+ if suite[:tags]
+ t.rspec_opts = suite[:tags].map { |x| "--tag #{x}" }.join(' ')
end
end
end
end
-desc 'Compiles the extension then runs all the tests'
-task :all
+# Define dependencies between the suites.
+task 'suite:wrapper' => [:compile, :rubocop]
+task 'suite:idiomatic' => 'suite:wrapper'
+task 'suite:bidi' => 'suite:wrapper'
+task 'suite:server' => 'suite:wrapper'
+desc 'Compiles the gRPC extension then runs all the tests'
+task all: ['suite:idiomatic', 'suite:bidi', 'suite:server']
task default: :all
-task 'spec:suite:wrapper' => [:compile, :rubocop]
-task 'spec:suite:idiomatic' => 'spec:suite:wrapper'
-task 'spec:suite:bidi' => 'spec:suite:wrapper'
-task 'spec:suite:server' => 'spec:suite:wrapper'
-task all: ['spec:suite:idiomatic', 'spec:suite:bidi', 'spec:suite:server']
diff --git a/src/ruby/bin/interop/interop_client.rb b/src/ruby/bin/interop/interop_client.rb
index b0b24b949f..b2a8711c79 100755
--- a/src/ruby/bin/interop/interop_client.rb
+++ b/src/ruby/bin/interop/interop_client.rb
@@ -57,7 +57,7 @@ require 'test/cpp/interop/empty'
require 'signet/ssl_config'
-AUTH_ENV = Google::Auth::ServiceAccountCredentials::ENV_VAR
+AUTH_ENV = Google::Auth::CredentialsLoader::ENV_VAR
# loads the certificates used to access the test server securely.
def load_test_certs
diff --git a/src/ruby/lib/grpc/generic/active_call.rb b/src/ruby/lib/grpc/generic/active_call.rb
index 7b69f1f6d0..6256330e88 100644
--- a/src/ruby/lib/grpc/generic/active_call.rb
+++ b/src/ruby/lib/grpc/generic/active_call.rb
@@ -505,12 +505,12 @@ module GRPC
# SingleReqView limits access to an ActiveCall's methods for use in server
# handlers that receive just one request.
- SingleReqView = view_class(:cancelled, :deadline)
+ SingleReqView = view_class(:cancelled, :deadline, :metadata)
# MultiReqView limits access to an ActiveCall's methods for use in
# server client_streamer handlers.
MultiReqView = view_class(:cancelled, :deadline, :each_queued_msg,
- :each_remote_read)
+ :each_remote_read, :metadata)
# Operation limits access to an ActiveCall's methods for use as
# a Operation on the client.
diff --git a/src/ruby/lib/grpc/generic/rpc_desc.rb b/src/ruby/lib/grpc/generic/rpc_desc.rb
index 5e3d3c9f9c..2cb3d2eebf 100644
--- a/src/ruby/lib/grpc/generic/rpc_desc.rb
+++ b/src/ruby/lib/grpc/generic/rpc_desc.rb
@@ -81,6 +81,7 @@ module GRPC
active_call.run_server_bidi(mth)
end
send_status(active_call, OK, 'OK')
+ active_call.finished
rescue BadStatus => e
# this is raised by handlers that want GRPC to send an application
# error code and detail message.
diff --git a/src/ruby/lib/grpc/generic/service.rb b/src/ruby/lib/grpc/generic/service.rb
index 6ea0831a2e..69076b4c6e 100644
--- a/src/ruby/lib/grpc/generic/service.rb
+++ b/src/ruby/lib/grpc/generic/service.rb
@@ -176,25 +176,26 @@ module GRPC
unmarshal = desc.unmarshal_proc(:output)
route = "/#{route_prefix}/#{name}"
if desc.request_response?
- define_method(mth_name) do |req, deadline = nil|
+ define_method(mth_name) do |req, deadline = nil, **kw|
logger.debug("calling #{@host}:#{route}")
- request_response(route, req, marshal, unmarshal, deadline)
+ request_response(route, req, marshal, unmarshal, deadline, **kw)
end
elsif desc.client_streamer?
- define_method(mth_name) do |reqs, deadline = nil|
+ define_method(mth_name) do |reqs, deadline = nil, **kw|
logger.debug("calling #{@host}:#{route}")
- client_streamer(route, reqs, marshal, unmarshal, deadline)
+ client_streamer(route, reqs, marshal, unmarshal, deadline, **kw)
end
elsif desc.server_streamer?
- define_method(mth_name) do |req, deadline = nil, &blk|
+ define_method(mth_name) do |req, deadline = nil, **kw, &blk|
logger.debug("calling #{@host}:#{route}")
- server_streamer(route, req, marshal, unmarshal, deadline,
+ server_streamer(route, req, marshal, unmarshal, deadline, **kw,
&blk)
end
else # is a bidi_stream
- define_method(mth_name) do |reqs, deadline = nil, &blk|
+ define_method(mth_name) do |reqs, deadline = nil, **kw, &blk|
logger.debug("calling #{@host}:#{route}")
- bidi_streamer(route, reqs, marshal, unmarshal, deadline, &blk)
+ bidi_streamer(route, reqs, marshal, unmarshal, deadline, **kw,
+ &blk)
end
end
end
diff --git a/src/ruby/spec/generic/active_call_spec.rb b/src/ruby/spec/generic/active_call_spec.rb
index 12cb5c1558..96e07cacb4 100644
--- a/src/ruby/spec/generic/active_call_spec.rb
+++ b/src/ruby/spec/generic/active_call_spec.rb
@@ -67,8 +67,8 @@ describe GRPC::ActiveCall do
end
describe '#multi_req_view' do
- xit 'exposes a fixed subset of the ActiveCall methods' do
- want = %w(cancelled, deadline, each_remote_read, shutdown)
+ it 'exposes a fixed subset of the ActiveCall methods' do
+ want = %w(cancelled, deadline, each_remote_read, metadata, shutdown)
v = @client_call.multi_req_view
want.each do |w|
expect(v.methods.include?(w))
@@ -77,8 +77,8 @@ describe GRPC::ActiveCall do
end
describe '#single_req_view' do
- xit 'exposes a fixed subset of the ActiveCall methods' do
- want = %w(cancelled, deadline, shutdown)
+ it 'exposes a fixed subset of the ActiveCall methods' do
+ want = %w(cancelled, deadline, metadata, shutdown)
v = @client_call.single_req_view
want.each do |w|
expect(v.methods.include?(w))
diff --git a/src/ruby/spec/generic/client_stub_spec.rb b/src/ruby/spec/generic/client_stub_spec.rb
index adf354f4ee..0c98fc40d9 100644
--- a/src/ruby/spec/generic/client_stub_spec.rb
+++ b/src/ruby/spec/generic/client_stub_spec.rb
@@ -384,13 +384,7 @@ describe 'ClientStub' do
th.join
end
- # disabled because an unresolved wire-protocol implementation feature
- #
- # - servers should be able initiate messaging, however, as it stand
- # servers don't know if all the client metadata has been sent until
- # they receive a message from the client. Without receiving all the
- # metadata, the server does not accept the call, so this test hangs.
- xit 'supports a server-initiated ping pong', bidi: true do
+ it 'supports a server-initiated ping pong', bidi: true do
server_port = create_test_server
host = "localhost:#{server_port}"
th = run_bidi_streamer_echo_ping_pong(@sent_msgs, @pass, false)
@@ -434,7 +428,7 @@ describe 'ClientStub' do
end
expect(c.remote_read).to eq(expected_input)
replys.each { |r| c.remote_send(r) }
- c.send_status(status, status == @pass ? 'OK' : 'NOK')
+ c.send_status(status, status == @pass ? 'OK' : 'NOK', true)
end
end
@@ -444,7 +438,7 @@ describe 'ClientStub' do
c = expect_server_to_be_invoked(mtx, cnd)
expected_inputs.each { |i| expect(c.remote_read).to eq(i) }
replys.each { |r| c.remote_send(r) }
- c.send_status(status, status == @pass ? 'OK' : 'NOK')
+ c.send_status(status, status == @pass ? 'OK' : 'NOK', true)
end
end
@@ -460,7 +454,7 @@ describe 'ClientStub' do
expect(c.remote_read).to eq(i)
end
end
- c.send_status(status, status == @pass ? 'OK' : 'NOK')
+ c.send_status(status, status == @pass ? 'OK' : 'NOK', true)
end
end
@@ -473,7 +467,7 @@ describe 'ClientStub' do
expect(c.metadata[k.to_s]).to eq(v)
end
c.remote_send(resp)
- c.send_status(status, status == @pass ? 'OK' : 'NOK')
+ c.send_status(status, status == @pass ? 'OK' : 'NOK', true)
end
end
@@ -486,7 +480,7 @@ describe 'ClientStub' do
expect(c.metadata[k.to_s]).to eq(v)
end
c.remote_send(resp)
- c.send_status(status, status == @pass ? 'OK' : 'NOK')
+ c.send_status(status, status == @pass ? 'OK' : 'NOK', true)
end
end
diff --git a/src/ruby/spec/generic/rpc_desc_spec.rb b/src/ruby/spec/generic/rpc_desc_spec.rb
index 8bff2a9a64..39d1e83748 100644
--- a/src/ruby/spec/generic/rpc_desc_spec.rb
+++ b/src/ruby/spec/generic/rpc_desc_spec.rb
@@ -94,6 +94,7 @@ describe GRPC::RpcDesc do
expect(@call).to receive(:remote_read).once.and_return(req)
expect(@call).to receive(:remote_send).once.with(@ok_response)
expect(@call).to receive(:send_status).once.with(OK, 'OK')
+ expect(@call).to receive(:finished).once
@request_response.run_server_method(@call, method(:fake_reqresp))
end
end
@@ -134,6 +135,7 @@ describe GRPC::RpcDesc do
it 'sends a response and closes the stream if there no errors' do
expect(@call).to receive(:remote_send).once.with(@ok_response)
expect(@call).to receive(:send_status).once.with(OK, 'OK')
+ expect(@call).to receive(:finished).once
@client_streamer.run_server_method(@call, method(:fake_clstream))
end
end
@@ -178,6 +180,7 @@ describe GRPC::RpcDesc do
expect(@call).to receive(:remote_read).once.and_return(req)
expect(@call).to receive(:remote_send).twice.with(@ok_response)
expect(@call).to receive(:send_status).once.with(OK, 'OK')
+ expect(@call).to receive(:finished).once
@server_streamer.run_server_method(@call, method(:fake_svstream))
end
end
@@ -207,6 +210,7 @@ describe GRPC::RpcDesc do
it 'closes the stream if there no errors' do
expect(@call).to receive(:run_server_bidi)
expect(@call).to receive(:send_status).once.with(OK, 'OK')
+ expect(@call).to receive(:finished).once
@bidi_streamer.run_server_method(@call, method(:fake_bidistream))
end
end
diff --git a/src/ruby/spec/generic/rpc_server_spec.rb b/src/ruby/spec/generic/rpc_server_spec.rb
index d5421d400c..34e5cdcd04 100644
--- a/src/ruby/spec/generic/rpc_server_spec.rb
+++ b/src/ruby/spec/generic/rpc_server_spec.rb
@@ -62,12 +62,15 @@ end
class EchoService
include GRPC::GenericService
rpc :an_rpc, EchoMsg, EchoMsg
+ attr_reader :received_md
def initialize(_default_var = 'ignored')
+ @received_md = []
end
- def an_rpc(req, _call)
+ def an_rpc(req, call)
logger.info('echo service received a request')
+ @received_md << call.metadata unless call.metadata.nil?
req
end
end
@@ -78,14 +81,17 @@ EchoStub = EchoService.rpc_stub_class
class SlowService
include GRPC::GenericService
rpc :an_rpc, EchoMsg, EchoMsg
+ attr_reader :received_md, :delay
def initialize(_default_var = 'ignored')
+ @delay = 0.25
+ @received_md = []
end
- def an_rpc(req, _call)
- delay = 0.25
- logger.info("starting a slow #{delay} rpc")
- sleep delay
+ def an_rpc(req, call)
+ logger.info("starting a slow #{@delay} rpc")
+ sleep @delay
+ @received_md << call.metadata unless call.metadata.nil?
req # send back the req as the response
end
end
@@ -337,6 +343,69 @@ describe GRPC::RpcServer do
t.join
end
+ it 'should receive metadata sent as rpc keyword args', server: true do
+ service = EchoService.new
+ @srv.handle(service)
+ t = Thread.new { @srv.run }
+ @srv.wait_till_running
+ req = EchoMsg.new
+ stub = EchoStub.new(@host, **@client_opts)
+ expect(stub.an_rpc(req, k1: 'v1', k2: 'v2')).to be_a(EchoMsg)
+ wanted_md = [{ 'k1' => 'v1', 'k2' => 'v2' }]
+ expect(service.received_md).to eq(wanted_md)
+ @srv.stop
+ t.join
+ end
+
+ it 'should receive metadata when a deadline is specified', server: true do
+ service = SlowService.new
+ @srv.handle(service)
+ t = Thread.new { @srv.run }
+ @srv.wait_till_running
+ req = EchoMsg.new
+ stub = SlowStub.new(@host, **@client_opts)
+ deadline = service.delay + 0.5 # wait for long enough
+ expect(stub.an_rpc(req, deadline, k1: 'v1', k2: 'v2')).to be_a(EchoMsg)
+ wanted_md = [{ 'k1' => 'v1', 'k2' => 'v2' }]
+ expect(service.received_md).to eq(wanted_md)
+ @srv.stop
+ t.join
+ end
+
+ it 'should not receive metadata if the client times out', server: true do
+ service = SlowService.new
+ @srv.handle(service)
+ t = Thread.new { @srv.run }
+ @srv.wait_till_running
+ req = EchoMsg.new
+ stub = SlowStub.new(@host, **@client_opts)
+ deadline = 0.1 # too short for SlowService to respond
+ blk = proc { stub.an_rpc(req, deadline, k1: 'v1', k2: 'v2') }
+ expect(&blk).to raise_error GRPC::BadStatus
+ wanted_md = []
+ expect(service.received_md).to eq(wanted_md)
+ @srv.stop
+ t.join
+ end
+
+ it 'should receive updated metadata', server: true do
+ service = EchoService.new
+ @srv.handle(service)
+ t = Thread.new { @srv.run }
+ @srv.wait_till_running
+ req = EchoMsg.new
+ @client_opts[:update_metadata] = proc do |md|
+ md[:k1] = 'updated-v1'
+ md
+ end
+ stub = EchoStub.new(@host, **@client_opts)
+ expect(stub.an_rpc(req, k1: 'v1', k2: 'v2')).to be_a(EchoMsg)
+ wanted_md = [{ 'k1' => 'updated-v1', 'k2' => 'v2' }]
+ expect(service.received_md).to eq(wanted_md)
+ @srv.stop
+ t.join
+ end
+
it 'should handle multiple parallel requests', server: true do
@srv.handle(EchoService)
Thread.new { @srv.run }