Merge branch 'master' of github.com:grpc/grpc into iomgr_executor

pull/3726/head
David Garcia Quintas 9 years ago
commit e945cd8064
  1. 3
      BUILD
  2. 236
      binding.gyp
  3. 1
      build.yaml
  4. 3
      examples/php/README.md
  5. 2
      gRPC.podspec
  6. 296
      grpc.gyp
  7. 12
      include/grpc/support/port_platform.h
  8. 3
      package.json
  9. 29
      src/core/channel/client_channel.c
  10. 2
      src/core/channel/compress_filter.c
  11. 17
      src/core/client_config/subchannel.c
  12. 22
      src/core/client_config/subchannel.h
  13. 4
      src/core/client_config/uri_parser.c
  14. 2
      src/core/compression/algorithm.c
  15. 11
      src/core/httpcli/parser.c
  16. 4
      src/core/iomgr/fd_posix.c
  17. 2
      src/core/iomgr/tcp_client_posix.c
  18. 2
      src/core/iomgr/tcp_server_posix.c
  19. 42
      src/core/security/credentials.c
  20. 8
      src/core/security/credentials.h
  21. 26
      src/core/security/security_context.c
  22. 11
      src/core/security/security_context.h
  23. 36
      src/core/security/server_auth_filter.c
  24. 4
      src/core/security/server_secure_chttp2.c
  25. 7
      src/core/surface/byte_buffer.c
  26. 30
      src/core/surface/call.c
  27. 11
      src/core/surface/call.h
  28. 65
      src/core/surface/call_test_only.h
  29. 8
      src/core/surface/channel_connectivity.c
  30. 3
      src/core/surface/completion_queue.c
  31. 4
      src/core/transport/chttp2/frame_data.c
  32. 4
      src/core/transport/chttp2/frame_goaway.c
  33. 8
      src/core/transport/chttp2/hpack_parser.c
  34. 16
      src/core/transport/chttp2/parsing.c
  35. 6
      src/core/transport/chttp2/stream_encoder.c
  36. 13
      src/core/tsi/ssl_transport_security.c
  37. 3
      src/cpp/server/server.cc
  38. 24
      src/csharp/Grpc.Auth/AuthInterceptors.cs
  39. 1
      src/csharp/Grpc.Auth/Grpc.Auth.csproj
  40. 93
      src/csharp/Grpc.Auth/GrpcCredentials.cs
  41. 25
      src/csharp/Grpc.Core.Tests/CallCredentialsTest.cs
  42. 73
      src/csharp/Grpc.Core.Tests/ChannelCredentialsTest.cs
  43. 10
      src/csharp/Grpc.Core.Tests/ChannelTest.cs
  44. 52
      src/csharp/Grpc.Core.Tests/FakeCredentials.cs
  45. 4
      src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj
  46. 2
      src/csharp/Grpc.Core.Tests/Internal/AsyncCallTest.cs
  47. 4
      src/csharp/Grpc.Core.Tests/MarshallingErrorsTest.cs
  48. 2
      src/csharp/Grpc.Core.Tests/MockServiceHelper.cs
  49. 2
      src/csharp/Grpc.Core.Tests/PInvokeTest.cs
  50. 142
      src/csharp/Grpc.Core/CallCredentials.cs
  51. 16
      src/csharp/Grpc.Core/CallOptions.cs
  52. 4
      src/csharp/Grpc.Core/Channel.cs
  53. 238
      src/csharp/Grpc.Core/ChannelCredentials.cs
  54. 31
      src/csharp/Grpc.Core/ClientBase.cs
  55. 138
      src/csharp/Grpc.Core/Credentials.cs
  56. 4
      src/csharp/Grpc.Core/Grpc.Core.csproj
  57. 2
      src/csharp/Grpc.Core/Grpc.Core.nuspec
  58. 10
      src/csharp/Grpc.Core/Internal/AsyncCall.cs
  59. 8
      src/csharp/Grpc.Core/Internal/CallSafeHandle.cs
  60. 6
      src/csharp/Grpc.Core/Internal/ChannelSafeHandle.cs
  61. 8
      src/csharp/Grpc.Core/Internal/CredentialsSafeHandle.cs
  62. 113
      src/csharp/Grpc.Core/Internal/NativeMetadataCredentialsPlugin.cs
  63. 2
      src/csharp/Grpc.Examples.MathClient/MathClient.cs
  64. 2
      src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs
  65. 2
      src/csharp/Grpc.HealthCheck.Tests/HealthClientServerTest.cs
  66. 49
      src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.csproj
  67. 11
      src/csharp/Grpc.IntegrationTesting.Client/packages.config
  68. 49
      src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.csproj
  69. 11
      src/csharp/Grpc.IntegrationTesting.Server/packages.config
  70. 5
      src/csharp/Grpc.IntegrationTesting/Empty.cs
  71. 4
      src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
  72. 97
      src/csharp/Grpc.IntegrationTesting/InteropClient.cs
  73. 7
      src/csharp/Grpc.IntegrationTesting/InteropServer.cs
  74. 446
      src/csharp/Grpc.IntegrationTesting/Messages.cs
  75. 97
      src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs
  76. 37
      src/csharp/Grpc.IntegrationTesting/Test.cs
  77. 188
      src/csharp/Grpc.IntegrationTesting/TestGrpc.cs
  78. 132
      src/csharp/Grpc.IntegrationTesting/proto/messages.proto
  79. 71
      src/csharp/Grpc.IntegrationTesting/proto/test.proto
  80. 4
      src/csharp/build_packages.bat
  81. 66
      src/csharp/ext/grpc_csharp_ext.c
  82. 2
      src/csharp/generate_proto_csharp.sh
  83. 188
      src/node/interop/interop_client.js
  84. 63
      src/node/interop/interop_server.js
  85. 2
      src/node/src/credentials.js
  86. 2
      src/node/src/server.js
  87. 2
      src/node/test/async_test.js
  88. 2
      src/node/test/channel_test.js
  89. 10
      src/node/test/credentials_test.js
  90. 10
      src/node/test/interop_sanity_test.js
  91. 5
      src/objective-c/README.md
  92. 10
      src/objective-c/RxLibrary/GRXWriter.m
  93. 30
      src/php/ext/grpc/package.xml
  94. 17
      src/php/ext/grpc/php_grpc.c
  95. 25
      src/php/lib/Grpc/BaseStub.php
  96. 8
      src/php/tests/generated_code/AbstractGeneratedCodeTest.php
  97. 20
      src/php/tests/interop/interop_client.php
  98. 22
      src/ruby/lib/grpc/generic/client_stub.rb
  99. 14
      src/ruby/spec/generic/client_stub_spec.rb
  100. 116
      templates/binding.gyp.template
  101. Some files were not shown because too many files have changed in this diff Show More

@ -224,6 +224,7 @@ cc_library(
"src/core/surface/api_trace.h",
"src/core/surface/byte_buffer_queue.h",
"src/core/surface/call.h",
"src/core/surface/call_test_only.h",
"src/core/surface/channel.h",
"src/core/surface/completion_queue.h",
"src/core/surface/event_string.h",
@ -512,6 +513,7 @@ cc_library(
"src/core/surface/api_trace.h",
"src/core/surface/byte_buffer_queue.h",
"src/core/surface/call.h",
"src/core/surface/call_test_only.h",
"src/core/surface/channel.h",
"src/core/surface/completion_queue.h",
"src/core/surface/event_string.h",
@ -1302,6 +1304,7 @@ objc_library(
"src/core/surface/api_trace.h",
"src/core/surface/byte_buffer_queue.h",
"src/core/surface/call.h",
"src/core/surface/call_test_only.h",
"src/core/surface/channel.h",
"src/core/surface/completion_queue.h",
"src/core/surface/event_string.h",

@ -1,3 +1,10 @@
# GRPC Node gyp file
# This currently builds the Node extension and dependencies
# This file has been automatically generated from a template file.
# Please look at the templates directory instead.
# This file can be regenerated from the template by running
# tools/buildgen/generate_projects.sh
# Copyright 2015, Google Inc.
# All rights reserved.
#
@ -26,11 +33,234 @@
# 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.
# Some of this file is built with the help of
# https://n8.io/converting-a-c-library-to-gyp/
{
"variables" : {
'variables': {
'config': '<!(echo $CONFIG)'
},
"targets" : [
# TODO: Finish windows support
'target_defaults': {
# Empirically, Node only exports ALPN symbols if its major version is >0.
# io.js always reports versions >0 and always exports ALPN symbols.
# Therefore, Node's major version will be truthy if and only if it
# supports ALPN. The output of "node -v" is v[major].[minor].[patch],
# like "v4.1.1" in a recent version. We use grep to extract just the
# major version. "4", would be the output for the example.
'defines': [
'TSI_OPENSSL_ALPN_SUPPORT=<!(node -v | grep -oP "(?<=v)(\d+)(?=\.\d+\.\d+)")'
],
'include_dirs': [
'.',
'include'
]
},
'targets': [
{
'target_name': 'gpr',
'product_prefix': 'lib',
'type': 'static_library',
'dependencies': [
],
'sources': [
'src/core/support/alloc.c',
'src/core/support/cmdline.c',
'src/core/support/cpu_iphone.c',
'src/core/support/cpu_linux.c',
'src/core/support/cpu_posix.c',
'src/core/support/cpu_windows.c',
'src/core/support/env_linux.c',
'src/core/support/env_posix.c',
'src/core/support/env_win32.c',
'src/core/support/file.c',
'src/core/support/file_posix.c',
'src/core/support/file_win32.c',
'src/core/support/histogram.c',
'src/core/support/host_port.c',
'src/core/support/log.c',
'src/core/support/log_android.c',
'src/core/support/log_linux.c',
'src/core/support/log_posix.c',
'src/core/support/log_win32.c',
'src/core/support/murmur_hash.c',
'src/core/support/slice.c',
'src/core/support/slice_buffer.c',
'src/core/support/stack_lockfree.c',
'src/core/support/string.c',
'src/core/support/string_posix.c',
'src/core/support/string_win32.c',
'src/core/support/subprocess_posix.c',
'src/core/support/sync.c',
'src/core/support/sync_posix.c',
'src/core/support/sync_win32.c',
'src/core/support/thd.c',
'src/core/support/thd_posix.c',
'src/core/support/thd_win32.c',
'src/core/support/time.c',
'src/core/support/time_posix.c',
'src/core/support/time_win32.c',
'src/core/support/tls_pthread.c',
],
},
{
'target_name': 'grpc',
'product_prefix': 'lib',
'type': 'static_library',
'dependencies': [
'gpr',
],
'sources': [
'src/core/httpcli/httpcli_security_connector.c',
'src/core/security/base64.c',
'src/core/security/client_auth_filter.c',
'src/core/security/credentials.c',
'src/core/security/credentials_metadata.c',
'src/core/security/credentials_posix.c',
'src/core/security/credentials_win32.c',
'src/core/security/google_default_credentials.c',
'src/core/security/handshake.c',
'src/core/security/json_token.c',
'src/core/security/jwt_verifier.c',
'src/core/security/secure_endpoint.c',
'src/core/security/security_connector.c',
'src/core/security/security_context.c',
'src/core/security/server_auth_filter.c',
'src/core/security/server_secure_chttp2.c',
'src/core/surface/init_secure.c',
'src/core/surface/secure_channel_create.c',
'src/core/tsi/fake_transport_security.c',
'src/core/tsi/ssl_transport_security.c',
'src/core/tsi/transport_security.c',
'src/core/census/grpc_context.c',
'src/core/census/grpc_filter.c',
'src/core/channel/channel_args.c',
'src/core/channel/channel_stack.c',
'src/core/channel/client_channel.c',
'src/core/channel/compress_filter.c',
'src/core/channel/connected_channel.c',
'src/core/channel/http_client_filter.c',
'src/core/channel/http_server_filter.c',
'src/core/channel/noop_filter.c',
'src/core/client_config/client_config.c',
'src/core/client_config/connector.c',
'src/core/client_config/lb_policies/pick_first.c',
'src/core/client_config/lb_policies/round_robin.c',
'src/core/client_config/lb_policy.c',
'src/core/client_config/lb_policy_factory.c',
'src/core/client_config/lb_policy_registry.c',
'src/core/client_config/resolver.c',
'src/core/client_config/resolver_factory.c',
'src/core/client_config/resolver_registry.c',
'src/core/client_config/resolvers/dns_resolver.c',
'src/core/client_config/resolvers/sockaddr_resolver.c',
'src/core/client_config/subchannel.c',
'src/core/client_config/subchannel_factory.c',
'src/core/client_config/subchannel_factory_decorators/add_channel_arg.c',
'src/core/client_config/subchannel_factory_decorators/merge_channel_args.c',
'src/core/client_config/uri_parser.c',
'src/core/compression/algorithm.c',
'src/core/compression/message_compress.c',
'src/core/debug/trace.c',
'src/core/httpcli/format_request.c',
'src/core/httpcli/httpcli.c',
'src/core/httpcli/parser.c',
'src/core/iomgr/alarm.c',
'src/core/iomgr/alarm_heap.c',
'src/core/iomgr/closure.c',
'src/core/iomgr/endpoint.c',
'src/core/iomgr/endpoint_pair_posix.c',
'src/core/iomgr/endpoint_pair_windows.c',
'src/core/iomgr/exec_ctx.c',
'src/core/iomgr/fd_posix.c',
'src/core/iomgr/iocp_windows.c',
'src/core/iomgr/iomgr.c',
'src/core/iomgr/iomgr_posix.c',
'src/core/iomgr/iomgr_windows.c',
'src/core/iomgr/pollset_multipoller_with_epoll.c',
'src/core/iomgr/pollset_multipoller_with_poll_posix.c',
'src/core/iomgr/pollset_posix.c',
'src/core/iomgr/pollset_set_posix.c',
'src/core/iomgr/pollset_set_windows.c',
'src/core/iomgr/pollset_windows.c',
'src/core/iomgr/resolve_address_posix.c',
'src/core/iomgr/resolve_address_windows.c',
'src/core/iomgr/sockaddr_utils.c',
'src/core/iomgr/socket_utils_common_posix.c',
'src/core/iomgr/socket_utils_linux.c',
'src/core/iomgr/socket_utils_posix.c',
'src/core/iomgr/socket_windows.c',
'src/core/iomgr/tcp_client_posix.c',
'src/core/iomgr/tcp_client_windows.c',
'src/core/iomgr/tcp_posix.c',
'src/core/iomgr/tcp_server_posix.c',
'src/core/iomgr/tcp_server_windows.c',
'src/core/iomgr/tcp_windows.c',
'src/core/iomgr/time_averaged_stats.c',
'src/core/iomgr/udp_server.c',
'src/core/iomgr/wakeup_fd_eventfd.c',
'src/core/iomgr/wakeup_fd_nospecial.c',
'src/core/iomgr/wakeup_fd_pipe.c',
'src/core/iomgr/wakeup_fd_posix.c',
'src/core/iomgr/workqueue_posix.c',
'src/core/iomgr/workqueue_windows.c',
'src/core/json/json.c',
'src/core/json/json_reader.c',
'src/core/json/json_string.c',
'src/core/json/json_writer.c',
'src/core/profiling/basic_timers.c',
'src/core/profiling/stap_timers.c',
'src/core/surface/api_trace.c',
'src/core/surface/byte_buffer.c',
'src/core/surface/byte_buffer_queue.c',
'src/core/surface/byte_buffer_reader.c',
'src/core/surface/call.c',
'src/core/surface/call_details.c',
'src/core/surface/call_log_batch.c',
'src/core/surface/channel.c',
'src/core/surface/channel_connectivity.c',
'src/core/surface/channel_create.c',
'src/core/surface/completion_queue.c',
'src/core/surface/event_string.c',
'src/core/surface/init.c',
'src/core/surface/lame_client.c',
'src/core/surface/metadata_array.c',
'src/core/surface/server.c',
'src/core/surface/server_chttp2.c',
'src/core/surface/server_create.c',
'src/core/surface/version.c',
'src/core/transport/chttp2/alpn.c',
'src/core/transport/chttp2/bin_encoder.c',
'src/core/transport/chttp2/frame_data.c',
'src/core/transport/chttp2/frame_goaway.c',
'src/core/transport/chttp2/frame_ping.c',
'src/core/transport/chttp2/frame_rst_stream.c',
'src/core/transport/chttp2/frame_settings.c',
'src/core/transport/chttp2/frame_window_update.c',
'src/core/transport/chttp2/hpack_parser.c',
'src/core/transport/chttp2/hpack_table.c',
'src/core/transport/chttp2/huffsyms.c',
'src/core/transport/chttp2/incoming_metadata.c',
'src/core/transport/chttp2/parsing.c',
'src/core/transport/chttp2/status_conversion.c',
'src/core/transport/chttp2/stream_encoder.c',
'src/core/transport/chttp2/stream_lists.c',
'src/core/transport/chttp2/stream_map.c',
'src/core/transport/chttp2/timeout_encoding.c',
'src/core/transport/chttp2/varint.c',
'src/core/transport/chttp2/writing.c',
'src/core/transport/chttp2_transport.c',
'src/core/transport/connectivity_state.c',
'src/core/transport/metadata.c',
'src/core/transport/stream_op.c',
'src/core/transport/transport.c',
'src/core/transport/transport_op_string.c',
'src/core/census/context.c',
'src/core/census/initialize.c',
'src/core/census/operation.c',
'src/core/census/tracing.c',
],
},
{
'include_dirs': [
"<!(node -e \"require('nan')\")"
@ -88,7 +318,7 @@
"src/node/ext/timeval.cc"
],
"dependencies": [
"grpc.gyp:grpc"
"grpc"
]
}
]

@ -184,6 +184,7 @@ filegroups:
- src/core/surface/api_trace.h
- src/core/surface/byte_buffer_queue.h
- src/core/surface/call.h
- src/core/surface/call_test_only.h
- src/core/surface/channel.h
- src/core/surface/completion_queue.h
- src/core/surface/event_string.h

@ -8,7 +8,7 @@ This requires PHP 5.5 or greater.
INSTALL
-------
- On Mac OS X, install [homebrew][]. On Linux, install [linuxbrew][]. Run the following command to install gRPC.
- On Mac OS X, install [homebrew][]. Run the following command to install gRPC.
```sh
$ curl -fsSL https://goo.gl/getgrpc | bash -s php
@ -59,7 +59,6 @@ TUTORIAL
You can find a more detailed tutorial in [gRPC Basics: PHP][]
[homebrew]:http://brew.sh
[linuxbrew]:https://github.com/Homebrew/linuxbrew#installation
[gRPC install script]:https://raw.githubusercontent.com/grpc/homebrew-grpc/master/scripts/install
[Node]:https://github.com/grpc/grpc/tree/master/examples/node
[gRPC Basics: PHP]:http://www.grpc.io/docs/tutorials/basic/php.html

@ -228,6 +228,7 @@ Pod::Spec.new do |s|
'src/core/surface/api_trace.h',
'src/core/surface/byte_buffer_queue.h',
'src/core/surface/call.h',
'src/core/surface/call_test_only.h',
'src/core/surface/channel.h',
'src/core/surface/completion_queue.h',
'src/core/surface/event_string.h',
@ -521,6 +522,7 @@ Pod::Spec.new do |s|
'src/core/surface/api_trace.h',
'src/core/surface/byte_buffer_queue.h',
'src/core/surface/call.h',
'src/core/surface/call_test_only.h',
'src/core/surface/channel.h',
'src/core/surface/completion_queue.h',
'src/core/surface/event_string.h',

@ -1,296 +0,0 @@
# GRPC gyp file
# This currently builds C code.
# This file has been automatically generated from a template file.
# Please look at the templates directory instead.
# This file can be regenerated from the template by running
# tools/buildgen/generate_projects.sh
# 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.
# Some of this file is built with the help of
# https://n8.io/converting-a-c-library-to-gyp/
{
# TODO: Finish windows support
'target_defaults': {
'default_configuration': 'Debug',
'configurations': {
'Debug': {
'defines': [ 'DEBUG', '_DEBUG' ],
'msvs_settings': {
'VCCLCompilerTool': {
'RuntimeLibrary': 1, # static debug
},
},
},
'Release': {
'defines': [ 'NDEBUG' ],
'msvs_settings': {
'VCCLCompilerTool': {
'RuntimeLibrary': 0, # static release
},
},
}
},
'msvs_settings': {
'VCLinkerTool': {
'GenerateDebugInformation': 'true',
},
},
# TODO: Add fallback for Windows, and if pkg-config is not available
'defines': [
'TSI_OPENSSL_ALPN_SUPPORT=<!(pkg-config --atleast-version=1.0.2 openssl >/dev/null 2>&1 && echo 1 || echo 0)'
],
'include_dirs': [
'.',
'include'
],
# TODO: Check for libraries with pkg-config
'libraries': [
'-lcrypto',
'-lssl',
'-ldl',
'-lpthread',
'-lz'
],
'direct_dependent_settings': {
'include_dirs': [
'.',
'include'
],
}
},
'targets': [
{
'target_name': 'gpr',
'product_prefix': 'lib',
'type': 'static_library',
'dependencies': [
],
'sources': [
'src/core/support/alloc.c',
'src/core/support/cmdline.c',
'src/core/support/cpu_iphone.c',
'src/core/support/cpu_linux.c',
'src/core/support/cpu_posix.c',
'src/core/support/cpu_windows.c',
'src/core/support/env_linux.c',
'src/core/support/env_posix.c',
'src/core/support/env_win32.c',
'src/core/support/file.c',
'src/core/support/file_posix.c',
'src/core/support/file_win32.c',
'src/core/support/histogram.c',
'src/core/support/host_port.c',
'src/core/support/log.c',
'src/core/support/log_android.c',
'src/core/support/log_linux.c',
'src/core/support/log_posix.c',
'src/core/support/log_win32.c',
'src/core/support/murmur_hash.c',
'src/core/support/slice.c',
'src/core/support/slice_buffer.c',
'src/core/support/stack_lockfree.c',
'src/core/support/string.c',
'src/core/support/string_posix.c',
'src/core/support/string_win32.c',
'src/core/support/subprocess_posix.c',
'src/core/support/sync.c',
'src/core/support/sync_posix.c',
'src/core/support/sync_win32.c',
'src/core/support/thd.c',
'src/core/support/thd_posix.c',
'src/core/support/thd_win32.c',
'src/core/support/time.c',
'src/core/support/time_posix.c',
'src/core/support/time_win32.c',
'src/core/support/tls_pthread.c',
],
},
{
'target_name': 'grpc',
'product_prefix': 'lib',
'type': 'static_library',
'dependencies': [
'gpr',
],
'sources': [
'src/core/httpcli/httpcli_security_connector.c',
'src/core/security/base64.c',
'src/core/security/client_auth_filter.c',
'src/core/security/credentials.c',
'src/core/security/credentials_metadata.c',
'src/core/security/credentials_posix.c',
'src/core/security/credentials_win32.c',
'src/core/security/google_default_credentials.c',
'src/core/security/handshake.c',
'src/core/security/json_token.c',
'src/core/security/jwt_verifier.c',
'src/core/security/secure_endpoint.c',
'src/core/security/security_connector.c',
'src/core/security/security_context.c',
'src/core/security/server_auth_filter.c',
'src/core/security/server_secure_chttp2.c',
'src/core/surface/init_secure.c',
'src/core/surface/secure_channel_create.c',
'src/core/tsi/fake_transport_security.c',
'src/core/tsi/ssl_transport_security.c',
'src/core/tsi/transport_security.c',
'src/core/census/grpc_context.c',
'src/core/census/grpc_filter.c',
'src/core/channel/channel_args.c',
'src/core/channel/channel_stack.c',
'src/core/channel/client_channel.c',
'src/core/channel/compress_filter.c',
'src/core/channel/connected_channel.c',
'src/core/channel/http_client_filter.c',
'src/core/channel/http_server_filter.c',
'src/core/channel/noop_filter.c',
'src/core/client_config/client_config.c',
'src/core/client_config/connector.c',
'src/core/client_config/lb_policies/pick_first.c',
'src/core/client_config/lb_policies/round_robin.c',
'src/core/client_config/lb_policy.c',
'src/core/client_config/lb_policy_factory.c',
'src/core/client_config/lb_policy_registry.c',
'src/core/client_config/resolver.c',
'src/core/client_config/resolver_factory.c',
'src/core/client_config/resolver_registry.c',
'src/core/client_config/resolvers/dns_resolver.c',
'src/core/client_config/resolvers/sockaddr_resolver.c',
'src/core/client_config/subchannel.c',
'src/core/client_config/subchannel_factory.c',
'src/core/client_config/subchannel_factory_decorators/add_channel_arg.c',
'src/core/client_config/subchannel_factory_decorators/merge_channel_args.c',
'src/core/client_config/uri_parser.c',
'src/core/compression/algorithm.c',
'src/core/compression/message_compress.c',
'src/core/debug/trace.c',
'src/core/httpcli/format_request.c',
'src/core/httpcli/httpcli.c',
'src/core/httpcli/parser.c',
'src/core/iomgr/alarm.c',
'src/core/iomgr/alarm_heap.c',
'src/core/iomgr/closure.c',
'src/core/iomgr/endpoint.c',
'src/core/iomgr/endpoint_pair_posix.c',
'src/core/iomgr/endpoint_pair_windows.c',
'src/core/iomgr/exec_ctx.c',
'src/core/iomgr/executor.c',
'src/core/iomgr/fd_posix.c',
'src/core/iomgr/iocp_windows.c',
'src/core/iomgr/iomgr.c',
'src/core/iomgr/iomgr_posix.c',
'src/core/iomgr/iomgr_windows.c',
'src/core/iomgr/pollset_multipoller_with_epoll.c',
'src/core/iomgr/pollset_multipoller_with_poll_posix.c',
'src/core/iomgr/pollset_posix.c',
'src/core/iomgr/pollset_set_posix.c',
'src/core/iomgr/pollset_set_windows.c',
'src/core/iomgr/pollset_windows.c',
'src/core/iomgr/resolve_address_posix.c',
'src/core/iomgr/resolve_address_windows.c',
'src/core/iomgr/sockaddr_utils.c',
'src/core/iomgr/socket_utils_common_posix.c',
'src/core/iomgr/socket_utils_linux.c',
'src/core/iomgr/socket_utils_posix.c',
'src/core/iomgr/socket_windows.c',
'src/core/iomgr/tcp_client_posix.c',
'src/core/iomgr/tcp_client_windows.c',
'src/core/iomgr/tcp_posix.c',
'src/core/iomgr/tcp_server_posix.c',
'src/core/iomgr/tcp_server_windows.c',
'src/core/iomgr/tcp_windows.c',
'src/core/iomgr/time_averaged_stats.c',
'src/core/iomgr/udp_server.c',
'src/core/iomgr/wakeup_fd_eventfd.c',
'src/core/iomgr/wakeup_fd_nospecial.c',
'src/core/iomgr/wakeup_fd_pipe.c',
'src/core/iomgr/wakeup_fd_posix.c',
'src/core/iomgr/workqueue_posix.c',
'src/core/iomgr/workqueue_windows.c',
'src/core/json/json.c',
'src/core/json/json_reader.c',
'src/core/json/json_string.c',
'src/core/json/json_writer.c',
'src/core/profiling/basic_timers.c',
'src/core/profiling/stap_timers.c',
'src/core/surface/api_trace.c',
'src/core/surface/byte_buffer.c',
'src/core/surface/byte_buffer_queue.c',
'src/core/surface/byte_buffer_reader.c',
'src/core/surface/call.c',
'src/core/surface/call_details.c',
'src/core/surface/call_log_batch.c',
'src/core/surface/channel.c',
'src/core/surface/channel_connectivity.c',
'src/core/surface/channel_create.c',
'src/core/surface/completion_queue.c',
'src/core/surface/event_string.c',
'src/core/surface/init.c',
'src/core/surface/lame_client.c',
'src/core/surface/metadata_array.c',
'src/core/surface/server.c',
'src/core/surface/server_chttp2.c',
'src/core/surface/server_create.c',
'src/core/surface/version.c',
'src/core/transport/chttp2/alpn.c',
'src/core/transport/chttp2/bin_encoder.c',
'src/core/transport/chttp2/frame_data.c',
'src/core/transport/chttp2/frame_goaway.c',
'src/core/transport/chttp2/frame_ping.c',
'src/core/transport/chttp2/frame_rst_stream.c',
'src/core/transport/chttp2/frame_settings.c',
'src/core/transport/chttp2/frame_window_update.c',
'src/core/transport/chttp2/hpack_parser.c',
'src/core/transport/chttp2/hpack_table.c',
'src/core/transport/chttp2/huffsyms.c',
'src/core/transport/chttp2/incoming_metadata.c',
'src/core/transport/chttp2/parsing.c',
'src/core/transport/chttp2/status_conversion.c',
'src/core/transport/chttp2/stream_encoder.c',
'src/core/transport/chttp2/stream_lists.c',
'src/core/transport/chttp2/stream_map.c',
'src/core/transport/chttp2/timeout_encoding.c',
'src/core/transport/chttp2/varint.c',
'src/core/transport/chttp2/writing.c',
'src/core/transport/chttp2_transport.c',
'src/core/transport/connectivity_state.c',
'src/core/transport/metadata.c',
'src/core/transport/stream_op.c',
'src/core/transport/transport.c',
'src/core/transport/transport_op_string.c',
'src/core/census/context.c',
'src/core/census/initialize.c',
'src/core/census/operation.c',
'src/core/census/tracing.c',
],
},
]
}

@ -181,6 +181,7 @@
#ifndef _BSD_SOURCE
#define _BSD_SOURCE
#endif
#define GPR_FORBID_UNREACHABLE_CODE
#define GPR_MSG_IOVLEN_TYPE int
#if TARGET_OS_IPHONE
#define GPR_PLATFORM_STRING "ios"
@ -336,4 +337,15 @@ typedef uintptr_t gpr_uintptr;
#endif
#endif
#ifdef GPR_FORBID_UNREACHABLE_CODE
#define GPR_UNREACHABLE_CODE(STATEMENT)
#else
#define GPR_UNREACHABLE_CODE(STATEMENT) \
do { \
gpr_log(GPR_ERROR, "Should never reach here."); \
abort(); \
STATEMENT; \
} while (0)
#endif /* GPR_FORBID_UNREACHABLE_CODE */
#endif /* GRPC_SUPPORT_PORT_PLATFORM_H */

@ -19,7 +19,7 @@
"lib": "src/node/src"
},
"scripts": {
"lint": "node ./node_modules/jshint/bin/jshint src/node/src src/node/test src/node/examples src/node/interop src/node/index.js",
"lint": "node ./node_modules/jshint/bin/jshint src/node/src src/node/test src/node/interop src/node/index.js",
"test": "./node_modules/.bin/mocha src/node/test && npm run-script lint",
"gen_docs": "./node_modules/.bin/jsdoc -c src/node/jsdoc_conf.json",
"coverage": "./node_modules/.bin/istanbul cover ./node_modules/.bin/_mocha src/node/test"
@ -53,7 +53,6 @@
"src/core",
"test/proto",
"include",
"grpc.gyp",
"binding.gyp"
],
"main": "src/node/index.js",

@ -196,13 +196,12 @@ static int is_empty(void *p, int len) {
return 1;
}
static void started_call(grpc_exec_ctx *exec_ctx, void *arg,
int iomgr_success) {
static void started_call_locked(grpc_exec_ctx *exec_ctx, void *arg,
int iomgr_success) {
call_data *calld = arg;
grpc_transport_stream_op op;
int have_waiting;
gpr_mu_lock(&calld->mu_state);
if (calld->state == CALL_CANCELLED && calld->subchannel_call != NULL) {
memset(&op, 0, sizeof(op));
op.cancel_with_status = GRPC_STATUS_CANCELLED;
@ -230,10 +229,18 @@ static void started_call(grpc_exec_ctx *exec_ctx, void *arg,
}
}
static void started_call(grpc_exec_ctx *exec_ctx, void *arg,
int iomgr_success) {
call_data *calld = arg;
gpr_mu_lock(&calld->mu_state);
started_call_locked(exec_ctx, arg, iomgr_success);
}
static void picked_target(grpc_exec_ctx *exec_ctx, void *arg,
int iomgr_success) {
call_data *calld = arg;
grpc_pollset *pollset;
grpc_subchannel_call_create_status call_creation_status;
if (calld->picked_channel == NULL) {
/* treat this like a cancellation */
@ -248,11 +255,15 @@ static void picked_target(grpc_exec_ctx *exec_ctx, void *arg,
GPR_ASSERT(calld->state == CALL_WAITING_FOR_PICK);
calld->state = CALL_WAITING_FOR_CALL;
pollset = calld->waiting_op.bind_pollset;
gpr_mu_unlock(&calld->mu_state);
grpc_closure_init(&calld->async_setup_task, started_call, calld);
grpc_subchannel_create_call(exec_ctx, calld->picked_channel, pollset,
&calld->subchannel_call,
&calld->async_setup_task);
call_creation_status = grpc_subchannel_create_call(
exec_ctx, calld->picked_channel, pollset, &calld->subchannel_call,
&calld->async_setup_task);
if (call_creation_status == GRPC_SUBCHANNEL_CALL_CREATE_READY) {
started_call_locked(exec_ctx, calld, iomgr_success);
} else {
gpr_mu_unlock(&calld->mu_state);
}
}
}
}
@ -645,9 +656,7 @@ static void destroy_call_elem(grpc_exec_ctx *exec_ctx,
case CALL_WAITING_FOR_CONFIG:
case CALL_WAITING_FOR_CALL:
case CALL_WAITING_FOR_SEND:
gpr_log(GPR_ERROR, "should never reach here");
abort();
break;
GPR_UNREACHABLE_CODE(return );
}
}

@ -242,7 +242,7 @@ static void process_send_ops(grpc_call_element *elem,
GPR_ASSERT(calld->remaining_slice_bytes > 0);
/* Increase input ref count, gpr_slice_buffer_add takes ownership. */
gpr_slice_buffer_add(&calld->slices, gpr_slice_ref(sop->data.slice));
GPR_ASSERT(GPR_SLICE_LENGTH(sop->data.slice) >=
GPR_ASSERT(GPR_SLICE_LENGTH(sop->data.slice) <=
calld->remaining_slice_bytes);
calld->remaining_slice_bytes -=
(gpr_uint32)GPR_SLICE_LENGTH(sop->data.slice);

@ -335,18 +335,20 @@ static void start_connect(grpc_exec_ctx *exec_ctx, grpc_subchannel *c) {
static void continue_creating_call(grpc_exec_ctx *exec_ctx, void *arg,
int iomgr_success) {
grpc_subchannel_call_create_status call_creation_status;
waiting_for_connect *w4c = arg;
grpc_subchannel_del_interested_party(exec_ctx, w4c->subchannel, w4c->pollset);
grpc_subchannel_create_call(exec_ctx, w4c->subchannel, w4c->pollset,
w4c->target, w4c->notify);
call_creation_status = grpc_subchannel_create_call(
exec_ctx, w4c->subchannel, w4c->pollset, w4c->target, w4c->notify);
GPR_ASSERT(call_creation_status == GRPC_SUBCHANNEL_CALL_CREATE_READY);
w4c->notify->cb(exec_ctx, w4c->notify->cb_arg, iomgr_success);
GRPC_SUBCHANNEL_UNREF(exec_ctx, w4c->subchannel, "waiting_for_connect");
gpr_free(w4c);
}
void grpc_subchannel_create_call(grpc_exec_ctx *exec_ctx, grpc_subchannel *c,
grpc_pollset *pollset,
grpc_subchannel_call **target,
grpc_closure *notify) {
grpc_subchannel_call_create_status grpc_subchannel_create_call(
grpc_exec_ctx *exec_ctx, grpc_subchannel *c, grpc_pollset *pollset,
grpc_subchannel_call **target, grpc_closure *notify) {
connection *con;
gpr_mu_lock(&c->mu);
if (c->active != NULL) {
@ -355,7 +357,7 @@ void grpc_subchannel_create_call(grpc_exec_ctx *exec_ctx, grpc_subchannel *c,
gpr_mu_unlock(&c->mu);
*target = create_call(exec_ctx, con);
notify->cb(exec_ctx, notify->cb_arg, 1);
return GRPC_SUBCHANNEL_CALL_CREATE_READY;
} else {
waiting_for_connect *w4c = gpr_malloc(sizeof(*w4c));
w4c->next = c->waiting;
@ -380,6 +382,7 @@ void grpc_subchannel_create_call(grpc_exec_ctx *exec_ctx, grpc_subchannel *c,
} else {
gpr_mu_unlock(&c->mu);
}
return GRPC_SUBCHANNEL_CALL_CREATE_PENDING;
}
}

@ -75,12 +75,22 @@ void grpc_subchannel_call_unref(grpc_exec_ctx *exec_ctx,
grpc_subchannel_call *call
GRPC_SUBCHANNEL_REF_EXTRA_ARGS);
/** construct a call (possibly asynchronously) */
void grpc_subchannel_create_call(grpc_exec_ctx *exec_ctx,
grpc_subchannel *subchannel,
grpc_pollset *pollset,
grpc_subchannel_call **target,
grpc_closure *notify);
typedef enum {
GRPC_SUBCHANNEL_CALL_CREATE_READY,
GRPC_SUBCHANNEL_CALL_CREATE_PENDING
} grpc_subchannel_call_create_status;
/** construct a subchannel call (possibly asynchronously).
*
* If the returned status is \a GRPC_SUBCHANNEL_CALL_CREATE_READY, the call will
* return immediately and \a target will point to a connected \a subchannel_call
* instance. Note that \a notify will \em not be invoked in this case.
* Otherwise, if the returned status is GRPC_SUBCHANNEL_CALL_CREATE_PENDING, the
* subchannel call will be created asynchronously, invoking the \a notify
* callback upon completion. */
grpc_subchannel_call_create_status grpc_subchannel_create_call(
grpc_exec_ctx *exec_ctx, grpc_subchannel *subchannel, grpc_pollset *pollset,
grpc_subchannel_call **target, grpc_closure *notify);
/** process a transport level op */
void grpc_subchannel_process_transport_op(grpc_exec_ctx *exec_ctx,

@ -37,6 +37,7 @@
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/port_platform.h>
#include <grpc/support/string_util.h>
/** a size_t default value... maps to all 1's */
@ -120,8 +121,7 @@ static int parse_fragment_or_query(const char *uri_text, size_t *i) {
} else {
return 1;
}
gpr_log(GPR_ERROR, "should never reach here");
abort();
GPR_UNREACHABLE_CODE(return 0);
default:
(*i) += advance;
break;

@ -101,6 +101,7 @@ grpc_compression_algorithm grpc_compression_algorithm_for_level(
default:
/* we shouldn't be making it here */
abort();
return GRPC_COMPRESS_NONE;
}
}
@ -116,6 +117,7 @@ grpc_compression_level grpc_compression_level_for_algorithm(
}
}
abort();
return GRPC_COMPRESS_LEVEL_NONE;
}
void grpc_compression_options_init(grpc_compression_options *opts) {

@ -139,8 +139,7 @@ static int finish_line(grpc_httpcli_parser *parser) {
}
break;
case GRPC_HTTPCLI_BODY:
gpr_log(GPR_ERROR, "should never reach here");
abort();
GPR_UNREACHABLE_CODE(return 0);
}
parser->cur_line_length = 0;
@ -165,8 +164,7 @@ static int addbyte(grpc_httpcli_parser *parser, gpr_uint8 byte) {
} else {
return 1;
}
gpr_log(GPR_ERROR, "should never reach here");
abort();
GPR_UNREACHABLE_CODE(return 0);
case GRPC_HTTPCLI_BODY:
if (parser->r.body_length == parser->body_capacity) {
parser->body_capacity = GPR_MAX(8, parser->body_capacity * 3 / 2);
@ -177,10 +175,7 @@ static int addbyte(grpc_httpcli_parser *parser, gpr_uint8 byte) {
parser->r.body_length++;
return 1;
}
gpr_log(GPR_ERROR, "should never reach here");
abort();
return 0;
GPR_UNREACHABLE_CODE(return 0);
}
void grpc_httpcli_parser_init(grpc_httpcli_parser *parser) {

@ -286,7 +286,7 @@ static void set_ready(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_closure **st) {
void grpc_fd_shutdown(grpc_exec_ctx *exec_ctx, grpc_fd *fd) {
gpr_mu_lock(&fd->mu);
GPR_ASSERT(!gpr_atm_no_barrier_load(&fd->shutdown));
GPR_ASSERT(!fd->shutdown);
fd->shutdown = 1;
set_ready_locked(exec_ctx, fd, &fd->read_closure);
set_ready_locked(exec_ctx, fd, &fd->write_closure);
@ -320,7 +320,7 @@ gpr_uint32 grpc_fd_begin_poll(grpc_fd *fd, grpc_pollset *pollset,
gpr_mu_lock(&fd->mu);
/* if we are shutdown, then don't add to the watcher set */
if (gpr_atm_no_barrier_load(&fd->shutdown)) {
if (fd->shutdown) {
watcher->fd = NULL;
watcher->pollset = NULL;
watcher->worker = NULL;

@ -191,7 +191,7 @@ static void on_writable(grpc_exec_ctx *exec_ctx, void *acp, int success) {
goto finish;
}
abort();
GPR_UNREACHABLE_CODE(return );
finish:
if (fd != NULL) {

@ -352,7 +352,7 @@ static void on_read(grpc_exec_ctx *exec_ctx, void *arg, int success) {
gpr_free(addr_str);
}
abort();
GPR_UNREACHABLE_CODE(return );
error:
gpr_mu_lock(&sp->server->mu);

@ -181,6 +181,48 @@ void grpc_server_credentials_set_auth_metadata_processor(
creds->processor = processor;
}
static void server_credentials_pointer_arg_destroy(void *p) {
grpc_server_credentials_unref(p);
}
static void *server_credentials_pointer_arg_copy(void *p) {
return grpc_server_credentials_ref(p);
}
grpc_arg grpc_server_credentials_to_arg(grpc_server_credentials *p) {
grpc_arg arg;
memset(&arg, 0, sizeof(grpc_arg));
arg.type = GRPC_ARG_POINTER;
arg.key = GRPC_SERVER_CREDENTIALS_ARG;
arg.value.pointer.p = p;
arg.value.pointer.copy = server_credentials_pointer_arg_copy;
arg.value.pointer.destroy = server_credentials_pointer_arg_destroy;
return arg;
}
grpc_server_credentials *grpc_server_credentials_from_arg(
const grpc_arg *arg) {
if (strcmp(arg->key, GRPC_SERVER_CREDENTIALS_ARG) != 0) return NULL;
if (arg->type != GRPC_ARG_POINTER) {
gpr_log(GPR_ERROR, "Invalid type %d for arg %s", arg->type,
GRPC_SERVER_CREDENTIALS_ARG);
return NULL;
}
return arg->value.pointer.p;
}
grpc_server_credentials *grpc_find_server_credentials_in_args(
const grpc_channel_args *args) {
size_t i;
if (args == NULL) return NULL;
for (i = 0; i < args->num_args; i++) {
grpc_server_credentials *p =
grpc_server_credentials_from_arg(&args->args[i]);
if (p != NULL) return p;
}
return NULL;
}
/* -- Ssl credentials. -- */
static void ssl_destruct(grpc_credentials *creds) {

@ -215,7 +215,6 @@ typedef struct {
grpc_server_credentials *c, grpc_security_connector **sc);
} grpc_server_credentials_vtable;
/* TODO(jboeuf): Add a refcount. */
struct grpc_server_credentials {
const grpc_server_credentials_vtable *vtable;
const char *type;
@ -231,6 +230,13 @@ grpc_server_credentials *grpc_server_credentials_ref(
void grpc_server_credentials_unref(grpc_server_credentials *creds);
#define GRPC_SERVER_CREDENTIALS_ARG "grpc.server_credentials"
grpc_arg grpc_server_credentials_to_arg(grpc_server_credentials *c);
grpc_server_credentials *grpc_server_credentials_from_arg(const grpc_arg *arg);
grpc_server_credentials *grpc_find_server_credentials_in_args(
const grpc_channel_args *args);
/* -- Ssl credentials. -- */
typedef struct {

@ -305,33 +305,43 @@ void grpc_auth_property_reset(grpc_auth_property *property) {
memset(property, 0, sizeof(grpc_auth_property));
}
grpc_arg grpc_auth_metadata_processor_to_arg(grpc_auth_metadata_processor *p) {
static void auth_context_pointer_arg_destroy(void *p) {
GRPC_AUTH_CONTEXT_UNREF(p, "auth_context_pointer_arg");
}
static void *auth_context_pointer_arg_copy(void *p) {
return GRPC_AUTH_CONTEXT_REF(p, "auth_context_pointer_arg");
}
grpc_arg grpc_auth_context_to_arg(grpc_auth_context *p) {
grpc_arg arg;
memset(&arg, 0, sizeof(grpc_arg));
arg.type = GRPC_ARG_POINTER;
arg.key = GRPC_AUTH_METADATA_PROCESSOR_ARG;
arg.key = GRPC_AUTH_CONTEXT_ARG;
arg.value.pointer.p = p;
arg.value.pointer.copy = auth_context_pointer_arg_copy;
arg.value.pointer.destroy = auth_context_pointer_arg_destroy;
return arg;
}
grpc_auth_metadata_processor *grpc_auth_metadata_processor_from_arg(
grpc_auth_context *grpc_auth_context_from_arg(
const grpc_arg *arg) {
if (strcmp(arg->key, GRPC_AUTH_METADATA_PROCESSOR_ARG) != 0) return NULL;
if (strcmp(arg->key, GRPC_AUTH_CONTEXT_ARG) != 0) return NULL;
if (arg->type != GRPC_ARG_POINTER) {
gpr_log(GPR_ERROR, "Invalid type %d for arg %s", arg->type,
GRPC_AUTH_METADATA_PROCESSOR_ARG);
GRPC_AUTH_CONTEXT_ARG);
return NULL;
}
return arg->value.pointer.p;
}
grpc_auth_metadata_processor *grpc_find_auth_metadata_processor_in_args(
grpc_auth_context *grpc_find_auth_context_in_args(
const grpc_channel_args *args) {
size_t i;
if (args == NULL) return NULL;
for (i = 0; i < args->num_args; i++) {
grpc_auth_metadata_processor *p =
grpc_auth_metadata_processor_from_arg(&args->args[i]);
grpc_auth_context *p =
grpc_auth_context_from_arg(&args->args[i]);
if (p != NULL) return p;
}
return NULL;

@ -103,13 +103,12 @@ typedef struct {
grpc_server_security_context *grpc_server_security_context_create(void);
void grpc_server_security_context_destroy(void *ctx);
/* --- Auth metadata processing. --- */
#define GRPC_AUTH_METADATA_PROCESSOR_ARG "grpc.auth_metadata_processor"
/* --- Channel args for auth context --- */
#define GRPC_AUTH_CONTEXT_ARG "grpc.auth_context"
grpc_arg grpc_auth_metadata_processor_to_arg(grpc_auth_metadata_processor *p);
grpc_auth_metadata_processor *grpc_auth_metadata_processor_from_arg(
const grpc_arg *arg);
grpc_auth_metadata_processor *grpc_find_auth_metadata_processor_in_args(
grpc_arg grpc_auth_context_to_arg(grpc_auth_context *c);
grpc_auth_context *grpc_auth_context_from_arg(const grpc_arg *arg);
grpc_auth_context *grpc_find_auth_context_in_args(
const grpc_channel_args *args);
#endif /* GRPC_INTERNAL_CORE_SECURITY_SECURITY_CONTEXT_H */

@ -34,7 +34,7 @@
#include <string.h>
#include "src/core/security/auth_filters.h"
#include "src/core/security/security_connector.h"
#include "src/core/security/credentials.h"
#include "src/core/security/security_context.h"
#include <grpc/support/alloc.h>
@ -58,8 +58,8 @@ typedef struct call_data {
} call_data;
typedef struct channel_data {
grpc_security_connector *security_connector;
grpc_auth_metadata_processor processor;
grpc_auth_context *auth_context;
grpc_server_credentials *creds;
grpc_mdctx *mdctx;
} channel_data;
@ -160,12 +160,12 @@ static void auth_on_recv(grpc_exec_ctx *exec_ctx, void *user_data,
grpc_stream_op *op = &ops[i];
if (op->type != GRPC_OP_METADATA || calld->got_client_metadata) continue;
calld->got_client_metadata = 1;
if (chand->processor.process == NULL) continue;
if (chand->creds->processor.process == NULL) continue;
calld->md_op = op;
calld->md = metadata_batch_to_md_array(&op->data.metadata);
chand->processor.process(chand->processor.state, calld->auth_context,
calld->md.metadata, calld->md.count,
on_md_processing_done, elem);
chand->creds->processor.process(
chand->creds->processor.state, calld->auth_context,
calld->md.metadata, calld->md.count, on_md_processing_done, elem);
return;
}
}
@ -221,7 +221,7 @@ static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
}
server_ctx = grpc_server_security_context_create();
server_ctx->auth_context =
grpc_auth_context_create(chand->security_connector->auth_context);
grpc_auth_context_create(chand->auth_context);
server_ctx->auth_context->pollset = initial_op->bind_pollset;
initial_op->context[GRPC_CONTEXT_SECURITY].value = server_ctx;
initial_op->context[GRPC_CONTEXT_SECURITY].destroy =
@ -241,9 +241,8 @@ static void init_channel_elem(grpc_exec_ctx *exec_ctx,
grpc_channel_element *elem, grpc_channel *master,
const grpc_channel_args *args, grpc_mdctx *mdctx,
int is_first, int is_last) {
grpc_security_connector *sc = grpc_find_security_connector_in_args(args);
grpc_auth_metadata_processor *processor =
grpc_find_auth_metadata_processor_in_args(args);
grpc_auth_context *auth_context = grpc_find_auth_context_in_args(args);
grpc_server_credentials *creds = grpc_find_server_credentials_in_args(args);
/* grab pointers to our data from the channel element */
channel_data *chand = elem->channel_data;
@ -252,15 +251,14 @@ static void init_channel_elem(grpc_exec_ctx *exec_ctx,
path */
GPR_ASSERT(!is_first);
GPR_ASSERT(!is_last);
GPR_ASSERT(sc != NULL);
GPR_ASSERT(processor != NULL);
GPR_ASSERT(auth_context != NULL);
GPR_ASSERT(creds != NULL);
/* initialize members */
GPR_ASSERT(!sc->is_client_side);
chand->security_connector =
GRPC_SECURITY_CONNECTOR_REF(sc, "server_auth_filter");
chand->auth_context =
GRPC_AUTH_CONTEXT_REF(auth_context, "server_auth_filter");
chand->creds = grpc_server_credentials_ref(creds);
chand->mdctx = mdctx;
chand->processor = *processor;
}
/* Destructor for channel data */
@ -268,8 +266,8 @@ static void destroy_channel_elem(grpc_exec_ctx *exec_ctx,
grpc_channel_element *elem) {
/* grab pointers to our data from the channel element */
channel_data *chand = elem->channel_data;
GRPC_SECURITY_CONNECTOR_UNREF(chand->security_connector,
"server_auth_filter");
GRPC_AUTH_CONTEXT_UNREF(chand->auth_context, "server_auth_filter");
grpc_server_credentials_unref(chand->creds);
}
const grpc_channel_filter grpc_server_auth_filter = {

@ -93,9 +93,9 @@ static void setup_transport(grpc_exec_ctx *exec_ctx, void *statep,
grpc_server_secure_state *state = statep;
grpc_channel_args *args_copy;
grpc_arg args_to_add[2];
args_to_add[0] = grpc_security_connector_to_arg(state->sc);
args_to_add[0] = grpc_server_credentials_to_arg(state->creds);
args_to_add[1] =
grpc_auth_metadata_processor_to_arg(&state->creds->processor);
grpc_auth_context_to_arg(state->sc->auth_context);
args_copy = grpc_channel_args_copy_and_add(
grpc_server_get_channel_args(state->server), args_to_add,
GPR_ARRAY_SIZE(args_to_add));

@ -75,9 +75,7 @@ grpc_byte_buffer *grpc_byte_buffer_copy(grpc_byte_buffer *bb) {
return grpc_raw_byte_buffer_create(bb->data.raw.slice_buffer.slices,
bb->data.raw.slice_buffer.count);
}
gpr_log(GPR_INFO, "should never get here");
abort();
return NULL;
GPR_UNREACHABLE_CODE(return NULL);
}
void grpc_byte_buffer_destroy(grpc_byte_buffer *bb) {
@ -95,6 +93,5 @@ size_t grpc_byte_buffer_length(grpc_byte_buffer *bb) {
case GRPC_BB_RAW:
return bb->data.raw.slice_buffer.length;
}
gpr_log(GPR_ERROR, "should never reach here");
abort();
GPR_UNREACHABLE_CODE(return 0);
}

@ -434,8 +434,8 @@ static grpc_cq_completion *allocate_completion(grpc_call *call) {
gpr_mu_unlock(&call->completion_mu);
return &call->completions[i];
}
gpr_log(GPR_ERROR, "should never reach here");
abort();
GPR_UNREACHABLE_CODE(return NULL);
return NULL;
}
static void done_completion(grpc_exec_ctx *exec_ctx, void *call,
@ -526,9 +526,13 @@ static void set_compression_algorithm(grpc_call *call,
call->compression_algorithm = algo;
}
grpc_compression_algorithm grpc_call_get_compression_algorithm(
const grpc_call *call) {
return call->compression_algorithm;
grpc_compression_algorithm grpc_call_test_only_get_compression_algorithm(
grpc_call *call) {
grpc_compression_algorithm algorithm;
gpr_mu_lock(&call->mu);
algorithm = call->compression_algorithm;
gpr_mu_unlock(&call->mu);
return algorithm;
}
static void set_encodings_accepted_by_peer(
@ -562,12 +566,20 @@ static void set_encodings_accepted_by_peer(
}
}
gpr_uint32 grpc_call_get_encodings_accepted_by_peer(grpc_call *call) {
return call->encodings_accepted_by_peer;
gpr_uint32 grpc_call_test_only_get_encodings_accepted_by_peer(grpc_call *call) {
gpr_uint32 encodings_accepted_by_peer;
gpr_mu_lock(&call->mu);
encodings_accepted_by_peer = call->encodings_accepted_by_peer;
gpr_mu_unlock(&call->mu);
return encodings_accepted_by_peer;
}
gpr_uint32 grpc_call_get_message_flags(const grpc_call *call) {
return call->incoming_message_flags;
gpr_uint32 grpc_call_test_only_get_message_flags(grpc_call *call) {
gpr_uint32 flags;
gpr_mu_lock(&call->mu);
flags = call->incoming_message_flags;
gpr_mu_unlock(&call->mu);
return flags;
}
static void set_status_details(grpc_call *call, status_source source,

@ -169,17 +169,6 @@ void *grpc_call_context_get(grpc_call *call, grpc_context_index elem);
gpr_uint8 grpc_call_is_client(grpc_call *call);
grpc_compression_algorithm grpc_call_get_compression_algorithm(
const grpc_call *call);
gpr_uint32 grpc_call_get_message_flags(const grpc_call *call);
/** Returns a bitset for the encodings (compression algorithms) supported by \a
* call's peer.
*
* To be indexed by grpc_compression_algorithm enum values. */
gpr_uint32 grpc_call_get_encodings_accepted_by_peer(grpc_call *call);
#ifdef __cplusplus
}
#endif

@ -0,0 +1,65 @@
/*
*
* 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 GRPC_INTERNAL_CORE_SURFACE_CALL_TEST_ONLY_H
#define GRPC_INTERNAL_CORE_SURFACE_CALL_TEST_ONLY_H
#include <grpc/grpc.h>
#ifdef __cplusplus
extern "C" {
#endif
/** Return the compression algorithm from \a call.
*
* \warning This function should \b only be used in test code. */
grpc_compression_algorithm grpc_call_test_only_get_compression_algorithm(
grpc_call *call);
/** Return the message flags from \a call.
*
* \warning This function should \b only be used in test code. */
gpr_uint32 grpc_call_test_only_get_message_flags(grpc_call *call);
/** Returns a bitset for the encodings (compression algorithms) supported by \a
* call's peer.
*
* To be indexed by grpc_compression_algorithm enum values. */
gpr_uint32 grpc_call_test_only_get_encodings_accepted_by_peer(grpc_call *call);
#ifdef __cplusplus
}
#endif
#endif /* GRPC_INTERNAL_CORE_SURFACE_CALL_TEST_ONLY_H */

@ -100,9 +100,7 @@ static void finished_completion(grpc_exec_ctx *exec_ctx, void *pw,
switch (w->phase) {
case WAITING:
case CALLED_BACK:
gpr_log(GPR_ERROR, "should never reach here");
abort();
break;
GPR_UNREACHABLE_CODE(return );
case CALLING_BACK:
w->phase = CALLED_BACK;
break;
@ -149,9 +147,7 @@ static void partly_done(grpc_exec_ctx *exec_ctx, state_watcher *w,
w->phase = CALLING_BACK_AND_FINISHED;
break;
case CALLING_BACK_AND_FINISHED:
gpr_log(GPR_ERROR, "should never reach here");
abort();
break;
GPR_UNREACHABLE_CODE(return );
case CALLED_BACK:
delete = 1;
break;

@ -254,8 +254,7 @@ static void del_plucker(grpc_completion_queue *cc, void *tag,
return;
}
}
gpr_log(GPR_ERROR, "should never reach here");
abort();
GPR_UNREACHABLE_CODE(return );
}
grpc_event grpc_completion_queue_pluck(grpc_completion_queue *cc, void *tag,

@ -168,7 +168,5 @@ grpc_chttp2_parse_error grpc_chttp2_data_parser_parse(
}
}
gpr_log(GPR_ERROR, "should never reach here");
abort();
return GRPC_CHTTP2_CONNECTION_ERROR;
GPR_UNREACHABLE_CODE(return GRPC_CHTTP2_CONNECTION_ERROR);
}

@ -152,9 +152,7 @@ grpc_chttp2_parse_error grpc_chttp2_goaway_parser_parse(
}
return GRPC_CHTTP2_PARSE_OK;
}
gpr_log(GPR_ERROR, "Should never end up here");
abort();
return GRPC_CHTTP2_CONNECTION_ERROR;
GPR_UNREACHABLE_CODE(return GRPC_CHTTP2_CONNECTION_ERROR);
}
void grpc_chttp2_goaway_append(gpr_uint32 last_stream_id, gpr_uint32 error_code,

@ -1166,9 +1166,7 @@ static int append_string(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur,
append_bytes(str, decoded, 3);
goto b64_byte0;
}
gpr_log(GPR_ERROR, "should never reach here");
abort();
return 1;
GPR_UNREACHABLE_CODE(return 1);
}
/* append a null terminator to a string */
@ -1313,9 +1311,7 @@ static int parse_value_string(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur,
return 0;
}
/* Add code to prevent return without value error */
gpr_log(GPR_ERROR, "Should never reach beyond switch in parse_value_string");
abort();
return 0;
GPR_UNREACHABLE_CODE(return 0);
}
static int parse_value_string_with_indexed_key(grpc_chttp2_hpack_parser *p,

@ -417,14 +417,10 @@ int grpc_chttp2_perform_read(grpc_exec_ctx *exec_ctx,
transport_parsing->incoming_frame_size -= (gpr_uint32)(end - cur);
return 1;
}
gpr_log(GPR_ERROR, "should never reach here");
abort();
GPR_UNREACHABLE_CODE(return 0);
}
gpr_log(GPR_ERROR, "should never reach here");
abort();
return 0;
GPR_UNREACHABLE_CODE(return 0);
}
static int init_frame_parser(grpc_chttp2_transport_parsing *transport_parsing) {
@ -580,9 +576,7 @@ static int init_data_frame_parser(
case GRPC_CHTTP2_CONNECTION_ERROR:
return 0;
}
gpr_log(GPR_ERROR, "should never reach here");
abort();
return 0;
GPR_UNREACHABLE_CODE(return 0);
}
static void free_timeout(void *p) { gpr_free(p); }
@ -820,7 +814,5 @@ static int parse_frame_slice(grpc_exec_ctx *exec_ctx,
case GRPC_CHTTP2_CONNECTION_ERROR:
return 0;
}
gpr_log(GPR_ERROR, "should never reach here");
abort();
return 0;
GPR_UNREACHABLE_CODE(return 0);
}

@ -428,7 +428,7 @@ static grpc_mdelem *hpack_enc(grpc_chttp2_hpack_compressor *c,
emit_lithdr_noidx(c, dynidx(c, indices_key), elem, st);
return elem;
}
abort();
GPR_UNREACHABLE_CODE(return NULL);
}
indices_key = c->indices_keys[HASH_FRAGMENT_3(key_hash)];
@ -442,7 +442,7 @@ static grpc_mdelem *hpack_enc(grpc_chttp2_hpack_compressor *c,
emit_lithdr_noidx(c, dynidx(c, indices_key), elem, st);
return elem;
}
abort();
GPR_UNREACHABLE_CODE(return NULL);
}
/* no elem, key in the table... fall back to literal emission */
@ -454,7 +454,7 @@ static grpc_mdelem *hpack_enc(grpc_chttp2_hpack_compressor *c,
emit_lithdr_noidx_v(c, elem, st);
return elem;
}
abort();
GPR_UNREACHABLE_CODE(return NULL);
}
#define STRLEN_LIT(x) (sizeof(x) - 1)

@ -319,8 +319,9 @@ static tsi_result peer_from_x509(X509 *cert, int include_certificate_type,
/* TODO(jboeuf): Maybe add more properties. */
GENERAL_NAMES *subject_alt_names =
X509_get_ext_d2i(cert, NID_subject_alt_name, 0, 0);
int subject_alt_name_count =
(subject_alt_names != NULL) ? sk_GENERAL_NAME_num(subject_alt_names) : 0;
int subject_alt_name_count = (subject_alt_names != NULL)
? (int)sk_GENERAL_NAME_num(subject_alt_names)
: 0;
size_t property_count;
tsi_result result;
GPR_ASSERT(subject_alt_name_count >= 0);
@ -358,7 +359,7 @@ static void log_ssl_error_stack(void) {
unsigned long err;
while ((err = ERR_get_error()) != 0) {
char details[256];
ERR_error_string_n(err, details, sizeof(details));
ERR_error_string_n((uint32_t)err, details, sizeof(details));
gpr_log(GPR_ERROR, "%s", details);
}
}
@ -668,7 +669,7 @@ static tsi_result ssl_protector_protect(tsi_frame_protector *self,
tsi_result result = TSI_OK;
/* First see if we have some pending data in the SSL BIO. */
int pending_in_ssl = BIO_pending(impl->from_ssl);
int pending_in_ssl = (int)BIO_pending(impl->from_ssl);
if (pending_in_ssl > 0) {
*unprotected_bytes_size = 0;
GPR_ASSERT(*protected_output_frames_size <= INT_MAX);
@ -726,7 +727,7 @@ static tsi_result ssl_protector_protect_flush(
impl->buffer_offset = 0;
}
pending = BIO_pending(impl->from_ssl);
pending = (int)BIO_pending(impl->from_ssl);
GPR_ASSERT(pending >= 0);
*still_pending_size = (size_t)pending;
if (*still_pending_size == 0) return TSI_OK;
@ -739,7 +740,7 @@ static tsi_result ssl_protector_protect_flush(
return TSI_INTERNAL_ERROR;
}
*protected_output_frames_size = (size_t)read_from_ssl;
pending = BIO_pending(impl->from_ssl);
pending = (int)BIO_pending(impl->from_ssl);
GPR_ASSERT(pending >= 0);
*still_pending_size = (size_t)pending;
return TSI_OK;

@ -153,8 +153,7 @@ class Server::SyncRequest GRPC_FINAL : public CompletionQueueTag {
GPR_ASSERT((*req)->in_flight_);
return true;
}
gpr_log(GPR_ERROR, "Should never reach here");
abort();
GPR_UNREACHABLE_CODE(return false);
}
void SetupRequest() { cq_ = grpc_completion_queue_create(nullptr); }

@ -41,8 +41,8 @@ using Grpc.Core.Utils;
namespace Grpc.Auth
{
/// <summary>
/// Factory methods to create authorization interceptors. Interceptors created can be registered with gRPC client classes (autogenerated client stubs that
/// inherit from <see cref="Grpc.Core.ClientBase"/>).
/// Factory methods to create authorization interceptors.
/// <seealso cref="GrpcCredentials"/>
/// </summary>
public static class AuthInterceptors
{
@ -50,31 +50,29 @@ namespace Grpc.Auth
private const string Schema = "Bearer";
/// <summary>
/// Creates interceptor that will obtain access token from any credential type that implements
/// Creates an <see cref="AsyncAuthInterceptor"/> that will obtain access token from any credential type that implements
/// <c>ITokenAccess</c>. (e.g. <c>GoogleCredential</c>).
/// </summary>
/// <param name="credential">The credential to use to obtain access tokens.</param>
/// <returns>The header interceptor.</returns>
public static HeaderInterceptor FromCredential(ITokenAccess credential)
/// <returns>The interceptor.</returns>
public static AsyncAuthInterceptor FromCredential(ITokenAccess credential)
{
return new HeaderInterceptor((method, authUri, metadata) =>
return new AsyncAuthInterceptor(async (authUri, metadata) =>
{
// TODO(jtattermusch): Rethink synchronous wait to obtain the result.
var accessToken = credential.GetAccessTokenForRequestAsync(authUri, CancellationToken.None)
.ConfigureAwait(false).GetAwaiter().GetResult();
var accessToken = await credential.GetAccessTokenForRequestAsync(authUri, CancellationToken.None).ConfigureAwait(false);
metadata.Add(CreateBearerTokenHeader(accessToken));
});
}
/// <summary>
/// Creates OAuth2 interceptor that will use given access token as authorization.
/// Creates an <see cref="AsyncAuthInterceptor"/> that will use given access token as authorization.
/// </summary>
/// <param name="accessToken">OAuth2 access token.</param>
/// <returns>The header interceptor.</returns>
public static HeaderInterceptor FromAccessToken(string accessToken)
/// <returns>The interceptor.</returns>
public static AsyncAuthInterceptor FromAccessToken(string accessToken)
{
Preconditions.CheckNotNull(accessToken);
return new HeaderInterceptor((method, authUri, metadata) =>
return new AsyncAuthInterceptor(async (authUri, metadata) =>
{
metadata.Add(CreateBearerTokenHeader(accessToken));
});

@ -78,6 +78,7 @@
<Compile Include="..\Grpc.Core\Version.cs">
<Link>Version.cs</Link>
</Compile>
<Compile Include="GrpcCredentials.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="AuthInterceptors.cs" />
</ItemGroup>

@ -0,0 +1,93 @@
#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.Threading;
using Google.Apis.Auth.OAuth2;
using Grpc.Core;
using Grpc.Core.Utils;
namespace Grpc.Auth
{
/// <summary>
/// Factory methods to create instances of <see cref="ChannelCredentials"/> and <see cref="CallCredentials"/> classes.
/// </summary>
public static class GrpcCredentials
{
/// <summary>
/// Creates a <see cref="MetadataCredentials"/> instance that will obtain access tokens
/// from any credential that implements <c>ITokenAccess</c>. (e.g. <c>GoogleCredential</c>).
/// </summary>
/// <param name="credential">The credential to use to obtain access tokens.</param>
/// <returns>The <c>MetadataCredentials</c> instance.</returns>
public static MetadataCredentials Create(ITokenAccess credential)
{
return new MetadataCredentials(AuthInterceptors.FromCredential(credential));
}
/// <summary>
/// Convenience method to create a <see cref="ChannelCredentials"/> instance from
/// <c>ITokenAccess</c> credential and <c>SslCredentials</c> instance.
/// </summary>
/// <param name="credential">The credential to use to obtain access tokens.</param>
/// <param name="sslCredentials">The <c>SslCredentials</c> instance.</param>
/// <returns>The channel credentials for access token based auth over a secure channel.</returns>
public static ChannelCredentials Create(ITokenAccess credential, SslCredentials sslCredentials)
{
return ChannelCredentials.Create(sslCredentials, Create(credential));
}
/// <summary>
/// Creates an instance of <see cref="MetadataCredentials"/> that will use given access token to authenticate
/// with a gRPC service.
/// </summary>
/// <param name="accessToken">OAuth2 access token.</param>
/// /// <returns>The <c>MetadataCredentials</c> instance.</returns>
public static MetadataCredentials FromAccessToken(string accessToken)
{
return new MetadataCredentials(AuthInterceptors.FromAccessToken(accessToken));
}
/// <summary>
/// Converts a <c>ITokenAccess</c> object into a <see cref="MetadataCredentials"/> object supported
/// by gRPC.
/// </summary>
/// <param name="credential"></param>
/// <returns></returns>
public static MetadataCredentials ToGrpcCredentials(this ITokenAccess credential)
{
return GrpcCredentials.Create(credential);
}
}
}

@ -32,6 +32,10 @@
#endregion
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;
@ -39,24 +43,23 @@ using NUnit.Framework;
namespace Grpc.Core.Tests
{
public class ClientBaseTest
public class CallCredentialsTest
{
[Test]
public void GetAuthUriBase_Valid()
public void CallCredentials_ComposeAtLeastTwo()
{
Assert.AreEqual("https://some.googleapi.com/", ClientBase.GetAuthUriBase("some.googleapi.com"));
Assert.AreEqual("https://some.googleapi.com/", ClientBase.GetAuthUriBase("dns:///some.googleapi.com/"));
Assert.AreEqual("https://some.googleapi.com/", ClientBase.GetAuthUriBase("dns:///some.googleapi.com:443/"));
Assert.AreEqual("https://some.googleapi.com/", ClientBase.GetAuthUriBase("some.googleapi.com:443/"));
Assert.Throws(typeof(ArgumentException), () => CallCredentials.Compose(new FakeCallCredentials()));
}
[Test]
public void GetAuthUriBase_Invalid()
public void CallCredentials_ToNativeCredentials()
{
Assert.IsNull(ClientBase.GetAuthUriBase("some.googleapi.com:"));
Assert.IsNull(ClientBase.GetAuthUriBase("https://some.googleapi.com/"));
Assert.IsNull(ClientBase.GetAuthUriBase("dns://some.googleapi.com:443")); // just two slashes
Assert.IsNull(ClientBase.GetAuthUriBase(""));
var composite = CallCredentials.Compose(
new MetadataCredentials(async (uri, m) => { await Task.Delay(1); }),
new MetadataCredentials(async (uri, m) => { await Task.Delay(2); }));
using (var nativeComposite = composite.ToNativeCredentials())
{
}
}
}
}

@ -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 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;
namespace Grpc.Core.Tests
{
public class ChannelCredentialsTest
{
[Test]
public void InsecureCredentials_IsNonComposable()
{
Assert.IsFalse(ChannelCredentials.Insecure.IsComposable);
}
[Test]
public void ChannelCredentials_CreateComposite()
{
var composite = ChannelCredentials.Create(new FakeChannelCredentials(true), new FakeCallCredentials());
Assert.IsFalse(composite.IsComposable);
Assert.Throws(typeof(ArgumentNullException), () => ChannelCredentials.Create(null, new FakeCallCredentials()));
Assert.Throws(typeof(ArgumentNullException), () => ChannelCredentials.Create(new FakeChannelCredentials(true), null));
// forbid composing non-composable
Assert.Throws(typeof(ArgumentException), () => ChannelCredentials.Create(new FakeChannelCredentials(false), new FakeCallCredentials()));
}
[Test]
public void ChannelCredentials_CreateWrapped()
{
ChannelCredentials.Create(new FakeCallCredentials());
}
}
}

@ -44,13 +44,13 @@ namespace Grpc.Core.Tests
[Test]
public void Constructor_RejectsInvalidParams()
{
Assert.Throws(typeof(ArgumentNullException), () => new Channel(null, Credentials.Insecure));
Assert.Throws(typeof(ArgumentNullException), () => new Channel(null, ChannelCredentials.Insecure));
}
[Test]
public void State_IdleAfterCreation()
{
var channel = new Channel("localhost", Credentials.Insecure);
var channel = new Channel("localhost", ChannelCredentials.Insecure);
Assert.AreEqual(ChannelState.Idle, channel.State);
channel.ShutdownAsync().Wait();
}
@ -58,7 +58,7 @@ namespace Grpc.Core.Tests
[Test]
public void WaitForStateChangedAsync_InvalidArgument()
{
var channel = new Channel("localhost", Credentials.Insecure);
var channel = new Channel("localhost", ChannelCredentials.Insecure);
Assert.Throws(typeof(ArgumentException), () => channel.WaitForStateChangedAsync(ChannelState.FatalFailure));
channel.ShutdownAsync().Wait();
}
@ -66,7 +66,7 @@ namespace Grpc.Core.Tests
[Test]
public void ResolvedTarget()
{
var channel = new Channel("127.0.0.1", Credentials.Insecure);
var channel = new Channel("127.0.0.1", ChannelCredentials.Insecure);
Assert.IsTrue(channel.ResolvedTarget.Contains("127.0.0.1"));
channel.ShutdownAsync().Wait();
}
@ -74,7 +74,7 @@ namespace Grpc.Core.Tests
[Test]
public void Shutdown_AllowedOnlyOnce()
{
var channel = new Channel("localhost", Credentials.Insecure);
var channel = new Channel("localhost", ChannelCredentials.Insecure);
channel.ShutdownAsync().Wait();
Assert.Throws(typeof(InvalidOperationException), () => channel.ShutdownAsync().GetAwaiter().GetResult());
}

@ -1,3 +1,4 @@
#region Copyright notice and license
// Copyright 2015, Google Inc.
// All rights reserved.
@ -28,16 +29,45 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
syntax = "proto3";
#endregion
package grpc.testing;
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;
// An empty message that you can re-use to avoid defining duplicated empty
// messages in your project. A typical example is to use it as argument or the
// return value of a service API. For instance:
//
// service Foo {
// rpc Bar (grpc.testing.Empty) returns (grpc.testing.Empty) { };
// };
//
message Empty {}
namespace Grpc.Core.Tests
{
internal class FakeChannelCredentials : ChannelCredentials
{
readonly bool composable;
public FakeChannelCredentials(bool composable)
{
this.composable = composable;
}
internal override bool IsComposable
{
get { return composable; }
}
internal override CredentialsSafeHandle ToNativeCredentials()
{
return null;
}
}
internal class FakeCallCredentials : CallCredentials
{
internal override CredentialsSafeHandle ToNativeCredentials()
{
return null;
}
}
}

@ -63,8 +63,10 @@
<Compile Include="..\Grpc.Core\Version.cs">
<Link>Version.cs</Link>
</Compile>
<Compile Include="ClientBaseTest.cs" />
<Compile Include="CallCredentialsTest.cs" />
<Compile Include="FakeCredentials.cs" />
<Compile Include="MarshallingErrorsTest.cs" />
<Compile Include="ChannelCredentialsTest.cs" />
<Compile Include="ShutdownTest.cs" />
<Compile Include="Internal\AsyncCallTest.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />

@ -49,7 +49,7 @@ namespace Grpc.Core.Internal.Tests
[SetUp]
public void Init()
{
channel = new Channel("localhost", Credentials.Insecure);
channel = new Channel("localhost", ChannelCredentials.Insecure);
fakeCall = new FakeNativeCall();

@ -119,7 +119,7 @@ namespace Grpc.Core.Tests
[Test]
public void RequestParsingError_UnaryRequest()
{
helper.UnaryHandler = new UnaryServerMethod<string, string>((request, context) =>
helper.UnaryHandler = new UnaryServerMethod<string, string>((request, context) =>
{
return Task.FromResult("RESPONSE");
});
@ -161,7 +161,7 @@ namespace Grpc.Core.Tests
{
helper.ClientStreamingHandler = new ClientStreamingServerMethod<string, string>(async (requestStream, context) =>
{
CollectionAssert.AreEqual(new [] {"A", "B"}, await requestStream.ToListAsync());
CollectionAssert.AreEqual(new[] { "A", "B" }, await requestStream.ToListAsync());
return "RESPONSE";
});
var call = Calls.AsyncClientStreamingCall(helper.CreateClientStreamingCall());

@ -154,7 +154,7 @@ namespace Grpc.Core.Tests
{
if (channel == null)
{
channel = new Channel(Host, GetServer().Ports.Single().BoundPort, Credentials.Insecure);
channel = new Channel(Host, GetServer().Ports.Single().BoundPort, ChannelCredentials.Insecure);
}
return channel;
}

@ -60,7 +60,7 @@ namespace Grpc.Core.Tests
public void CompletionQueueCreateDestroyBenchmark()
{
BenchmarkUtil.RunBenchmark(
100000, 1000000,
10, 10,
() =>
{
CompletionQueueSafeHandle cq = CompletionQueueSafeHandle.Create();

@ -0,0 +1,142 @@
#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.Threading.Tasks;
using Grpc.Core.Internal;
using Grpc.Core.Utils;
namespace Grpc.Core
{
/// <summary>
/// Client-side call credentials. Provide authorization with per-call granularity.
/// </summary>
public abstract class CallCredentials
{
/// <summary>
/// Composes multiple multiple <c>CallCredentials</c> objects into
/// a single <c>CallCredentials</c> object.
/// </summary>
/// <param name="credentials">credentials to compose</param>
/// <returns>The new <c>CompositeCallCredentials</c></returns>
public static CallCredentials Compose(params CallCredentials[] credentials)
{
return new CompositeCallCredentials(credentials);
}
/// <summary>
/// Creates native object for the credentials.
/// </summary>
/// <returns>The native credentials.</returns>
internal abstract CredentialsSafeHandle ToNativeCredentials();
}
/// <summary>
/// Asynchronous authentication interceptor for <see cref="MetadataCredentials"/>.
/// </summary>
/// <param name="authUri">URL of a service to which current remote call needs to authenticate</param>
/// <param name="metadata">Metadata to populate with entries that will be added to outgoing call's headers.</param>
/// <returns></returns>
public delegate Task AsyncAuthInterceptor(string authUri, Metadata metadata);
/// <summary>
/// Client-side credentials that delegate metadata based auth to an interceptor.
/// The interceptor is automatically invoked for each remote call that uses <c>MetadataCredentials.</c>
/// </summary>
public class MetadataCredentials : CallCredentials
{
readonly AsyncAuthInterceptor interceptor;
/// <summary>
/// Initializes a new instance of <c>MetadataCredentials</c> class.
/// </summary>
/// <param name="interceptor">authentication interceptor</param>
public MetadataCredentials(AsyncAuthInterceptor interceptor)
{
this.interceptor = interceptor;
}
internal override CredentialsSafeHandle ToNativeCredentials()
{
NativeMetadataCredentialsPlugin plugin = new NativeMetadataCredentialsPlugin(interceptor);
return plugin.Credentials;
}
}
/// <summary>
/// Credentials that allow composing multiple credentials objects into one <see cref="CallCredentials"/> object.
/// </summary>
internal sealed class CompositeCallCredentials : CallCredentials
{
readonly List<CallCredentials> credentials;
/// <summary>
/// Initializes a new instance of <c>CompositeCallCredentials</c> class.
/// The resulting credentials object will be composite of all the credentials specified as parameters.
/// </summary>
/// <param name="credentials">credentials to compose</param>
public CompositeCallCredentials(params CallCredentials[] credentials)
{
Preconditions.CheckArgument(credentials.Length >= 2, "Composite credentials object can only be created from 2 or more credentials.");
this.credentials = new List<CallCredentials>(credentials);
}
internal override CredentialsSafeHandle ToNativeCredentials()
{
return ToNativeRecursive(0);
}
// Recursive descent makes managing lifetime of intermediate CredentialSafeHandle instances easier.
// In practice, we won't usually see composites from more than two credentials anyway.
private CredentialsSafeHandle ToNativeRecursive(int startIndex)
{
if (startIndex == credentials.Count - 1)
{
return credentials[startIndex].ToNativeCredentials();
}
using (var cred1 = credentials[startIndex].ToNativeCredentials())
using (var cred2 = ToNativeRecursive(startIndex + 1))
{
var nativeComposite = CredentialsSafeHandle.CreateComposite(cred1, cred2);
if (nativeComposite.IsInvalid)
{
throw new ArgumentException("Error creating native composite credentials. Likely, this is because you are trying to compose incompatible credentials.");
}
return nativeComposite;
}
}
}
}

@ -49,6 +49,7 @@ namespace Grpc.Core
CancellationToken cancellationToken;
WriteOptions writeOptions;
ContextPropagationToken propagationToken;
CallCredentials credentials;
/// <summary>
/// Creates a new instance of <c>CallOptions</c> struct.
@ -58,14 +59,16 @@ namespace Grpc.Core
/// <param name="cancellationToken">Can be used to request cancellation of the call.</param>
/// <param name="writeOptions">Write options that will be used for this call.</param>
/// <param name="propagationToken">Context propagation token obtained from <see cref="ServerCallContext"/>.</param>
/// <param name="credentials">Credentials to use for this call.</param>
public CallOptions(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken),
WriteOptions writeOptions = null, ContextPropagationToken propagationToken = null)
WriteOptions writeOptions = null, ContextPropagationToken propagationToken = null, CallCredentials credentials = null)
{
this.headers = headers;
this.deadline = deadline;
this.cancellationToken = cancellationToken;
this.writeOptions = writeOptions;
this.propagationToken = propagationToken;
this.credentials = credentials;
}
/// <summary>
@ -114,6 +117,17 @@ namespace Grpc.Core
}
}
/// <summary>
/// Credentials to use for this call.
/// </summary>
public CallCredentials Credentials
{
get
{
return this.credentials;
}
}
/// <summary>
/// Returns new instance of <see cref="CallOptions"/> with
/// <c>Headers</c> set to the value provided. Values of all other fields are preserved.

@ -68,7 +68,7 @@ namespace Grpc.Core
/// <param name="target">Target of the channel.</param>
/// <param name="credentials">Credentials to secure the channel.</param>
/// <param name="options">Channel options.</param>
public Channel(string target, Credentials credentials, IEnumerable<ChannelOption> options = null)
public Channel(string target, ChannelCredentials credentials, IEnumerable<ChannelOption> options = null)
{
this.target = Preconditions.CheckNotNull(target, "target");
this.environment = GrpcEnvironment.AddRef();
@ -96,7 +96,7 @@ namespace Grpc.Core
/// <param name="port">The port.</param>
/// <param name="credentials">Credentials to secure the channel.</param>
/// <param name="options">Channel options.</param>
public Channel(string host, int port, Credentials credentials, IEnumerable<ChannelOption> options = null) :
public Channel(string host, int port, ChannelCredentials credentials, IEnumerable<ChannelOption> options = null) :
this(string.Format("{0}:{1}", host, port), credentials, options)
{
}

@ -0,0 +1,238 @@
#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.Threading.Tasks;
using Grpc.Core.Internal;
using Grpc.Core.Utils;
namespace Grpc.Core
{
/// <summary>
/// Client-side channel credentials. Used for creation of a secure channel.
/// </summary>
public abstract class ChannelCredentials
{
static readonly ChannelCredentials InsecureInstance = new InsecureCredentialsImpl();
/// <summary>
/// Returns instance of credentials that provides no security and
/// will result in creating an unsecure channel with no encryption whatsoever.
/// </summary>
public static ChannelCredentials Insecure
{
get
{
return InsecureInstance;
}
}
/// <summary>
/// Creates a new instance of <c>ChannelCredentials</c> class by composing
/// given channel credentials with call credentials.
/// </summary>
/// <param name="channelCredentials">Channel credentials.</param>
/// <param name="callCredentials">Call credentials.</param>
/// <returns>The new composite <c>ChannelCredentials</c></returns>
public static ChannelCredentials Create(ChannelCredentials channelCredentials, CallCredentials callCredentials)
{
return new CompositeChannelCredentials(channelCredentials, callCredentials);
}
/// <summary>
/// Creates a new instance of <c>ChannelCredentials</c> by wrapping
/// an instance of <c>CallCredentials</c>.
/// </summary>
/// <param name="callCredentials">Call credentials.</param>
/// <returns>The <c>ChannelCredentials</c> wrapping given call credentials.</returns>
public static ChannelCredentials Create(CallCredentials callCredentials)
{
return new WrappedCallCredentials(callCredentials);
}
/// <summary>
/// Creates native object for the credentials. May return null if insecure channel
/// should be created.
/// </summary>
/// <returns>The native credentials.</returns>
internal abstract CredentialsSafeHandle ToNativeCredentials();
/// <summary>
/// Returns <c>true</c> if this credential type allows being composed by <c>CompositeCredentials</c>.
/// </summary>
internal virtual bool IsComposable
{
get { return false; }
}
private sealed class InsecureCredentialsImpl : ChannelCredentials
{
internal override CredentialsSafeHandle ToNativeCredentials()
{
return null;
}
}
}
/// <summary>
/// Client-side SSL credentials.
/// </summary>
public sealed class SslCredentials : ChannelCredentials
{
readonly string rootCertificates;
readonly KeyCertificatePair keyCertificatePair;
/// <summary>
/// Creates client-side SSL credentials loaded from
/// disk file pointed to by the GRPC_DEFAULT_SSL_ROOTS_FILE_PATH environment variable.
/// If that fails, gets the roots certificates from a well known place on disk.
/// </summary>
public SslCredentials() : this(null, null)
{
}
/// <summary>
/// Creates client-side SSL credentials from
/// a string containing PEM encoded root certificates.
/// </summary>
public SslCredentials(string rootCertificates) : this(rootCertificates, null)
{
}
/// <summary>
/// Creates client-side SSL credentials.
/// </summary>
/// <param name="rootCertificates">string containing PEM encoded server root certificates.</param>
/// <param name="keyCertificatePair">a key certificate pair.</param>
public SslCredentials(string rootCertificates, KeyCertificatePair keyCertificatePair)
{
this.rootCertificates = rootCertificates;
this.keyCertificatePair = keyCertificatePair;
}
/// <summary>
/// PEM encoding of the server root certificates.
/// </summary>
public string RootCertificates
{
get
{
return this.rootCertificates;
}
}
/// <summary>
/// Client side key and certificate pair.
/// If null, client will not use key and certificate pair.
/// </summary>
public KeyCertificatePair KeyCertificatePair
{
get
{
return this.keyCertificatePair;
}
}
// Composing composite makes no sense.
internal override bool IsComposable
{
get { return true; }
}
internal override CredentialsSafeHandle ToNativeCredentials()
{
return CredentialsSafeHandle.CreateSslCredentials(rootCertificates, keyCertificatePair);
}
}
/// <summary>
/// Credentials that allow composing one <see cref="ChannelCredentials"/> object and
/// one or more <see cref="CallCredentials"/> objects into a single <see cref="ChannelCredentials"/>.
/// </summary>
internal sealed class CompositeChannelCredentials : ChannelCredentials
{
readonly ChannelCredentials channelCredentials;
readonly CallCredentials callCredentials;
/// <summary>
/// Initializes a new instance of <c>CompositeChannelCredentials</c> class.
/// The resulting credentials object will be composite of all the credentials specified as parameters.
/// </summary>
/// <param name="channelCredentials">channelCredentials to compose</param>
/// <param name="callCredentials">channelCredentials to compose</param>
public CompositeChannelCredentials(ChannelCredentials channelCredentials, CallCredentials callCredentials)
{
this.channelCredentials = Preconditions.CheckNotNull(channelCredentials);
this.callCredentials = Preconditions.CheckNotNull(callCredentials);
Preconditions.CheckArgument(channelCredentials.IsComposable, "Supplied channel credentials do not allow composition.");
}
internal override CredentialsSafeHandle ToNativeCredentials()
{
using (var cred1 = channelCredentials.ToNativeCredentials())
using (var cred2 = callCredentials.ToNativeCredentials())
{
var nativeComposite = CredentialsSafeHandle.CreateComposite(cred1, cred2);
if (nativeComposite.IsInvalid)
{
throw new ArgumentException("Error creating native composite credentials. Likely, this is because you are trying to compose incompatible credentials.");
}
return nativeComposite;
}
}
}
/// <summary>
/// Credentials wrapping <see cref="CallCredentials"/> as <see cref="ChannelCredentials"/>.
/// </summary>
internal sealed class WrappedCallCredentials : ChannelCredentials
{
readonly CallCredentials callCredentials;
/// <summary>
/// Wraps instance of <c>CallCredentials</c> as <c>ChannelCredentials</c>.
/// </summary>
/// <param name="callCredentials">credentials to wrap</param>
public WrappedCallCredentials(CallCredentials callCredentials)
{
this.callCredentials = Preconditions.CheckNotNull(callCredentials);
}
internal override CredentialsSafeHandle ToNativeCredentials()
{
return callCredentials.ToNativeCredentials();
}
}
}

@ -40,18 +40,17 @@ namespace Grpc.Core
/// <summary>
/// Interceptor for call headers.
/// </summary>
public delegate void HeaderInterceptor(IMethod method, string authUri, Metadata metadata);
/// <remarks>Header interceptor is no longer to recommented way to perform authentication.
/// For header (initial metadata) based auth such as OAuth2 or JWT access token, use <see cref="MetadataCredentials"/>.
/// </remarks>
public delegate void HeaderInterceptor(IMethod method, Metadata metadata);
/// <summary>
/// Base class for client-side stubs.
/// </summary>
public abstract class ClientBase
{
// Regex for removal of the optional DNS scheme, trailing port, and trailing backslash
static readonly Regex ChannelTargetPattern = new Regex(@"^(dns:\/{3})?([^:\/]+)(:\d+)?\/?$");
readonly Channel channel;
readonly string authUriBase;
/// <summary>
/// Initializes a new instance of <c>ClientBase</c> class.
@ -60,13 +59,14 @@ namespace Grpc.Core
public ClientBase(Channel channel)
{
this.channel = channel;
this.authUriBase = GetAuthUriBase(channel.Target);
}
/// <summary>
/// Can be used to register a custom header (request metadata) interceptor.
/// Can be used to register a custom header interceptor.
/// The interceptor is invoked each time a new call on this client is started.
/// It is not recommented to use header interceptor to add auth headers to RPC calls.
/// </summary>
/// <seealso cref="HeaderInterceptor"/>
public HeaderInterceptor HeaderInterceptor
{
get;
@ -115,24 +115,9 @@ namespace Grpc.Core
{
options = options.WithHeaders(new Metadata());
}
var authUri = authUriBase != null ? authUriBase + method.ServiceName : null;
interceptor(method, authUri, options.Headers);
interceptor(method, options.Headers);
}
return new CallInvocationDetails<TRequest, TResponse>(channel, method, Host, options);
}
/// <summary>
/// Creates Auth URI base from channel's target (the one passed at channel creation).
/// Fully-qualified service name is to be appended to this.
/// </summary>
internal static string GetAuthUriBase(string target)
{
var match = ChannelTargetPattern.Match(target);
if (!match.Success)
{
return null;
}
return "https://" + match.Groups[2].Value + "/";
}
}
}

@ -1,138 +0,0 @@
#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
{
/// <summary>
/// Client-side credentials. Used for creation of a secure channel.
/// </summary>
public abstract class Credentials
{
static readonly Credentials InsecureInstance = new InsecureCredentialsImpl();
/// <summary>
/// Returns instance of credential that provides no security and
/// will result in creating an unsecure channel with no encryption whatsoever.
/// </summary>
public static Credentials Insecure
{
get
{
return InsecureInstance;
}
}
/// <summary>
/// Creates native object for the credentials. May return null if insecure channel
/// should be created.
/// </summary>
/// <returns>The native credentials.</returns>
internal abstract CredentialsSafeHandle ToNativeCredentials();
private sealed class InsecureCredentialsImpl : Credentials
{
internal override CredentialsSafeHandle ToNativeCredentials()
{
return null;
}
}
}
/// <summary>
/// Client-side SSL credentials.
/// </summary>
public sealed class SslCredentials : Credentials
{
readonly string rootCertificates;
readonly KeyCertificatePair keyCertificatePair;
/// <summary>
/// Creates client-side SSL credentials loaded from
/// disk file pointed to by the GRPC_DEFAULT_SSL_ROOTS_FILE_PATH environment variable.
/// If that fails, gets the roots certificates from a well known place on disk.
/// </summary>
public SslCredentials() : this(null, null)
{
}
/// <summary>
/// Creates client-side SSL credentials from
/// a string containing PEM encoded root certificates.
/// </summary>
public SslCredentials(string rootCertificates) : this(rootCertificates, null)
{
}
/// <summary>
/// Creates client-side SSL credentials.
/// </summary>
/// <param name="rootCertificates">string containing PEM encoded server root certificates.</param>
/// <param name="keyCertificatePair">a key certificate pair.</param>
public SslCredentials(string rootCertificates, KeyCertificatePair keyCertificatePair)
{
this.rootCertificates = rootCertificates;
this.keyCertificatePair = keyCertificatePair;
}
/// <summary>
/// PEM encoding of the server root certificates.
/// </summary>
public string RootCertificates
{
get
{
return this.rootCertificates;
}
}
/// <summary>
/// Client side key and certificate pair.
/// If null, client will not use key and certificate pair.
/// </summary>
public KeyCertificatePair KeyCertificatePair
{
get
{
return this.keyCertificatePair;
}
}
internal override CredentialsSafeHandle ToNativeCredentials()
{
return CredentialsSafeHandle.CreateSslCredentials(rootCertificates, keyCertificatePair);
}
}
}

@ -48,7 +48,9 @@
<ItemGroup>
<Compile Include="AsyncDuplexStreamingCall.cs" />
<Compile Include="AsyncServerStreamingCall.cs" />
<Compile Include="CallCredentials.cs" />
<Compile Include="IClientStreamWriter.cs" />
<Compile Include="Internal\NativeMetadataCredentialsPlugin.cs" />
<Compile Include="Internal\INativeCall.cs" />
<Compile Include="IServerStreamWriter.cs" />
<Compile Include="IAsyncStreamWriter.cs" />
@ -79,7 +81,7 @@
<Compile Include="Utils\AsyncStreamExtensions.cs" />
<Compile Include="Utils\BenchmarkUtil.cs" />
<Compile Include="Internal\CredentialsSafeHandle.cs" />
<Compile Include="Credentials.cs" />
<Compile Include="ChannelCredentials.cs" />
<Compile Include="Internal\ChannelArgsSafeHandle.cs" />
<Compile Include="Internal\AsyncCompletion.cs" />
<Compile Include="Internal\AsyncCallBase.cs" />

@ -16,7 +16,7 @@
<tags>gRPC RPC Protocol HTTP/2</tags>
<dependencies>
<dependency id="Ix-Async" version="1.2.3" />
<dependency id="grpc.native.csharp_ext" version="$GrpcNativeCsharpExtVersion$" />
<dependency id="grpc.native.csharp" version="$GrpcNativeCsharpVersion$" />
</dependencies>
</metadata>
<files>

@ -344,9 +344,13 @@ namespace Grpc.Core.Internal
var parentCall = details.Options.PropagationToken != null ? details.Options.PropagationToken.ParentCall : CallSafeHandle.NullInstance;
return details.Channel.Handle.CreateCall(environment.CompletionRegistry,
parentCall, ContextPropagationToken.DefaultMask, cq,
details.Method, details.Host, Timespec.FromDateTime(details.Options.Deadline.Value));
var credentials = details.Options.Credentials;
using (var nativeCredentials = credentials != null ? credentials.ToNativeCredentials() : null)
{
return details.Channel.Handle.CreateCall(environment.CompletionRegistry,
parentCall, ContextPropagationToken.DefaultMask, cq,
details.Method, details.Host, Timespec.FromDateTime(details.Options.Deadline.Value), nativeCredentials);
}
}
// Make sure that once cancellationToken for this call is cancelled, Cancel() will be called.

@ -98,6 +98,9 @@ namespace Grpc.Core.Internal
static extern GRPCCallError grpcsharp_call_send_initial_metadata(CallSafeHandle call,
BatchContextSafeHandle ctx, MetadataArraySafeHandle metadataArray);
[DllImport("grpc_csharp_ext.dll")]
static extern GRPCCallError grpcsharp_call_set_credentials(CallSafeHandle call, CredentialsSafeHandle credentials);
[DllImport("grpc_csharp_ext.dll")]
static extern CStringSafeHandle grpcsharp_call_get_peer(CallSafeHandle call);
@ -113,6 +116,11 @@ namespace Grpc.Core.Internal
this.completionRegistry = completionRegistry;
}
public void SetCredentials(CredentialsSafeHandle credentials)
{
grpcsharp_call_set_credentials(this, credentials).CheckOk();
}
public void StartUnary(UnaryResponseClientHandler callback, byte[] payload, MetadataArraySafeHandle metadataArray, WriteFlags writeFlags)
{
var ctx = BatchContextSafeHandle.Create();

@ -82,9 +82,13 @@ namespace Grpc.Core.Internal
return grpcsharp_secure_channel_create(credentials, target, channelArgs);
}
public CallSafeHandle CreateCall(CompletionRegistry registry, CallSafeHandle parentCall, ContextPropagationFlags propagationMask, CompletionQueueSafeHandle cq, string method, string host, Timespec deadline)
public CallSafeHandle CreateCall(CompletionRegistry registry, CallSafeHandle parentCall, ContextPropagationFlags propagationMask, CompletionQueueSafeHandle cq, string method, string host, Timespec deadline, CredentialsSafeHandle credentials)
{
var result = grpcsharp_channel_create_call(this, parentCall, propagationMask, cq, method, host, deadline);
if (credentials != null)
{
result.SetCredentials(credentials);
}
result.SetCompletionRegistry(registry);
return result;
}

@ -43,6 +43,9 @@ namespace Grpc.Core.Internal
[DllImport("grpc_csharp_ext.dll", CharSet = CharSet.Ansi)]
static extern CredentialsSafeHandle grpcsharp_ssl_credentials_create(string pemRootCerts, string keyCertPairCertChain, string keyCertPairPrivateKey);
[DllImport("grpc_csharp_ext.dll")]
static extern CredentialsSafeHandle grpcsharp_composite_credentials_create(CredentialsSafeHandle creds1, CredentialsSafeHandle creds2);
[DllImport("grpc_csharp_ext.dll")]
static extern void grpcsharp_credentials_release(IntPtr credentials);
@ -69,6 +72,11 @@ namespace Grpc.Core.Internal
}
}
public static CredentialsSafeHandle CreateComposite(CredentialsSafeHandle creds1, CredentialsSafeHandle creds2)
{
return grpcsharp_composite_credentials_create(creds1, creds2);
}
protected override bool ReleaseHandle()
{
grpcsharp_credentials_release(handle);

@ -0,0 +1,113 @@
#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.Logging;
using Grpc.Core.Utils;
namespace Grpc.Core.Internal
{
internal delegate void NativeMetadataInterceptor(IntPtr statePtr, IntPtr serviceUrlPtr, IntPtr callbackPtr, IntPtr userDataPtr, bool isDestroy);
internal class NativeMetadataCredentialsPlugin
{
const string GetMetadataExceptionMsg = "Exception occured in metadata credentials plugin.";
static readonly ILogger Logger = GrpcEnvironment.Logger.ForType<NativeMetadataCredentialsPlugin>();
[DllImport("grpc_csharp_ext.dll")]
static extern CredentialsSafeHandle grpcsharp_metadata_credentials_create_from_plugin(NativeMetadataInterceptor interceptor);
[DllImport("grpc_csharp_ext.dll", CharSet = CharSet.Ansi)]
static extern void grpcsharp_metadata_credentials_notify_from_plugin(IntPtr callbackPtr, IntPtr userData, MetadataArraySafeHandle metadataArray, StatusCode statusCode, string errorDetails);
AsyncAuthInterceptor interceptor;
GCHandle gcHandle;
NativeMetadataInterceptor nativeInterceptor;
CredentialsSafeHandle credentials;
public NativeMetadataCredentialsPlugin(AsyncAuthInterceptor interceptor)
{
this.interceptor = Preconditions.CheckNotNull(interceptor, "interceptor");
this.nativeInterceptor = NativeMetadataInterceptorHandler;
// Make sure the callback doesn't get garbage collected until it is destroyed.
this.gcHandle = GCHandle.Alloc(this.nativeInterceptor, GCHandleType.Normal);
this.credentials = grpcsharp_metadata_credentials_create_from_plugin(nativeInterceptor);
}
public CredentialsSafeHandle Credentials
{
get { return credentials; }
}
private void NativeMetadataInterceptorHandler(IntPtr statePtr, IntPtr serviceUrlPtr, IntPtr callbackPtr, IntPtr userDataPtr, bool isDestroy)
{
if (isDestroy)
{
gcHandle.Free();
return;
}
try
{
string serviceUrl = Marshal.PtrToStringAnsi(serviceUrlPtr);
StartGetMetadata(serviceUrl, callbackPtr, userDataPtr);
}
catch (Exception e)
{
grpcsharp_metadata_credentials_notify_from_plugin(callbackPtr, userDataPtr, MetadataArraySafeHandle.Create(Metadata.Empty), StatusCode.Unknown, GetMetadataExceptionMsg);
Logger.Error(e, GetMetadataExceptionMsg);
}
}
private async void StartGetMetadata(string serviceUrl, IntPtr callbackPtr, IntPtr userDataPtr)
{
try
{
var metadata = new Metadata();
await interceptor(serviceUrl, metadata);
using (var metadataArray = MetadataArraySafeHandle.Create(metadata))
{
grpcsharp_metadata_credentials_notify_from_plugin(callbackPtr, userDataPtr, metadataArray, StatusCode.OK, null);
}
}
catch (Exception e)
{
grpcsharp_metadata_credentials_notify_from_plugin(callbackPtr, userDataPtr, MetadataArraySafeHandle.Create(Metadata.Empty), StatusCode.Unknown, GetMetadataExceptionMsg);
Logger.Error(e, GetMetadataExceptionMsg);
}
}
}
}

@ -39,7 +39,7 @@ namespace Math
{
public static void Main(string[] args)
{
var channel = new Channel("127.0.0.1", 23456, Credentials.Insecure);
var channel = new Channel("127.0.0.1", 23456, ChannelCredentials.Insecure);
Math.IMathClient client = new Math.MathClient(channel);
MathExamples.DivExample(client);

@ -61,7 +61,7 @@ namespace Math.Tests
Ports = { { Host, ServerPort.PickUnused, ServerCredentials.Insecure } }
};
server.Start();
channel = new Channel(Host, server.Ports.Single().BoundPort, Credentials.Insecure);
channel = new Channel(Host, server.Ports.Single().BoundPort, ChannelCredentials.Insecure);
client = Math.NewClient(channel);
}

@ -63,7 +63,7 @@ namespace Grpc.HealthCheck.Tests
Ports = { { Host, ServerPort.PickUnused, ServerCredentials.Insecure } }
};
server.Start();
channel = new Channel(Host, server.Ports.Single().BoundPort, Credentials.Insecure);
channel = new Channel(Host, server.Ports.Single().BoundPort, ChannelCredentials.Insecure);
client = Grpc.Health.V1Alpha.Health.NewClient(channel);
}

@ -9,6 +9,7 @@
<AssemblyName>Grpc.IntegrationTesting.Client</AssemblyName>
<StartupObject>Grpc.IntegrationTesting.Client.Program</StartupObject>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<NuGetPackageImportStamp>6d22e68f</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@ -38,7 +39,47 @@
<AssemblyOriginatorKeyFile>C:\keys\Grpc.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<ItemGroup>
<Reference Include="BouncyCastle.Crypto, Version=1.7.4137.9688, Culture=neutral, PublicKeyToken=a4292a325f69b123, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\BouncyCastle.1.7.0\lib\Net40-Client\BouncyCastle.Crypto.dll</HintPath>
</Reference>
<Reference Include="Google.Apis.Auth, Version=1.9.3.19379, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Google.Apis.Auth.1.9.3\lib\net40\Google.Apis.Auth.dll</HintPath>
</Reference>
<Reference Include="Google.Apis.Auth.PlatformServices, Version=1.9.3.19383, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Google.Apis.Auth.1.9.3\lib\net40\Google.Apis.Auth.PlatformServices.dll</HintPath>
</Reference>
<Reference Include="Google.Apis.Core, Version=1.9.3.19379, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Google.Apis.Core.1.9.3\lib\portable-net40+sl50+win+wpa81+wp80\Google.Apis.Core.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Threading.Tasks, Version=1.0.12.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Threading.Tasks.Extensions">
<HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Threading.Tasks.Extensions.Desktop, Version=1.0.168.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=7.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Net" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Net.Http.Extensions">
<HintPath>..\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Extensions.dll</HintPath>
</Reference>
<Reference Include="System.Net.Http.Primitives">
<HintPath>..\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Primitives.dll</HintPath>
</Reference>
<Reference Include="System.Net.Http.WebRequest" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\Grpc.Core\Version.cs">
@ -60,5 +101,13 @@
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
<None Include="packages.config" />
</ItemGroup>
<Import Project="..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets" Condition="Exists('..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets'))" />
</Target>
</Project>

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="BouncyCastle" version="1.7.0" targetFramework="net45" />
<package id="Google.Apis.Auth" version="1.9.3" targetFramework="net45" />
<package id="Google.Apis.Core" version="1.9.3" targetFramework="net45" />
<package id="Microsoft.Bcl" version="1.1.10" targetFramework="net45" />
<package id="Microsoft.Bcl.Async" version="1.0.168" targetFramework="net45" />
<package id="Microsoft.Bcl.Build" version="1.0.21" targetFramework="net45" />
<package id="Microsoft.Net.Http" version="2.2.29" targetFramework="net45" />
<package id="Newtonsoft.Json" version="7.0.1" targetFramework="net45" />
</packages>

@ -9,6 +9,7 @@
<AssemblyName>Grpc.IntegrationTesting.Server</AssemblyName>
<StartupObject>Grpc.IntegrationTesting.Server.Program</StartupObject>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<NuGetPackageImportStamp>d9ee8e52</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@ -38,7 +39,47 @@
<AssemblyOriginatorKeyFile>C:\keys\Grpc.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<ItemGroup>
<Reference Include="BouncyCastle.Crypto, Version=1.7.4137.9688, Culture=neutral, PublicKeyToken=a4292a325f69b123, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\BouncyCastle.1.7.0\lib\Net40-Client\BouncyCastle.Crypto.dll</HintPath>
</Reference>
<Reference Include="Google.Apis.Auth, Version=1.9.3.19379, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Google.Apis.Auth.1.9.3\lib\net40\Google.Apis.Auth.dll</HintPath>
</Reference>
<Reference Include="Google.Apis.Auth.PlatformServices, Version=1.9.3.19383, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Google.Apis.Auth.1.9.3\lib\net40\Google.Apis.Auth.PlatformServices.dll</HintPath>
</Reference>
<Reference Include="Google.Apis.Core, Version=1.9.3.19379, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Google.Apis.Core.1.9.3\lib\portable-net40+sl50+win+wpa81+wp80\Google.Apis.Core.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Threading.Tasks, Version=1.0.12.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Threading.Tasks.Extensions">
<HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Threading.Tasks.Extensions.Desktop, Version=1.0.168.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=7.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Net" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Net.Http.Extensions">
<HintPath>..\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Extensions.dll</HintPath>
</Reference>
<Reference Include="System.Net.Http.Primitives">
<HintPath>..\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Primitives.dll</HintPath>
</Reference>
<Reference Include="System.Net.Http.WebRequest" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\Grpc.Core\Version.cs">
@ -60,5 +101,13 @@
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
<None Include="packages.config" />
</ItemGroup>
<Import Project="..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets" Condition="Exists('..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets'))" />
</Target>
</Project>

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="BouncyCastle" version="1.7.0" targetFramework="net45" />
<package id="Google.Apis.Auth" version="1.9.3" targetFramework="net45" />
<package id="Google.Apis.Core" version="1.9.3" targetFramework="net45" />
<package id="Microsoft.Bcl" version="1.1.10" targetFramework="net45" />
<package id="Microsoft.Bcl.Async" version="1.0.168" targetFramework="net45" />
<package id="Microsoft.Bcl.Build" version="1.0.21" targetFramework="net45" />
<package id="Microsoft.Net.Http" version="2.2.29" targetFramework="net45" />
<package id="Newtonsoft.Json" version="7.0.1" targetFramework="net45" />
</packages>

@ -1,5 +1,5 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: empty.proto
// source: test/proto/empty.proto
#pragma warning disable 1591, 0612, 3021
#region Designer generated code
@ -23,7 +23,8 @@ namespace Grpc.Testing {
static Empty() {
byte[] descriptorData = global::System.Convert.FromBase64String(
string.Concat(
"CgtlbXB0eS5wcm90bxIMZ3JwYy50ZXN0aW5nIgcKBUVtcHR5YgZwcm90bzM="));
"ChZ0ZXN0L3Byb3RvL2VtcHR5LnByb3RvEgxncnBjLnRlc3RpbmciBwoFRW1w",
"dHliBnByb3RvMw=="));
descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
new pbr::FileDescriptor[] { },
new pbr::GeneratedCodeInfo(null, new pbr::GeneratedCodeInfo[] {

@ -96,6 +96,7 @@
<Compile Include="Empty.cs" />
<Compile Include="Messages.cs" />
<Compile Include="InteropClientServerTest.cs" />
<Compile Include="MetadataCredentialsTest.cs" />
<Compile Include="TestServiceImpl.cs" />
<Compile Include="InteropServer.cs" />
<Compile Include="InteropClient.cs" />
@ -118,9 +119,6 @@
<ItemGroup>
<None Include="app.config" />
<None Include="packages.config" />
<None Include="proto\test.proto" />
<None Include="proto\empty.proto" />
<None Include="proto\messages.proto" />
<None Include="data\README">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>

@ -33,20 +33,21 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using CommandLine;
using CommandLine.Text;
using Google.Apis.Auth.OAuth2;
using Google.Protobuf;
using Grpc.Auth;
using Grpc.Core;
using Grpc.Core.Utils;
using Grpc.Testing;
using Newtonsoft.Json.Linq;
using NUnit.Framework;
using CommandLine.Text;
using System.IO;
namespace Grpc.IntegrationTesting
{
@ -66,11 +67,13 @@ namespace Grpc.IntegrationTesting
[Option("test_case", DefaultValue = "large_unary")]
public string TestCase { get; set; }
[Option("use_tls")]
public bool UseTls { get; set; }
// Deliberately using nullable bool type to allow --use_tls=true syntax (as opposed to --use_tls)
[Option("use_tls", DefaultValue = false)]
public bool? UseTls { get; set; }
[Option("use_test_ca")]
public bool UseTestCa { get; set; }
// Deliberately using nullable bool type to allow --use_test_ca=true syntax (as opposed to --use_test_ca)
[Option("use_test_ca", DefaultValue = false)]
public bool? UseTestCa { get; set; }
[Option("default_service_account", Required = false)]
public string DefaultServiceAccount { get; set; }
@ -116,7 +119,7 @@ namespace Grpc.IntegrationTesting
private async Task Run()
{
var credentials = options.UseTls ? TestCredentials.CreateTestClientCredentials(options.UseTestCa) : Credentials.Insecure;
var credentials = await CreateCredentialsAsync();
List<ChannelOption> channelOptions = null;
if (!string.IsNullOrEmpty(options.ServerHostOverride))
@ -132,6 +135,26 @@ namespace Grpc.IntegrationTesting
await channel.ShutdownAsync();
}
private async Task<ChannelCredentials> CreateCredentialsAsync()
{
var credentials = options.UseTls.Value ? TestCredentials.CreateTestClientCredentials(options.UseTestCa.Value) : ChannelCredentials.Insecure;
if (options.TestCase == "jwt_token_creds")
{
var googleCredential = await GoogleCredential.GetApplicationDefaultAsync();
Assert.IsTrue(googleCredential.IsCreateScopedRequired);
credentials = ChannelCredentials.Create(credentials, googleCredential.ToGrpcCredentials());
}
if (options.TestCase == "compute_engine_creds")
{
var googleCredential = await GoogleCredential.GetApplicationDefaultAsync();
Assert.IsFalse(googleCredential.IsCreateScopedRequired);
credentials = ChannelCredentials.Create(credentials, googleCredential.ToGrpcCredentials());
}
return credentials;
}
private async Task RunTestCaseAsync(TestService.TestServiceClient client, ClientOptions options)
{
switch (options.TestCase)
@ -155,16 +178,16 @@ namespace Grpc.IntegrationTesting
await RunEmptyStreamAsync(client);
break;
case "compute_engine_creds":
await RunComputeEngineCredsAsync(client, options.DefaultServiceAccount, options.OAuthScope);
RunComputeEngineCreds(client, options.DefaultServiceAccount, options.OAuthScope);
break;
case "jwt_token_creds":
await RunJwtTokenCredsAsync(client, options.DefaultServiceAccount);
RunJwtTokenCreds(client);
break;
case "oauth2_auth_token":
await RunOAuth2AuthTokenAsync(client, options.DefaultServiceAccount, options.OAuthScope);
await RunOAuth2AuthTokenAsync(client, options.OAuthScope);
break;
case "per_rpc_creds":
await RunPerRpcCredsAsync(client, options.DefaultServiceAccount, options.OAuthScope);
await RunPerRpcCredsAsync(client, options.OAuthScope);
break;
case "cancel_after_begin":
await RunCancelAfterBeginAsync(client);
@ -318,13 +341,10 @@ namespace Grpc.IntegrationTesting
Console.WriteLine("Passed!");
}
public static async Task RunComputeEngineCredsAsync(TestService.TestServiceClient client, string defaultServiceAccount, string oauthScope)
public static void RunComputeEngineCreds(TestService.TestServiceClient client, string defaultServiceAccount, string oauthScope)
{
Console.WriteLine("running compute_engine_creds");
var credential = await GoogleCredential.GetApplicationDefaultAsync();
Assert.IsFalse(credential.IsCreateScopedRequired);
client.HeaderInterceptor = AuthInterceptors.FromCredential(credential);
var request = new SimpleRequest
{
ResponseType = PayloadType.COMPRESSABLE,
@ -334,6 +354,7 @@ namespace Grpc.IntegrationTesting
FillOauthScope = true
};
// not setting credentials here because they were set on channel already
var response = client.UnaryCall(request);
Assert.AreEqual(PayloadType.COMPRESSABLE, response.Payload.Type);
@ -344,13 +365,10 @@ namespace Grpc.IntegrationTesting
Console.WriteLine("Passed!");
}
public static async Task RunJwtTokenCredsAsync(TestService.TestServiceClient client, string defaultServiceAccount)
public static void RunJwtTokenCreds(TestService.TestServiceClient client)
{
Console.WriteLine("running jwt_token_creds");
var credential = await GoogleCredential.GetApplicationDefaultAsync();
Assert.IsTrue(credential.IsCreateScopedRequired);
client.HeaderInterceptor = AuthInterceptors.FromCredential(credential);
var request = new SimpleRequest
{
ResponseType = PayloadType.COMPRESSABLE,
@ -359,53 +377,50 @@ namespace Grpc.IntegrationTesting
FillUsername = true,
};
// not setting credentials here because they were set on channel already
var response = client.UnaryCall(request);
Assert.AreEqual(PayloadType.COMPRESSABLE, response.Payload.Type);
Assert.AreEqual(314159, response.Payload.Body.Length);
Assert.AreEqual(defaultServiceAccount, response.Username);
Assert.AreEqual(GetEmailFromServiceAccountFile(), response.Username);
Console.WriteLine("Passed!");
}
public static async Task RunOAuth2AuthTokenAsync(TestService.TestServiceClient client, string defaultServiceAccount, string oauthScope)
public static async Task RunOAuth2AuthTokenAsync(TestService.TestServiceClient client, string oauthScope)
{
Console.WriteLine("running oauth2_auth_token");
ITokenAccess credential = (await GoogleCredential.GetApplicationDefaultAsync()).CreateScoped(new[] { oauthScope });
string oauth2Token = await credential.GetAccessTokenForRequestAsync();
client.HeaderInterceptor = AuthInterceptors.FromAccessToken(oauth2Token);
var credentials = GrpcCredentials.FromAccessToken(oauth2Token);
var request = new SimpleRequest
{
FillUsername = true,
FillOauthScope = true
};
var response = client.UnaryCall(request);
var response = client.UnaryCall(request, new CallOptions(credentials: credentials));
Assert.False(string.IsNullOrEmpty(response.OauthScope));
Assert.True(oauthScope.Contains(response.OauthScope));
Assert.AreEqual(defaultServiceAccount, response.Username);
Assert.AreEqual(GetEmailFromServiceAccountFile(), response.Username);
Console.WriteLine("Passed!");
}
public static async Task RunPerRpcCredsAsync(TestService.TestServiceClient client, string defaultServiceAccount, string oauthScope)
public static async Task RunPerRpcCredsAsync(TestService.TestServiceClient client, string oauthScope)
{
Console.WriteLine("running per_rpc_creds");
ITokenAccess credential = (await GoogleCredential.GetApplicationDefaultAsync()).CreateScoped(new[] { oauthScope });
string accessToken = await credential.GetAccessTokenForRequestAsync();
var headerInterceptor = AuthInterceptors.FromAccessToken(accessToken);
ITokenAccess googleCredential = await GoogleCredential.GetApplicationDefaultAsync();
var credentials = GrpcCredentials.Create(googleCredential);
var request = new SimpleRequest
{
FillUsername = true,
};
var headers = new Metadata();
headerInterceptor(null, "", headers);
var response = client.UnaryCall(request, headers: headers);
var response = client.UnaryCall(request, new CallOptions(credentials: credentials));
Assert.AreEqual(defaultServiceAccount, response.Username);
Assert.AreEqual(GetEmailFromServiceAccountFile(), response.Username);
Console.WriteLine("Passed!");
}
@ -485,5 +500,17 @@ namespace Grpc.IntegrationTesting
{
return new Payload { Body = ByteString.CopyFrom(new byte[size]) };
}
// extracts the client_email field from service account file used for auth test cases
private static string GetEmailFromServiceAccountFile()
{
string keyFile = Environment.GetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS");
Assert.IsNotNull(keyFile);
var jobject = JObject.Parse(File.ReadAllText(keyFile));
string email = jobject.GetValue("client_email").Value<string>();
Assert.IsTrue(email.Length > 0); // spec requires nonempty client email.
return email;
}
}
}

@ -54,8 +54,9 @@ namespace Grpc.IntegrationTesting
[Option("port", DefaultValue = 8070)]
public int Port { get; set; }
[Option("use_tls")]
public bool UseTls { get; set; }
// Deliberately using nullable bool type to allow --use_tls=true syntax (as opposed to --use_tls)
[Option("use_tls", DefaultValue = false)]
public bool? UseTls { get; set; }
[HelpOption]
public string GetUsage()
@ -99,7 +100,7 @@ namespace Grpc.IntegrationTesting
string host = "0.0.0.0";
int port = options.Port;
if (options.UseTls)
if (options.UseTls.Value)
{
server.Ports.Add(host, port, TestCredentials.CreateTestServerCredentials());
}

@ -1,5 +1,5 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: messages.proto
// source: test/proto/messages.proto
#pragma warning disable 1591, 0612, 3021
#region Designer generated code
@ -21,37 +21,48 @@ namespace Grpc.Testing {
static Messages() {
byte[] descriptorData = global::System.Convert.FromBase64String(
string.Concat(
"Cg5tZXNzYWdlcy5wcm90bxIMZ3JwYy50ZXN0aW5nIkAKB1BheWxvYWQSJwoE",
"dHlwZRgBIAEoDjIZLmdycGMudGVzdGluZy5QYXlsb2FkVHlwZRIMCgRib2R5",
"GAIgASgMIrEBCg1TaW1wbGVSZXF1ZXN0EjAKDXJlc3BvbnNlX3R5cGUYASAB",
"KA4yGS5ncnBjLnRlc3RpbmcuUGF5bG9hZFR5cGUSFQoNcmVzcG9uc2Vfc2l6",
"ZRgCIAEoBRImCgdwYXlsb2FkGAMgASgLMhUuZ3JwYy50ZXN0aW5nLlBheWxv",
"YWQSFQoNZmlsbF91c2VybmFtZRgEIAEoCBIYChBmaWxsX29hdXRoX3Njb3Bl",
"GAUgASgIIl8KDlNpbXBsZVJlc3BvbnNlEiYKB3BheWxvYWQYASABKAsyFS5n",
"cnBjLnRlc3RpbmcuUGF5bG9hZBIQCgh1c2VybmFtZRgCIAEoCRITCgtvYXV0",
"aF9zY29wZRgDIAEoCSJDChlTdHJlYW1pbmdJbnB1dENhbGxSZXF1ZXN0EiYK",
"B3BheWxvYWQYASABKAsyFS5ncnBjLnRlc3RpbmcuUGF5bG9hZCI9ChpTdHJl",
"YW1pbmdJbnB1dENhbGxSZXNwb25zZRIfChdhZ2dyZWdhdGVkX3BheWxvYWRf",
"c2l6ZRgBIAEoBSI3ChJSZXNwb25zZVBhcmFtZXRlcnMSDAoEc2l6ZRgBIAEo",
"BRITCgtpbnRlcnZhbF91cxgCIAEoBSK1AQoaU3RyZWFtaW5nT3V0cHV0Q2Fs",
"bFJlcXVlc3QSMAoNcmVzcG9uc2VfdHlwZRgBIAEoDjIZLmdycGMudGVzdGlu",
"Zy5QYXlsb2FkVHlwZRI9ChNyZXNwb25zZV9wYXJhbWV0ZXJzGAIgAygLMiAu",
"Z3JwYy50ZXN0aW5nLlJlc3BvbnNlUGFyYW1ldGVycxImCgdwYXlsb2FkGAMg",
"ASgLMhUuZ3JwYy50ZXN0aW5nLlBheWxvYWQiRQobU3RyZWFtaW5nT3V0cHV0",
"Q2FsbFJlc3BvbnNlEiYKB3BheWxvYWQYASABKAsyFS5ncnBjLnRlc3Rpbmcu",
"UGF5bG9hZCo/CgtQYXlsb2FkVHlwZRIQCgxDT01QUkVTU0FCTEUQABISCg5V",
"TkNPTVBSRVNTQUJMRRABEgoKBlJBTkRPTRACYgZwcm90bzM="));
"Chl0ZXN0L3Byb3RvL21lc3NhZ2VzLnByb3RvEgxncnBjLnRlc3RpbmciQAoH",
"UGF5bG9hZBInCgR0eXBlGAEgASgOMhkuZ3JwYy50ZXN0aW5nLlBheWxvYWRU",
"eXBlEgwKBGJvZHkYAiABKAwiKwoKRWNob1N0YXR1cxIMCgRjb2RlGAEgASgF",
"Eg8KB21lc3NhZ2UYAiABKAkioQIKDVNpbXBsZVJlcXVlc3QSMAoNcmVzcG9u",
"c2VfdHlwZRgBIAEoDjIZLmdycGMudGVzdGluZy5QYXlsb2FkVHlwZRIVCg1y",
"ZXNwb25zZV9zaXplGAIgASgFEiYKB3BheWxvYWQYAyABKAsyFS5ncnBjLnRl",
"c3RpbmcuUGF5bG9hZBIVCg1maWxsX3VzZXJuYW1lGAQgASgIEhgKEGZpbGxf",
"b2F1dGhfc2NvcGUYBSABKAgSOwoUcmVzcG9uc2VfY29tcHJlc3Npb24YBiAB",
"KA4yHS5ncnBjLnRlc3RpbmcuQ29tcHJlc3Npb25UeXBlEjEKD3Jlc3BvbnNl",
"X3N0YXR1cxgHIAEoCzIYLmdycGMudGVzdGluZy5FY2hvU3RhdHVzIl8KDlNp",
"bXBsZVJlc3BvbnNlEiYKB3BheWxvYWQYASABKAsyFS5ncnBjLnRlc3Rpbmcu",
"UGF5bG9hZBIQCgh1c2VybmFtZRgCIAEoCRITCgtvYXV0aF9zY29wZRgDIAEo",
"CSJDChlTdHJlYW1pbmdJbnB1dENhbGxSZXF1ZXN0EiYKB3BheWxvYWQYASAB",
"KAsyFS5ncnBjLnRlc3RpbmcuUGF5bG9hZCI9ChpTdHJlYW1pbmdJbnB1dENh",
"bGxSZXNwb25zZRIfChdhZ2dyZWdhdGVkX3BheWxvYWRfc2l6ZRgBIAEoBSI3",
"ChJSZXNwb25zZVBhcmFtZXRlcnMSDAoEc2l6ZRgBIAEoBRITCgtpbnRlcnZh",
"bF91cxgCIAEoBSKlAgoaU3RyZWFtaW5nT3V0cHV0Q2FsbFJlcXVlc3QSMAoN",
"cmVzcG9uc2VfdHlwZRgBIAEoDjIZLmdycGMudGVzdGluZy5QYXlsb2FkVHlw",
"ZRI9ChNyZXNwb25zZV9wYXJhbWV0ZXJzGAIgAygLMiAuZ3JwYy50ZXN0aW5n",
"LlJlc3BvbnNlUGFyYW1ldGVycxImCgdwYXlsb2FkGAMgASgLMhUuZ3JwYy50",
"ZXN0aW5nLlBheWxvYWQSOwoUcmVzcG9uc2VfY29tcHJlc3Npb24YBiABKA4y",
"HS5ncnBjLnRlc3RpbmcuQ29tcHJlc3Npb25UeXBlEjEKD3Jlc3BvbnNlX3N0",
"YXR1cxgHIAEoCzIYLmdycGMudGVzdGluZy5FY2hvU3RhdHVzIkUKG1N0cmVh",
"bWluZ091dHB1dENhbGxSZXNwb25zZRImCgdwYXlsb2FkGAEgASgLMhUuZ3Jw",
"Yy50ZXN0aW5nLlBheWxvYWQiMwoNUmVjb25uZWN0SW5mbxIOCgZwYXNzZWQY",
"ASABKAgSEgoKYmFja29mZl9tcxgCIAMoBSo/CgtQYXlsb2FkVHlwZRIQCgxD",
"T01QUkVTU0FCTEUQABISCg5VTkNPTVBSRVNTQUJMRRABEgoKBlJBTkRPTRAC",
"KjIKD0NvbXByZXNzaW9uVHlwZRIICgROT05FEAASCAoER1pJUBABEgsKB0RF",
"RkxBVEUQAmIGcHJvdG8z"));
descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
new pbr::FileDescriptor[] { },
new pbr::GeneratedCodeInfo(new[] {typeof(global::Grpc.Testing.PayloadType), }, new pbr::GeneratedCodeInfo[] {
new pbr::GeneratedCodeInfo(new[] {typeof(global::Grpc.Testing.PayloadType), typeof(global::Grpc.Testing.CompressionType), }, new pbr::GeneratedCodeInfo[] {
new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.Payload), new[]{ "Type", "Body" }, null, null, null),
new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.SimpleRequest), new[]{ "ResponseType", "ResponseSize", "Payload", "FillUsername", "FillOauthScope" }, null, null, null),
new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.EchoStatus), new[]{ "Code", "Message" }, null, null, null),
new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.SimpleRequest), new[]{ "ResponseType", "ResponseSize", "Payload", "FillUsername", "FillOauthScope", "ResponseCompression", "ResponseStatus" }, null, null, null),
new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.SimpleResponse), new[]{ "Payload", "Username", "OauthScope" }, null, null, null),
new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.StreamingInputCallRequest), new[]{ "Payload" }, null, null, null),
new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.StreamingInputCallResponse), new[]{ "AggregatedPayloadSize" }, null, null, null),
new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.ResponseParameters), new[]{ "Size", "IntervalUs" }, null, null, null),
new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.StreamingOutputCallRequest), new[]{ "ResponseType", "ResponseParameters", "Payload" }, null, null, null),
new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.StreamingOutputCallResponse), new[]{ "Payload" }, null, null, null)
new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.StreamingOutputCallRequest), new[]{ "ResponseType", "ResponseParameters", "Payload", "ResponseCompression", "ResponseStatus" }, null, null, null),
new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.StreamingOutputCallResponse), new[]{ "Payload" }, null, null, null),
new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.ReconnectInfo), new[]{ "Passed", "BackoffMs" }, null, null, null)
}));
}
#endregion
@ -64,6 +75,12 @@ namespace Grpc.Testing {
RANDOM = 2,
}
public enum CompressionType {
NONE = 0,
GZIP = 1,
DEFLATE = 2,
}
#endregion
#region Messages
@ -195,13 +212,141 @@ namespace Grpc.Testing {
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
public sealed partial class EchoStatus : pb::IMessage<EchoStatus> {
private static readonly pb::MessageParser<EchoStatus> _parser = new pb::MessageParser<EchoStatus>(() => new EchoStatus());
public static pb::MessageParser<EchoStatus> Parser { get { return _parser; } }
public static pbr::MessageDescriptor Descriptor {
get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[1]; }
}
pbr::MessageDescriptor pb::IMessage.Descriptor {
get { return Descriptor; }
}
public EchoStatus() {
OnConstruction();
}
partial void OnConstruction();
public EchoStatus(EchoStatus other) : this() {
code_ = other.code_;
message_ = other.message_;
}
public EchoStatus Clone() {
return new EchoStatus(this);
}
public const int CodeFieldNumber = 1;
private int code_;
public int Code {
get { return code_; }
set {
code_ = value;
}
}
public const int MessageFieldNumber = 2;
private string message_ = "";
public string Message {
get { return message_; }
set {
message_ = pb::Preconditions.CheckNotNull(value, "value");
}
}
public override bool Equals(object other) {
return Equals(other as EchoStatus);
}
public bool Equals(EchoStatus other) {
if (ReferenceEquals(other, null)) {
return false;
}
if (ReferenceEquals(other, this)) {
return true;
}
if (Code != other.Code) return false;
if (Message != other.Message) return false;
return true;
}
public override int GetHashCode() {
int hash = 1;
if (Code != 0) hash ^= Code.GetHashCode();
if (Message.Length != 0) hash ^= Message.GetHashCode();
return hash;
}
public override string ToString() {
return pb::JsonFormatter.Default.Format(this);
}
public void WriteTo(pb::CodedOutputStream output) {
if (Code != 0) {
output.WriteRawTag(8);
output.WriteInt32(Code);
}
if (Message.Length != 0) {
output.WriteRawTag(18);
output.WriteString(Message);
}
}
public int CalculateSize() {
int size = 0;
if (Code != 0) {
size += 1 + pb::CodedOutputStream.ComputeInt32Size(Code);
}
if (Message.Length != 0) {
size += 1 + pb::CodedOutputStream.ComputeStringSize(Message);
}
return size;
}
public void MergeFrom(EchoStatus other) {
if (other == null) {
return;
}
if (other.Code != 0) {
Code = other.Code;
}
if (other.Message.Length != 0) {
Message = other.Message;
}
}
public void MergeFrom(pb::CodedInputStream input) {
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
input.SkipLastField();
break;
case 8: {
Code = input.ReadInt32();
break;
}
case 18: {
Message = input.ReadString();
break;
}
}
}
}
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
public sealed partial class SimpleRequest : pb::IMessage<SimpleRequest> {
private static readonly pb::MessageParser<SimpleRequest> _parser = new pb::MessageParser<SimpleRequest>(() => new SimpleRequest());
public static pb::MessageParser<SimpleRequest> Parser { get { return _parser; } }
public static pbr::MessageDescriptor Descriptor {
get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[1]; }
get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[2]; }
}
pbr::MessageDescriptor pb::IMessage.Descriptor {
@ -220,6 +365,8 @@ namespace Grpc.Testing {
Payload = other.payload_ != null ? other.Payload.Clone() : null;
fillUsername_ = other.fillUsername_;
fillOauthScope_ = other.fillOauthScope_;
responseCompression_ = other.responseCompression_;
ResponseStatus = other.responseStatus_ != null ? other.ResponseStatus.Clone() : null;
}
public SimpleRequest Clone() {
@ -271,6 +418,24 @@ namespace Grpc.Testing {
}
}
public const int ResponseCompressionFieldNumber = 6;
private global::Grpc.Testing.CompressionType responseCompression_ = global::Grpc.Testing.CompressionType.NONE;
public global::Grpc.Testing.CompressionType ResponseCompression {
get { return responseCompression_; }
set {
responseCompression_ = value;
}
}
public const int ResponseStatusFieldNumber = 7;
private global::Grpc.Testing.EchoStatus responseStatus_;
public global::Grpc.Testing.EchoStatus ResponseStatus {
get { return responseStatus_; }
set {
responseStatus_ = value;
}
}
public override bool Equals(object other) {
return Equals(other as SimpleRequest);
}
@ -287,6 +452,8 @@ namespace Grpc.Testing {
if (!object.Equals(Payload, other.Payload)) return false;
if (FillUsername != other.FillUsername) return false;
if (FillOauthScope != other.FillOauthScope) return false;
if (ResponseCompression != other.ResponseCompression) return false;
if (!object.Equals(ResponseStatus, other.ResponseStatus)) return false;
return true;
}
@ -297,6 +464,8 @@ namespace Grpc.Testing {
if (payload_ != null) hash ^= Payload.GetHashCode();
if (FillUsername != false) hash ^= FillUsername.GetHashCode();
if (FillOauthScope != false) hash ^= FillOauthScope.GetHashCode();
if (ResponseCompression != global::Grpc.Testing.CompressionType.NONE) hash ^= ResponseCompression.GetHashCode();
if (responseStatus_ != null) hash ^= ResponseStatus.GetHashCode();
return hash;
}
@ -325,6 +494,14 @@ namespace Grpc.Testing {
output.WriteRawTag(40);
output.WriteBool(FillOauthScope);
}
if (ResponseCompression != global::Grpc.Testing.CompressionType.NONE) {
output.WriteRawTag(48);
output.WriteEnum((int) ResponseCompression);
}
if (responseStatus_ != null) {
output.WriteRawTag(58);
output.WriteMessage(ResponseStatus);
}
}
public int CalculateSize() {
@ -344,6 +521,12 @@ namespace Grpc.Testing {
if (FillOauthScope != false) {
size += 1 + 1;
}
if (ResponseCompression != global::Grpc.Testing.CompressionType.NONE) {
size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) ResponseCompression);
}
if (responseStatus_ != null) {
size += 1 + pb::CodedOutputStream.ComputeMessageSize(ResponseStatus);
}
return size;
}
@ -369,6 +552,15 @@ namespace Grpc.Testing {
if (other.FillOauthScope != false) {
FillOauthScope = other.FillOauthScope;
}
if (other.ResponseCompression != global::Grpc.Testing.CompressionType.NONE) {
ResponseCompression = other.ResponseCompression;
}
if (other.responseStatus_ != null) {
if (responseStatus_ == null) {
responseStatus_ = new global::Grpc.Testing.EchoStatus();
}
ResponseStatus.MergeFrom(other.ResponseStatus);
}
}
public void MergeFrom(pb::CodedInputStream input) {
@ -401,6 +593,17 @@ namespace Grpc.Testing {
FillOauthScope = input.ReadBool();
break;
}
case 48: {
responseCompression_ = (global::Grpc.Testing.CompressionType) input.ReadEnum();
break;
}
case 58: {
if (responseStatus_ == null) {
responseStatus_ = new global::Grpc.Testing.EchoStatus();
}
input.ReadMessage(responseStatus_);
break;
}
}
}
}
@ -413,7 +616,7 @@ namespace Grpc.Testing {
public static pb::MessageParser<SimpleResponse> Parser { get { return _parser; } }
public static pbr::MessageDescriptor Descriptor {
get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[2]; }
get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[3]; }
}
pbr::MessageDescriptor pb::IMessage.Descriptor {
@ -573,7 +776,7 @@ namespace Grpc.Testing {
public static pb::MessageParser<StreamingInputCallRequest> Parser { get { return _parser; } }
public static pbr::MessageDescriptor Descriptor {
get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[3]; }
get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[4]; }
}
pbr::MessageDescriptor pb::IMessage.Descriptor {
@ -681,7 +884,7 @@ namespace Grpc.Testing {
public static pb::MessageParser<StreamingInputCallResponse> Parser { get { return _parser; } }
public static pbr::MessageDescriptor Descriptor {
get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[4]; }
get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[5]; }
}
pbr::MessageDescriptor pb::IMessage.Descriptor {
@ -783,7 +986,7 @@ namespace Grpc.Testing {
public static pb::MessageParser<ResponseParameters> Parser { get { return _parser; } }
public static pbr::MessageDescriptor Descriptor {
get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[5]; }
get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[6]; }
}
pbr::MessageDescriptor pb::IMessage.Descriptor {
@ -911,7 +1114,7 @@ namespace Grpc.Testing {
public static pb::MessageParser<StreamingOutputCallRequest> Parser { get { return _parser; } }
public static pbr::MessageDescriptor Descriptor {
get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[6]; }
get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[7]; }
}
pbr::MessageDescriptor pb::IMessage.Descriptor {
@ -928,6 +1131,8 @@ namespace Grpc.Testing {
responseType_ = other.responseType_;
responseParameters_ = other.responseParameters_.Clone();
Payload = other.payload_ != null ? other.Payload.Clone() : null;
responseCompression_ = other.responseCompression_;
ResponseStatus = other.responseStatus_ != null ? other.ResponseStatus.Clone() : null;
}
public StreamingOutputCallRequest Clone() {
@ -960,6 +1165,24 @@ namespace Grpc.Testing {
}
}
public const int ResponseCompressionFieldNumber = 6;
private global::Grpc.Testing.CompressionType responseCompression_ = global::Grpc.Testing.CompressionType.NONE;
public global::Grpc.Testing.CompressionType ResponseCompression {
get { return responseCompression_; }
set {
responseCompression_ = value;
}
}
public const int ResponseStatusFieldNumber = 7;
private global::Grpc.Testing.EchoStatus responseStatus_;
public global::Grpc.Testing.EchoStatus ResponseStatus {
get { return responseStatus_; }
set {
responseStatus_ = value;
}
}
public override bool Equals(object other) {
return Equals(other as StreamingOutputCallRequest);
}
@ -974,6 +1197,8 @@ namespace Grpc.Testing {
if (ResponseType != other.ResponseType) return false;
if(!responseParameters_.Equals(other.responseParameters_)) return false;
if (!object.Equals(Payload, other.Payload)) return false;
if (ResponseCompression != other.ResponseCompression) return false;
if (!object.Equals(ResponseStatus, other.ResponseStatus)) return false;
return true;
}
@ -982,6 +1207,8 @@ namespace Grpc.Testing {
if (ResponseType != global::Grpc.Testing.PayloadType.COMPRESSABLE) hash ^= ResponseType.GetHashCode();
hash ^= responseParameters_.GetHashCode();
if (payload_ != null) hash ^= Payload.GetHashCode();
if (ResponseCompression != global::Grpc.Testing.CompressionType.NONE) hash ^= ResponseCompression.GetHashCode();
if (responseStatus_ != null) hash ^= ResponseStatus.GetHashCode();
return hash;
}
@ -999,6 +1226,14 @@ namespace Grpc.Testing {
output.WriteRawTag(26);
output.WriteMessage(Payload);
}
if (ResponseCompression != global::Grpc.Testing.CompressionType.NONE) {
output.WriteRawTag(48);
output.WriteEnum((int) ResponseCompression);
}
if (responseStatus_ != null) {
output.WriteRawTag(58);
output.WriteMessage(ResponseStatus);
}
}
public int CalculateSize() {
@ -1010,6 +1245,12 @@ namespace Grpc.Testing {
if (payload_ != null) {
size += 1 + pb::CodedOutputStream.ComputeMessageSize(Payload);
}
if (ResponseCompression != global::Grpc.Testing.CompressionType.NONE) {
size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) ResponseCompression);
}
if (responseStatus_ != null) {
size += 1 + pb::CodedOutputStream.ComputeMessageSize(ResponseStatus);
}
return size;
}
@ -1027,6 +1268,15 @@ namespace Grpc.Testing {
}
Payload.MergeFrom(other.Payload);
}
if (other.ResponseCompression != global::Grpc.Testing.CompressionType.NONE) {
ResponseCompression = other.ResponseCompression;
}
if (other.responseStatus_ != null) {
if (responseStatus_ == null) {
responseStatus_ = new global::Grpc.Testing.EchoStatus();
}
ResponseStatus.MergeFrom(other.ResponseStatus);
}
}
public void MergeFrom(pb::CodedInputStream input) {
@ -1051,6 +1301,17 @@ namespace Grpc.Testing {
input.ReadMessage(payload_);
break;
}
case 48: {
responseCompression_ = (global::Grpc.Testing.CompressionType) input.ReadEnum();
break;
}
case 58: {
if (responseStatus_ == null) {
responseStatus_ = new global::Grpc.Testing.EchoStatus();
}
input.ReadMessage(responseStatus_);
break;
}
}
}
}
@ -1063,7 +1324,7 @@ namespace Grpc.Testing {
public static pb::MessageParser<StreamingOutputCallResponse> Parser { get { return _parser; } }
public static pbr::MessageDescriptor Descriptor {
get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[7]; }
get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[8]; }
}
pbr::MessageDescriptor pb::IMessage.Descriptor {
@ -1165,6 +1426,127 @@ namespace Grpc.Testing {
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
public sealed partial class ReconnectInfo : pb::IMessage<ReconnectInfo> {
private static readonly pb::MessageParser<ReconnectInfo> _parser = new pb::MessageParser<ReconnectInfo>(() => new ReconnectInfo());
public static pb::MessageParser<ReconnectInfo> Parser { get { return _parser; } }
public static pbr::MessageDescriptor Descriptor {
get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[9]; }
}
pbr::MessageDescriptor pb::IMessage.Descriptor {
get { return Descriptor; }
}
public ReconnectInfo() {
OnConstruction();
}
partial void OnConstruction();
public ReconnectInfo(ReconnectInfo other) : this() {
passed_ = other.passed_;
backoffMs_ = other.backoffMs_.Clone();
}
public ReconnectInfo Clone() {
return new ReconnectInfo(this);
}
public const int PassedFieldNumber = 1;
private bool passed_;
public bool Passed {
get { return passed_; }
set {
passed_ = value;
}
}
public const int BackoffMsFieldNumber = 2;
private static readonly pb::FieldCodec<int> _repeated_backoffMs_codec
= pb::FieldCodec.ForInt32(18);
private readonly pbc::RepeatedField<int> backoffMs_ = new pbc::RepeatedField<int>();
public pbc::RepeatedField<int> BackoffMs {
get { return backoffMs_; }
}
public override bool Equals(object other) {
return Equals(other as ReconnectInfo);
}
public bool Equals(ReconnectInfo other) {
if (ReferenceEquals(other, null)) {
return false;
}
if (ReferenceEquals(other, this)) {
return true;
}
if (Passed != other.Passed) return false;
if(!backoffMs_.Equals(other.backoffMs_)) return false;
return true;
}
public override int GetHashCode() {
int hash = 1;
if (Passed != false) hash ^= Passed.GetHashCode();
hash ^= backoffMs_.GetHashCode();
return hash;
}
public override string ToString() {
return pb::JsonFormatter.Default.Format(this);
}
public void WriteTo(pb::CodedOutputStream output) {
if (Passed != false) {
output.WriteRawTag(8);
output.WriteBool(Passed);
}
backoffMs_.WriteTo(output, _repeated_backoffMs_codec);
}
public int CalculateSize() {
int size = 0;
if (Passed != false) {
size += 1 + 1;
}
size += backoffMs_.CalculateSize(_repeated_backoffMs_codec);
return size;
}
public void MergeFrom(ReconnectInfo other) {
if (other == null) {
return;
}
if (other.Passed != false) {
Passed = other.Passed;
}
backoffMs_.Add(other.backoffMs_);
}
public void MergeFrom(pb::CodedInputStream input) {
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
input.SkipLastField();
break;
case 8: {
Passed = input.ReadBool();
break;
}
case 18:
case 16: {
backoffMs_.AddEntriesFrom(input, _repeated_backoffMs_codec);
break;
}
}
}
}
}
#endregion
}

@ -0,0 +1,97 @@
#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.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Grpc.Core;
using Grpc.Core.Utils;
using Grpc.Testing;
using NUnit.Framework;
namespace Grpc.IntegrationTesting
{
public class MetadataCredentialsTest
{
const string Host = "localhost";
Server server;
Channel channel;
TestService.ITestServiceClient client;
[TestFixtureSetUp]
public void Init()
{
var serverCredentials = new SslServerCredentials(new[] { new KeyCertificatePair(File.ReadAllText(TestCredentials.ServerCertChainPath), File.ReadAllText(TestCredentials.ServerPrivateKeyPath)) });
server = new Server
{
Services = { TestService.BindService(new TestServiceImpl()) },
Ports = { { Host, ServerPort.PickUnused, serverCredentials } }
};
server.Start();
var options = new List<ChannelOption>
{
new ChannelOption(ChannelOptions.SslTargetNameOverride, TestCredentials.DefaultHostOverride)
};
var asyncAuthInterceptor = new AsyncAuthInterceptor(async (authUri, metadata) =>
{
await Task.Delay(100); // make sure the operation is asynchronous.
metadata.Add("authorization", "SECRET_TOKEN");
});
var clientCredentials = ChannelCredentials.Create(
new SslCredentials(File.ReadAllText(TestCredentials.ClientCertAuthorityPath)),
new MetadataCredentials(asyncAuthInterceptor));
channel = new Channel(Host, server.Ports.Single().BoundPort, clientCredentials, options);
client = TestService.NewClient(channel);
}
[TestFixtureTearDown]
public void Cleanup()
{
channel.ShutdownAsync().Wait();
server.ShutdownAsync().Wait();
}
[Test]
public void MetadataCredentials()
{
var response = client.UnaryCall(new SimpleRequest { ResponseSize = 10 });
Assert.AreEqual(10, response.Payload.Body.Length);
}
}
}

@ -1,5 +1,5 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: test.proto
// source: test/proto/test.proto
#pragma warning disable 1591, 0612, 3021
#region Designer generated code
@ -21,21 +21,26 @@ namespace Grpc.Testing {
static Test() {
byte[] descriptorData = global::System.Convert.FromBase64String(
string.Concat(
"Cgp0ZXN0LnByb3RvEgxncnBjLnRlc3RpbmcaC2VtcHR5LnByb3RvGg5tZXNz",
"YWdlcy5wcm90bzK7BAoLVGVzdFNlcnZpY2USNQoJRW1wdHlDYWxsEhMuZ3Jw",
"Yy50ZXN0aW5nLkVtcHR5GhMuZ3JwYy50ZXN0aW5nLkVtcHR5EkYKCVVuYXJ5",
"Q2FsbBIbLmdycGMudGVzdGluZy5TaW1wbGVSZXF1ZXN0GhwuZ3JwYy50ZXN0",
"aW5nLlNpbXBsZVJlc3BvbnNlEmwKE1N0cmVhbWluZ091dHB1dENhbGwSKC5n",
"cnBjLnRlc3RpbmcuU3RyZWFtaW5nT3V0cHV0Q2FsbFJlcXVlc3QaKS5ncnBj",
"LnRlc3RpbmcuU3RyZWFtaW5nT3V0cHV0Q2FsbFJlc3BvbnNlMAESaQoSU3Ry",
"ZWFtaW5nSW5wdXRDYWxsEicuZ3JwYy50ZXN0aW5nLlN0cmVhbWluZ0lucHV0",
"Q2FsbFJlcXVlc3QaKC5ncnBjLnRlc3RpbmcuU3RyZWFtaW5nSW5wdXRDYWxs",
"UmVzcG9uc2UoARJpCg5GdWxsRHVwbGV4Q2FsbBIoLmdycGMudGVzdGluZy5T",
"dHJlYW1pbmdPdXRwdXRDYWxsUmVxdWVzdBopLmdycGMudGVzdGluZy5TdHJl",
"YW1pbmdPdXRwdXRDYWxsUmVzcG9uc2UoATABEmkKDkhhbGZEdXBsZXhDYWxs",
"EiguZ3JwYy50ZXN0aW5nLlN0cmVhbWluZ091dHB1dENhbGxSZXF1ZXN0Giku",
"Z3JwYy50ZXN0aW5nLlN0cmVhbWluZ091dHB1dENhbGxSZXNwb25zZSgBMAFi",
"BnByb3RvMw=="));
"ChV0ZXN0L3Byb3RvL3Rlc3QucHJvdG8SDGdycGMudGVzdGluZxoWdGVzdC9w",
"cm90by9lbXB0eS5wcm90bxoZdGVzdC9wcm90by9tZXNzYWdlcy5wcm90bzK7",
"BAoLVGVzdFNlcnZpY2USNQoJRW1wdHlDYWxsEhMuZ3JwYy50ZXN0aW5nLkVt",
"cHR5GhMuZ3JwYy50ZXN0aW5nLkVtcHR5EkYKCVVuYXJ5Q2FsbBIbLmdycGMu",
"dGVzdGluZy5TaW1wbGVSZXF1ZXN0GhwuZ3JwYy50ZXN0aW5nLlNpbXBsZVJl",
"c3BvbnNlEmwKE1N0cmVhbWluZ091dHB1dENhbGwSKC5ncnBjLnRlc3Rpbmcu",
"U3RyZWFtaW5nT3V0cHV0Q2FsbFJlcXVlc3QaKS5ncnBjLnRlc3RpbmcuU3Ry",
"ZWFtaW5nT3V0cHV0Q2FsbFJlc3BvbnNlMAESaQoSU3RyZWFtaW5nSW5wdXRD",
"YWxsEicuZ3JwYy50ZXN0aW5nLlN0cmVhbWluZ0lucHV0Q2FsbFJlcXVlc3Qa",
"KC5ncnBjLnRlc3RpbmcuU3RyZWFtaW5nSW5wdXRDYWxsUmVzcG9uc2UoARJp",
"Cg5GdWxsRHVwbGV4Q2FsbBIoLmdycGMudGVzdGluZy5TdHJlYW1pbmdPdXRw",
"dXRDYWxsUmVxdWVzdBopLmdycGMudGVzdGluZy5TdHJlYW1pbmdPdXRwdXRD",
"YWxsUmVzcG9uc2UoATABEmkKDkhhbGZEdXBsZXhDYWxsEiguZ3JwYy50ZXN0",
"aW5nLlN0cmVhbWluZ091dHB1dENhbGxSZXF1ZXN0GikuZ3JwYy50ZXN0aW5n",
"LlN0cmVhbWluZ091dHB1dENhbGxSZXNwb25zZSgBMAEyVQoUVW5pbXBsZW1l",
"bnRlZFNlcnZpY2USPQoRVW5pbXBsZW1lbnRlZENhbGwSEy5ncnBjLnRlc3Rp",
"bmcuRW1wdHkaEy5ncnBjLnRlc3RpbmcuRW1wdHkyfwoQUmVjb25uZWN0U2Vy",
"dmljZRIxCgVTdGFydBITLmdycGMudGVzdGluZy5FbXB0eRoTLmdycGMudGVz",
"dGluZy5FbXB0eRI4CgRTdG9wEhMuZ3JwYy50ZXN0aW5nLkVtcHR5GhsuZ3Jw",
"Yy50ZXN0aW5nLlJlY29ubmVjdEluZm9iBnByb3RvMw=="));
descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
new pbr::FileDescriptor[] { global::Grpc.Testing.Proto.Empty.Descriptor, global::Grpc.Testing.Messages.Descriptor, },
new pbr::GeneratedCodeInfo(null, null));

@ -1,5 +1,5 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: test.proto
// source: test/proto/test.proto
#region Designer generated code
using System;
@ -207,5 +207,191 @@ namespace Grpc.Testing {
}
}
public static class UnimplementedService
{
static readonly string __ServiceName = "grpc.testing.UnimplementedService";
static readonly Marshaller<global::Grpc.Testing.Empty> __Marshaller_Empty = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.Empty.Parser.ParseFrom);
static readonly Method<global::Grpc.Testing.Empty, global::Grpc.Testing.Empty> __Method_UnimplementedCall = new Method<global::Grpc.Testing.Empty, global::Grpc.Testing.Empty>(
MethodType.Unary,
__ServiceName,
"UnimplementedCall",
__Marshaller_Empty,
__Marshaller_Empty);
// service descriptor
public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
{
get { return global::Grpc.Testing.Test.Descriptor.Services[1]; }
}
// client interface
public interface IUnimplementedServiceClient
{
global::Grpc.Testing.Empty UnimplementedCall(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
global::Grpc.Testing.Empty UnimplementedCall(global::Grpc.Testing.Empty request, CallOptions options);
AsyncUnaryCall<global::Grpc.Testing.Empty> UnimplementedCallAsync(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
AsyncUnaryCall<global::Grpc.Testing.Empty> UnimplementedCallAsync(global::Grpc.Testing.Empty request, CallOptions options);
}
// server-side interface
public interface IUnimplementedService
{
Task<global::Grpc.Testing.Empty> UnimplementedCall(global::Grpc.Testing.Empty request, ServerCallContext context);
}
// client stub
public class UnimplementedServiceClient : ClientBase, IUnimplementedServiceClient
{
public UnimplementedServiceClient(Channel channel) : base(channel)
{
}
public global::Grpc.Testing.Empty UnimplementedCall(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
var call = CreateCall(__Method_UnimplementedCall, new CallOptions(headers, deadline, cancellationToken));
return Calls.BlockingUnaryCall(call, request);
}
public global::Grpc.Testing.Empty UnimplementedCall(global::Grpc.Testing.Empty request, CallOptions options)
{
var call = CreateCall(__Method_UnimplementedCall, options);
return Calls.BlockingUnaryCall(call, request);
}
public AsyncUnaryCall<global::Grpc.Testing.Empty> UnimplementedCallAsync(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
var call = CreateCall(__Method_UnimplementedCall, new CallOptions(headers, deadline, cancellationToken));
return Calls.AsyncUnaryCall(call, request);
}
public AsyncUnaryCall<global::Grpc.Testing.Empty> UnimplementedCallAsync(global::Grpc.Testing.Empty request, CallOptions options)
{
var call = CreateCall(__Method_UnimplementedCall, options);
return Calls.AsyncUnaryCall(call, request);
}
}
// creates service definition that can be registered with a server
public static ServerServiceDefinition BindService(IUnimplementedService serviceImpl)
{
return ServerServiceDefinition.CreateBuilder(__ServiceName)
.AddMethod(__Method_UnimplementedCall, serviceImpl.UnimplementedCall).Build();
}
// creates a new client
public static UnimplementedServiceClient NewClient(Channel channel)
{
return new UnimplementedServiceClient(channel);
}
}
public static class ReconnectService
{
static readonly string __ServiceName = "grpc.testing.ReconnectService";
static readonly Marshaller<global::Grpc.Testing.Empty> __Marshaller_Empty = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.Empty.Parser.ParseFrom);
static readonly Marshaller<global::Grpc.Testing.ReconnectInfo> __Marshaller_ReconnectInfo = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.ReconnectInfo.Parser.ParseFrom);
static readonly Method<global::Grpc.Testing.Empty, global::Grpc.Testing.Empty> __Method_Start = new Method<global::Grpc.Testing.Empty, global::Grpc.Testing.Empty>(
MethodType.Unary,
__ServiceName,
"Start",
__Marshaller_Empty,
__Marshaller_Empty);
static readonly Method<global::Grpc.Testing.Empty, global::Grpc.Testing.ReconnectInfo> __Method_Stop = new Method<global::Grpc.Testing.Empty, global::Grpc.Testing.ReconnectInfo>(
MethodType.Unary,
__ServiceName,
"Stop",
__Marshaller_Empty,
__Marshaller_ReconnectInfo);
// service descriptor
public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
{
get { return global::Grpc.Testing.Test.Descriptor.Services[2]; }
}
// client interface
public interface IReconnectServiceClient
{
global::Grpc.Testing.Empty Start(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
global::Grpc.Testing.Empty Start(global::Grpc.Testing.Empty request, CallOptions options);
AsyncUnaryCall<global::Grpc.Testing.Empty> StartAsync(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
AsyncUnaryCall<global::Grpc.Testing.Empty> StartAsync(global::Grpc.Testing.Empty request, CallOptions options);
global::Grpc.Testing.ReconnectInfo Stop(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
global::Grpc.Testing.ReconnectInfo Stop(global::Grpc.Testing.Empty request, CallOptions options);
AsyncUnaryCall<global::Grpc.Testing.ReconnectInfo> StopAsync(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
AsyncUnaryCall<global::Grpc.Testing.ReconnectInfo> StopAsync(global::Grpc.Testing.Empty request, CallOptions options);
}
// server-side interface
public interface IReconnectService
{
Task<global::Grpc.Testing.Empty> Start(global::Grpc.Testing.Empty request, ServerCallContext context);
Task<global::Grpc.Testing.ReconnectInfo> Stop(global::Grpc.Testing.Empty request, ServerCallContext context);
}
// client stub
public class ReconnectServiceClient : ClientBase, IReconnectServiceClient
{
public ReconnectServiceClient(Channel channel) : base(channel)
{
}
public global::Grpc.Testing.Empty Start(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
var call = CreateCall(__Method_Start, new CallOptions(headers, deadline, cancellationToken));
return Calls.BlockingUnaryCall(call, request);
}
public global::Grpc.Testing.Empty Start(global::Grpc.Testing.Empty request, CallOptions options)
{
var call = CreateCall(__Method_Start, options);
return Calls.BlockingUnaryCall(call, request);
}
public AsyncUnaryCall<global::Grpc.Testing.Empty> StartAsync(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
var call = CreateCall(__Method_Start, new CallOptions(headers, deadline, cancellationToken));
return Calls.AsyncUnaryCall(call, request);
}
public AsyncUnaryCall<global::Grpc.Testing.Empty> StartAsync(global::Grpc.Testing.Empty request, CallOptions options)
{
var call = CreateCall(__Method_Start, options);
return Calls.AsyncUnaryCall(call, request);
}
public global::Grpc.Testing.ReconnectInfo Stop(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
var call = CreateCall(__Method_Stop, new CallOptions(headers, deadline, cancellationToken));
return Calls.BlockingUnaryCall(call, request);
}
public global::Grpc.Testing.ReconnectInfo Stop(global::Grpc.Testing.Empty request, CallOptions options)
{
var call = CreateCall(__Method_Stop, options);
return Calls.BlockingUnaryCall(call, request);
}
public AsyncUnaryCall<global::Grpc.Testing.ReconnectInfo> StopAsync(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
var call = CreateCall(__Method_Stop, new CallOptions(headers, deadline, cancellationToken));
return Calls.AsyncUnaryCall(call, request);
}
public AsyncUnaryCall<global::Grpc.Testing.ReconnectInfo> StopAsync(global::Grpc.Testing.Empty request, CallOptions options)
{
var call = CreateCall(__Method_Stop, options);
return Calls.AsyncUnaryCall(call, request);
}
}
// creates service definition that can be registered with a server
public static ServerServiceDefinition BindService(IReconnectService serviceImpl)
{
return ServerServiceDefinition.CreateBuilder(__ServiceName)
.AddMethod(__Method_Start, serviceImpl.Start)
.AddMethod(__Method_Stop, serviceImpl.Stop).Build();
}
// creates a new client
public static ReconnectServiceClient NewClient(Channel channel)
{
return new ReconnectServiceClient(channel);
}
}
}
#endregion

@ -1,132 +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.
// Message definitions to be used by integration test service definitions.
syntax = "proto3";
package grpc.testing;
// The type of payload that should be returned.
enum PayloadType {
// Compressable text format.
COMPRESSABLE = 0;
// Uncompressable binary format.
UNCOMPRESSABLE = 1;
// Randomly chosen from all other formats defined in this enum.
RANDOM = 2;
}
// A block of data, to simply increase gRPC message size.
message Payload {
// The type of data in body.
PayloadType type = 1;
// Primary contents of payload.
bytes body = 2;
}
// Unary request.
message SimpleRequest {
// Desired payload type in the response from the server.
// If response_type is RANDOM, server randomly chooses one from other formats.
PayloadType response_type = 1;
// Desired payload size in the response from the server.
// If response_type is COMPRESSABLE, this denotes the size before compression.
int32 response_size = 2;
// Optional input payload sent along with the request.
Payload payload = 3;
// Whether SimpleResponse should include username.
bool fill_username = 4;
// Whether SimpleResponse should include OAuth scope.
bool fill_oauth_scope = 5;
}
// Unary response, as configured by the request.
message SimpleResponse {
// Payload to increase message size.
Payload payload = 1;
// The user the request came from, for verifying authentication was
// successful when the client expected it.
string username = 2;
// OAuth scope.
string oauth_scope = 3;
}
// Client-streaming request.
message StreamingInputCallRequest {
// Optional input payload sent along with the request.
Payload payload = 1;
// Not expecting any payload from the response.
}
// Client-streaming response.
message StreamingInputCallResponse {
// Aggregated size of payloads received from the client.
int32 aggregated_payload_size = 1;
}
// Configuration for a particular response.
message ResponseParameters {
// Desired payload sizes in responses from the server.
// If response_type is COMPRESSABLE, this denotes the size before compression.
int32 size = 1;
// Desired interval between consecutive responses in the response stream in
// microseconds.
int32 interval_us = 2;
}
// Server-streaming request.
message StreamingOutputCallRequest {
// Desired payload type in the response from the server.
// If response_type is RANDOM, the payload from each response in the stream
// might be of different types. This is to simulate a mixed type of payload
// stream.
PayloadType response_type = 1;
// Configuration for each expected response message.
repeated ResponseParameters response_parameters = 2;
// Optional input payload sent along with the request.
Payload payload = 3;
}
// Server-streaming response, as configured by the request and parameters.
message StreamingOutputCallResponse {
// Payload to increase response size.
Payload payload = 1;
}

@ -1,71 +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.
// An integration test service that covers all the method signature permutations
// of unary/streaming requests/responses.
syntax = "proto3";
import "empty.proto";
import "messages.proto";
package grpc.testing;
// A simple service to test the various types of RPCs and experiment with
// performance with various types of payload.
service TestService {
// One empty request followed by one empty response.
rpc EmptyCall(grpc.testing.Empty) returns (grpc.testing.Empty);
// One request followed by one response.
rpc UnaryCall(SimpleRequest) returns (SimpleResponse);
// One request followed by a sequence of responses (streamed download).
// The server returns the payload with client desired type and sizes.
rpc StreamingOutputCall(StreamingOutputCallRequest)
returns (stream StreamingOutputCallResponse);
// A sequence of requests followed by one response (streamed upload).
// The server returns the aggregated size of client payload as the result.
rpc StreamingInputCall(stream StreamingInputCallRequest)
returns (StreamingInputCallResponse);
// A sequence of requests with each request served by the server immediately.
// As one request could lead to multiple responses, this interface
// demonstrates the idea of full duplexing.
rpc FullDuplexCall(stream StreamingOutputCallRequest)
returns (stream StreamingOutputCallResponse);
// A sequence of requests followed by a sequence of responses.
// The server buffers all the client requests and then serves them in order. A
// stream of responses are returned to the client when the server starts with
// first request.
rpc HalfDuplexCall(stream StreamingOutputCallRequest)
returns (stream StreamingOutputCallResponse);
}

@ -20,9 +20,9 @@ endlocal
@call ..\..\vsprojects\build_plugins.bat || goto :error
%NUGET% pack ..\..\vsprojects\nuget_package\grpc.native.csharp_ext.nuspec -Version %CORE_VERSION% || goto :error
%NUGET% pack ..\..\vsprojects\nuget_package\grpc.native.csharp.nuspec -Version %CORE_VERSION% || goto :error
%NUGET% pack Grpc.Auth\Grpc.Auth.nuspec -Symbols -Version %VERSION% || goto :error
%NUGET% pack Grpc.Core\Grpc.Core.nuspec -Symbols -Version %VERSION% -Properties GrpcNativeCsharpExtVersion=%CORE_VERSION% || goto :error
%NUGET% pack Grpc.Core\Grpc.Core.nuspec -Symbols -Version %VERSION% -Properties GrpcNativeCsharpVersion=%CORE_VERSION% || goto :error
%NUGET% pack Grpc.HealthCheck\Grpc.HealthCheck.nuspec -Symbols -Version %VERSION_WITH_BETA% -Properties ProtobufVersion=%PROTOBUF_VERSION% || goto :error
%NUGET% pack Grpc.Tools.nuspec -Version %VERSION% || goto :error
%NUGET% pack Grpc.nuspec -Version %VERSION% || goto :error

@ -68,7 +68,7 @@ grpc_byte_buffer *string_to_byte_buffer(const char *buffer, size_t len) {
/*
* Helper to maintain lifetime of batch op inputs and store batch op outputs.
*/
typedef struct gprcsharp_batch_context {
typedef struct grpcsharp_batch_context {
grpc_metadata_array send_initial_metadata;
grpc_byte_buffer *send_message;
struct {
@ -665,16 +665,16 @@ grpcsharp_call_start_duplex_streaming(grpc_call *call,
}
GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_recv_initial_metadata(
grpc_call *call, grpcsharp_batch_context *ctx) {
/* TODO: don't use magic number */
grpc_op ops[1];
ops[0].op = GRPC_OP_RECV_INITIAL_METADATA;
ops[0].data.recv_initial_metadata = &(ctx->recv_initial_metadata);
ops[0].flags = 0;
ops[0].reserved = NULL;
grpc_call *call, grpcsharp_batch_context *ctx) {
/* TODO: don't use magic number */
grpc_op ops[1];
ops[0].op = GRPC_OP_RECV_INITIAL_METADATA;
ops[0].data.recv_initial_metadata = &(ctx->recv_initial_metadata);
ops[0].flags = 0;
ops[0].reserved = NULL;
return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx,
NULL);
return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx,
NULL);
}
GPR_EXPORT grpc_call_error GPR_CALLTYPE
@ -785,6 +785,11 @@ grpcsharp_call_send_initial_metadata(grpc_call *call,
NULL);
}
GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_set_credentials(grpc_call *call,
grpc_credentials *creds) {
return grpc_call_set_credentials(call, creds);
}
/* Server */
GPR_EXPORT grpc_server *GPR_CALLTYPE
@ -892,6 +897,47 @@ grpcsharp_server_add_secure_http2_port(grpc_server *server, const char *addr,
return grpc_server_add_secure_http2_port(server, addr, creds);
}
GPR_EXPORT grpc_credentials *GPR_CALLTYPE grpcsharp_composite_credentials_create(
grpc_credentials *creds1,
grpc_credentials *creds2) {
return grpc_composite_credentials_create(creds1, creds2, NULL);
}
/* Metadata credentials plugin */
GPR_EXPORT void GPR_CALLTYPE grpcsharp_metadata_credentials_notify_from_plugin(
grpc_credentials_plugin_metadata_cb cb,
void *user_data, grpc_metadata_array *metadata,
grpc_status_code status, const char *error_details) {
cb(user_data, metadata->metadata, metadata->count, status, error_details);
}
typedef void(GPR_CALLTYPE *grpcsharp_metadata_interceptor_func)(
void *state, const char *service_url, grpc_credentials_plugin_metadata_cb cb,
void *user_data, gpr_int32 is_destroy);
static void grpcsharp_get_metadata_handler(void *state, const char *service_url,
grpc_credentials_plugin_metadata_cb cb, void *user_data) {
grpcsharp_metadata_interceptor_func interceptor =
(grpcsharp_metadata_interceptor_func)(gpr_intptr)state;
interceptor(state, service_url, cb, user_data, 0);
}
static void grpcsharp_metadata_credentials_destroy_handler(void *state) {
grpcsharp_metadata_interceptor_func interceptor =
(grpcsharp_metadata_interceptor_func)(gpr_intptr)state;
interceptor(state, NULL, NULL, NULL, 1);
}
GPR_EXPORT grpc_credentials *GPR_CALLTYPE grpcsharp_metadata_credentials_create_from_plugin(
grpcsharp_metadata_interceptor_func metadata_interceptor) {
grpc_metadata_credentials_plugin plugin;
plugin.get_metadata = grpcsharp_get_metadata_handler;
plugin.destroy = grpcsharp_metadata_credentials_destroy_handler;
plugin.state = (void*)(gpr_intptr)metadata_interceptor;
return grpc_metadata_credentials_create_from_plugin(plugin, NULL);
}
/* Logging */
typedef void(GPR_CALLTYPE *grpcsharp_log_func)(const char *file, gpr_int32 line,

@ -42,7 +42,7 @@ $PROTOC --plugin=$PLUGIN --csharp_out=$EXAMPLES_DIR --grpc_out=$EXAMPLES_DIR \
-I $EXAMPLES_DIR/proto $EXAMPLES_DIR/proto/math.proto
$PROTOC --plugin=$PLUGIN --csharp_out=$INTEROP_DIR --grpc_out=$INTEROP_DIR \
-I $INTEROP_DIR/proto $INTEROP_DIR/proto/*.proto
-I ../.. ../../test/proto/*.proto
$PROTOC --plugin=$PLUGIN --csharp_out=$HEALTHCHECK_DIR --grpc_out=$HEALTHCHECK_DIR \
-I $HEALTHCHECK_DIR/proto $HEALTHCHECK_DIR/proto/health.proto

@ -44,12 +44,14 @@ var GoogleAuth = require('google-auth-library');
var assert = require('assert');
var AUTH_SCOPE = 'https://www.googleapis.com/auth/xapi.zoo';
var AUTH_SCOPE_RESPONSE = 'xapi.zoo';
var AUTH_USER = ('155450119199-vefjjaekcc6cmsd5914v6lqufunmh9ue' +
'@developer.gserviceaccount.com');
var COMPUTE_ENGINE_USER = ('155450119199-r5aaqa2vqoa9g5mv2m6s3m1l293rlmel' +
'@developer.gserviceaccount.com');
var SERVICE_ACCOUNT_EMAIL;
try {
SERVICE_ACCOUNT_EMAIL = require(
process.env.GOOGLE_APPLICATION_CREDENTIALS).client_email;
} catch (e) {
// This will cause the tests to fail if they need that string
SERVICE_ACCOUNT_EMAIL = null;
}
var ECHO_INITIAL_KEY = 'x-grpc-test-echo-initial';
var ECHO_TRAILING_KEY = 'x-grpc-test-echo-trailing-bin';
@ -345,6 +347,41 @@ function customMetadata(client, done) {
stream.end();
}
function statusCodeAndMessage(client, done) {
done = multiDone(done, 2);
var arg = {
response_status: {
code: 2,
message: 'test status message'
}
};
client.unaryCall(arg, function(err, resp) {
assert(err);
assert.strictEqual(err.code, 2);
assert.strictEqual(err.message, 'test status message');
done();
});
var duplex = client.fullDuplexCall();
duplex.on('status', function(status) {
assert(status);
assert.strictEqual(status.code, 2);
assert.strictEqual(status.details, 'test status message');
done();
});
duplex.on('error', function(){});
duplex.write(arg);
duplex.end();
}
function unimplementedMethod(client, done) {
client.unimplementedCall({}, function(err, resp) {
assert(err);
assert.strictEqual(err.code, grpc.status.UNIMPLEMENTED);
assert(!err.message);
done();
});
}
/**
* Run one of the authentication tests.
* @param {string} expected_user The expected username in the response
@ -369,7 +406,7 @@ function authTest(expected_user, scope, client, done) {
assert.strictEqual(resp.payload.body.length, 314159);
assert.strictEqual(resp.username, expected_user);
if (scope) {
assert.strictEqual(resp.oauth_scope, AUTH_SCOPE_RESPONSE);
assert(scope.indexOf(resp.oauth_scope) > -1);
}
if (done) {
done();
@ -377,56 +414,49 @@ function authTest(expected_user, scope, client, done) {
});
}
function oauth2Test(expected_user, scope, per_rpc, client, done) {
(new GoogleAuth()).getApplicationDefault(function(err, credential) {
function computeEngineCreds(client, done, extra) {
authTest(extra.service_account, null, client, done);
}
function serviceAccountCreds(client, done, extra) {
authTest(SERVICE_ACCOUNT_EMAIL, extra.oauth_scope, client, done);
}
function jwtTokenCreds(client, done, extra) {
authTest(SERVICE_ACCOUNT_EMAIL, null, client, done);
}
function oauth2Test(client, done, extra) {
var arg = {
fill_username: true,
fill_oauth_scope: true
};
client.unaryCall(arg, function(err, resp) {
assert.ifError(err);
var arg = {
fill_username: true,
fill_oauth_scope: true
};
credential = credential.createScoped(scope);
credential.getAccessToken(function(err, token) {
assert.ifError(err);
var updateMetadata = function(authURI, metadata, callback) {
metadata.add('authorization', 'Bearer ' + token);
callback(null, metadata);
};
var makeTestCall = function(error, client_metadata) {
assert.ifError(error);
client.unaryCall(arg, function(err, resp) {
assert.ifError(err);
assert.strictEqual(resp.username, expected_user);
assert.strictEqual(resp.oauth_scope, AUTH_SCOPE_RESPONSE);
if (done) {
done();
}
}, client_metadata);
};
if (per_rpc) {
updateMetadata('', new grpc.Metadata(), makeTestCall);
} else {
client.$updateMetadata = updateMetadata;
makeTestCall(null, new grpc.Metadata());
}
});
assert.strictEqual(resp.username, SERVICE_ACCOUNT_EMAIL);
assert(extra.oauth_scope.indexOf(resp.oauth_scope) > -1);
if (done) {
done();
}
});
}
function perRpcAuthTest(expected_user, scope, per_rpc, client, done) {
function perRpcAuthTest(client, done, extra) {
(new GoogleAuth()).getApplicationDefault(function(err, credential) {
assert.ifError(err);
var arg = {
fill_username: true,
fill_oauth_scope: true
};
var scope = extra.oauth_scope;
if (credential.createScopedRequired() && scope) {
credential = credential.createScoped(scope);
}
var creds = grpc.credentials.createFromGoogleCredential(credential);
client.unaryCall(arg, function(err, resp) {
assert.ifError(err);
assert.strictEqual(resp.username, expected_user);
assert.strictEqual(resp.oauth_scope, AUTH_SCOPE_RESPONSE);
assert.strictEqual(resp.username, SERVICE_ACCOUNT_EMAIL);
assert(extra.oauth_scope.indexOf(resp.oauth_scope) > -1);
if (done) {
done();
}
@ -473,25 +503,44 @@ function getOauth2Creds(scope, callback) {
* Map from test case names to test functions
*/
var test_cases = {
empty_unary: {run: emptyUnary},
large_unary: {run: largeUnary},
client_streaming: {run: clientStreaming},
server_streaming: {run: serverStreaming},
ping_pong: {run: pingPong},
empty_stream: {run: emptyStream},
cancel_after_begin: {run: cancelAfterBegin},
cancel_after_first_response: {run: cancelAfterFirstResponse},
timeout_on_sleeping_server: {run: timeoutOnSleepingServer},
custom_metadata: {run: customMetadata},
compute_engine_creds: {run: _.partial(authTest, COMPUTE_ENGINE_USER, null),
getCreds: _.partial(getApplicationCreds, null)},
service_account_creds: {run: _.partial(authTest, AUTH_USER, AUTH_SCOPE),
getCreds: _.partial(getApplicationCreds, AUTH_SCOPE)},
jwt_token_creds: {run: _.partial(authTest, AUTH_USER, null),
getCreds: _.partial(getApplicationCreds, null)},
oauth2_auth_token: {run: _.partial(oauth2Test, AUTH_USER, AUTH_SCOPE, false),
getCreds: _.partial(getOauth2Creds, AUTH_SCOPE)},
per_rpc_creds: {run: _.partial(perRpcAuthTest, AUTH_USER, AUTH_SCOPE, true)}
empty_unary: {run: emptyUnary,
Client: testProto.TestService},
large_unary: {run: largeUnary,
Client: testProto.TestService},
client_streaming: {run: clientStreaming,
Client: testProto.TestService},
server_streaming: {run: serverStreaming,
Client: testProto.TestService},
ping_pong: {run: pingPong,
Client: testProto.TestService},
empty_stream: {run: emptyStream,
Client: testProto.TestService},
cancel_after_begin: {run: cancelAfterBegin,
Client: testProto.TestService},
cancel_after_first_response: {run: cancelAfterFirstResponse,
Client: testProto.TestService},
timeout_on_sleeping_server: {run: timeoutOnSleepingServer,
Client: testProto.TestService},
custom_metadata: {run: customMetadata,
Client: testProto.TestService},
status_code_and_message: {run: statusCodeAndMessage,
Client: testProto.TestService},
unimplemented_method: {run: unimplementedMethod,
Client: testProto.UnimplementedService},
compute_engine_creds: {run: computeEngineCreds,
Client: testProto.TestService,
getCreds: getApplicationCreds},
service_account_creds: {run: serviceAccountCreds,
Client: testProto.TestService,
getCreds: getApplicationCreds},
jwt_token_creds: {run: jwtTokenCreds,
Client: testProto.TestService,
getCreds: getApplicationCreds},
oauth2_auth_token: {run: oauth2Test,
Client: testProto.TestService,
getCreds: getOauth2Creds},
per_rpc_creds: {run: perRpcAuthTest,
Client: testProto.TestService}
};
/**
@ -504,8 +553,9 @@ var test_cases = {
* @param {bool} tls Indicates that a secure channel should be used
* @param {function} done Callback to call when the test is completed. Included
* primarily for use with mocha
* @param {object=} extra Extra options for some tests
*/
function runTest(address, host_override, test_case, tls, test_ca, done) {
function runTest(address, host_override, test_case, tls, test_ca, done, extra) {
// TODO(mlumish): enable TLS functionality
var options = {};
var creds;
@ -529,12 +579,13 @@ function runTest(address, host_override, test_case, tls, test_ca, done) {
var execute = function(err, creds) {
assert.ifError(err);
var client = new testProto.TestService(address, creds, options);
test.run(client, done);
var client = new test.Client(address, creds, options);
test.run(client, done, extra);
};
if (test.getCreds) {
test.getCreds(function(err, new_creds) {
test.getCreds(extra.oauth_scope, function(err, new_creds) {
assert.ifError(err);
execute(err, grpc.credentials.combineChannelCredentials(
creds, new_creds));
});
@ -547,13 +598,18 @@ if (require.main === module) {
var parseArgs = require('minimist');
var argv = parseArgs(process.argv, {
string: ['server_host', 'server_host_override', 'server_port', 'test_case',
'use_tls', 'use_test_ca']
'use_tls', 'use_test_ca', 'default_service_account', 'oauth_scope',
'service_account_key_file']
});
var extra_args = {
service_account: argv.default_service_account,
oauth_scope: argv.oauth_scope
};
runTest(argv.server_host + ':' + argv.server_port, argv.server_host_override,
argv.test_case, argv.use_tls === 'true', argv.use_test_ca === 'true',
function () {
console.log('OK:', argv.test_case);
});
}, extra_args);
}
/**

@ -44,6 +44,9 @@ var testProto = grpc.load({
var ECHO_INITIAL_KEY = 'x-grpc-test-echo-initial';
var ECHO_TRAILING_KEY = 'x-grpc-test-echo-trailing-bin';
var incompressible_data = fs.readFileSync(
__dirname + '/../../../test/cpp/interop/rnd.dat');
/**
* Create a buffer filled with size zeroes
* @param {number} size The length of the buffer
@ -83,6 +86,19 @@ function getEchoTrailer(call) {
return response_trailer;
}
function getPayload(payload_type, size) {
if (payload_type === 'RANDOM') {
payload_type = ['COMPRESSABLE',
'UNCOMPRESSABLE'][Math.random() < 0.5 ? 0 : 1];
}
var body;
switch (payload_type) {
case 'COMPRESSABLE': body = zeroBuffer(size); break;
case 'UNCOMPRESSABLE': incompressible_data.slice(size); break;
}
return {type: payload_type, body: body};
}
/**
* Respond to an empty parameter with an empty response.
* NOTE: this currently does not work due to issue #137
@ -104,13 +120,14 @@ function handleEmpty(call, callback) {
function handleUnary(call, callback) {
echoHeader(call);
var req = call.request;
var zeros = zeroBuffer(req.response_size);
var payload_type = req.response_type;
if (payload_type === 'RANDOM') {
payload_type = ['COMPRESSABLE',
'UNCOMPRESSABLE'][Math.random() < 0.5 ? 0 : 1];
if (req.response_status) {
var status = req.response_status;
status.metadata = getEchoTrailer(call);
callback(status);
return;
}
callback(null, {payload: {type: payload_type, body: zeros}},
var payload = getPayload(req.response_type, req.response_size);
callback(null, {payload: payload},
getEchoTrailer(call));
}
@ -139,18 +156,14 @@ function handleStreamingInput(call, callback) {
function handleStreamingOutput(call) {
echoHeader(call);
var req = call.request;
var payload_type = req.response_type;
if (payload_type === 'RANDOM') {
payload_type = ['COMPRESSABLE',
'UNCOMPRESSABLE'][Math.random() < 0.5 ? 0 : 1];
if (req.response_status) {
var status = req.response_status;
status.metadata = getEchoTrailer(call);
call.emit('error', status);
return;
}
_.each(req.response_parameters, function(resp_param) {
call.write({
payload: {
body: zeroBuffer(resp_param.size),
type: payload_type
}
});
call.write({payload: getPayload(req.response_type, resp_param.size)});
});
call.end(getEchoTrailer(call));
}
@ -163,18 +176,14 @@ function handleStreamingOutput(call) {
function handleFullDuplex(call) {
echoHeader(call);
call.on('data', function(value) {
var payload_type = value.response_type;
if (payload_type === 'RANDOM') {
payload_type = ['COMPRESSABLE',
'UNCOMPRESSABLE'][Math.random() < 0.5 ? 0 : 1];
if (value.response_status) {
var status = value.response_status;
status.metadata = getEchoTrailer(call);
call.emit('error', status);
return;
}
_.each(value.response_parameters, function(resp_param) {
call.write({
payload: {
body: zeroBuffer(resp_param.size),
type: payload_type
}
});
call.write({payload: getPayload(value.response_type, resp_param.size)});
});
});
call.on('end', function() {
@ -188,7 +197,7 @@ function handleFullDuplex(call) {
* @param {Call} call Call to handle
*/
function handleHalfDuplex(call) {
throw new Error('HalfDuplexCall not yet implemented');
call.emit('error', Error('HalfDuplexCall not yet implemented'));
}
/**

@ -153,7 +153,7 @@ exports.combineCallCredentials = function() {
current = current.compose(arguments[i]);
}
return current;
}
};
/**
* Create an insecure credentials object. This is used to create a channel that

@ -629,7 +629,7 @@ function Server(options) {
(new Metadata())._getCoreRepresentation();
batch[grpc.opType.SEND_STATUS_FROM_SERVER] = {
code: grpc.status.UNIMPLEMENTED,
details: 'This method is not available on this server.',
details: '',
metadata: {}
};
batch[grpc.opType.RECV_CLOSE_ON_SERVER] = true;

@ -57,7 +57,7 @@ describe('Async functionality', function() {
grpc.ServerCredentials.createInsecure());
server.start();
math_client = new math.Math('localhost:' + port_num,
grpc.Credentials.createInsecure());
grpc.credentials.createInsecure());
done();
});
after(function() {

@ -149,7 +149,7 @@ describe('channel', function() {
afterEach(function() {
channel.close();
});
it.only('should time out if called alone', function(done) {
it('should time out if called alone', function(done) {
var old_state = channel.getConnectivityState();
var deadline = new Date();
deadline.setSeconds(deadline.getSeconds() + 1);

@ -130,8 +130,8 @@ describe('client credentials', function() {
callback(null, metadata);
};
var creds = grpc.credentials.createFromMetadataGenerator(metadataUpdater);
var combined_creds = grpc.credentials.combineCredentials(client_ssl_creds,
creds);
var combined_creds = grpc.credentials.combineChannelCredentials(
client_ssl_creds, creds);
var client = new Client('localhost:' + port, combined_creds,
client_options);
var call = client.unary({}, function(err, data) {
@ -150,8 +150,8 @@ describe('client credentials', function() {
callback(null, metadata);
};
var creds = grpc.credentials.createFromMetadataGenerator(metadataUpdater);
var combined_creds = grpc.credentials.combineCredentials(client_ssl_creds,
creds);
var combined_creds = grpc.credentials.combineChannelCredentials(
client_ssl_creds, creds);
var client = new Client('localhost:' + port, combined_creds,
client_options);
var call = client.unary({}, function(err, data) {
@ -231,7 +231,7 @@ describe('client credentials', function() {
updater_creds, alt_updater_creds);
var call = client.unary({}, function(err, data) {
assert.ifError(err);
}, null, {credentials: updater_creds});
}, null, {credentials: combined_updater});
call.on('metadata', function(metadata) {
assert.deepEqual(metadata.get('plugin_key'), ['plugin_value']);
assert.deepEqual(metadata.get('other_plugin_key'),

@ -71,7 +71,7 @@ describe('Interop tests', function() {
interop_client.runTest(port, name_override, 'server_streaming', true, true,
done);
});
it('should pass ping_pong', function(done) {
it.only('should pass ping_pong', function(done) {
interop_client.runTest(port, name_override, 'ping_pong', true, true, done);
});
it('should pass empty_stream', function(done) {
@ -94,4 +94,12 @@ describe('Interop tests', function() {
interop_client.runTest(port, name_override, 'custom_metadata',
true, true, done);
});
it('should pass status_code_and_message', function(done) {
interop_client.runTest(port, name_override, 'status_code_and_message',
true, true, done);
});
it('should pass unimplemented_method', function(done) {
interop_client.runTest(port, name_override, 'unimplemented_method',
true, true, done);
});
});

@ -17,7 +17,7 @@ services.
<a name="install"></a>
## Install protoc with the gRPC plugin
On Mac OS X, install [homebrew][]. On Linux, install [linuxbrew][].
On Mac OS X, install [homebrew][].
Run the following command to install _protoc_ and the gRPC _protoc_ plugin:
```sh
@ -153,7 +153,7 @@ _protoc_, in which case no system modification nor renaming is necessary.
<a name="no-cocoapods"></a>
### Integrate the generated gRPC library without using Cocoapods
You need to compile the generated `.pbpbjc.*` files (the enums and messages) without ARC support,
You need to compile the generated `.pbobjc.*` files (the enums and messages) without ARC support,
and the generated `.pbrpc.*` files (the services) with ARC support. The generated code depends on
v0.5+ of the Objective-C gRPC runtime library and v3.0.0-alpha-3+ of the Objective-C Protobuf
runtime library.
@ -168,7 +168,6 @@ Objective-C Protobuf runtime library.
[Protocol Buffers]:https://developers.google.com/protocol-buffers/
[homebrew]:http://brew.sh
[linuxbrew]:https://github.com/Homebrew/linuxbrew
[gRPC install script]:https://raw.githubusercontent.com/grpc/homebrew-grpc/master/scripts/install
[example Podfile]:https://github.com/grpc/grpc/blob/master/src/objective-c/examples/Sample/Podfile
[sample app]: https://github.com/grpc/grpc/tree/master/src/objective-c/examples/Sample

@ -35,4 +35,14 @@
@implementation GRXWriter
- (void)startWithWriteable:(id<GRXWriteable>)writeable {
NSAssert(NO, @"Missing base implementation for %@", NSStringFromSelector(_cmd));
[self doesNotRecognizeSelector:_cmd];
}
- (void)finishWithError:(NSError *)errorOrNil {
NSAssert(NO, @"Missing base implementation for %@", NSStringFromSelector(_cmd));
[self doesNotRecognizeSelector:_cmd];
}
@end

@ -10,10 +10,10 @@
<email>grpc-packages@google.com</email>
<active>yes</active>
</lead>
<date>2015-09-24</date>
<time>09:51:04</time>
<date>2015-10-07</date>
<time>13:40:54</time>
<version>
<release>0.6.0</release>
<release>0.6.1</release>
<api>0.6.0</api>
</version>
<stability>
@ -22,12 +22,7 @@
</stability>
<license>BSD</license>
<notes>
- support per message compression disable
- expose per-call host override option
- expose connectivity API
- expose channel target and call peer
- add user-agent
- update to wrap gRPC C core library beta version 0.11.0
- fixed undefined constant fatal error when run with apache/nginx #2275
</notes>
<contents>
<dir baseinstalldir="/" name="/">
@ -44,7 +39,7 @@
<file baseinstalldir="/" md5sum="6988d6e97c19c8f8e3eb92371cf8246b" name="credentials.h" role="src" />
<file baseinstalldir="/" md5sum="38a1bc979d810c36ebc2a52d4b7b5319" name="CREDITS" role="doc" />
<file baseinstalldir="/" md5sum="3f35b472bbdef5a788cd90617d7d0847" name="LICENSE" role="doc" />
<file baseinstalldir="/" md5sum="6a550516a1423def0786851c76f87c85" name="php_grpc.c" role="src" />
<file baseinstalldir="/" md5sum="b77f1f3941aaf7a21090b493e9f26037" name="php_grpc.c" role="src" />
<file baseinstalldir="/" md5sum="673b07859d9f69232f8a754c56780686" name="php_grpc.h" role="src" />
<file baseinstalldir="/" md5sum="7533a6d3ea02c78cad23a9651de0825d" name="README.md" role="doc" />
<file baseinstalldir="/" md5sum="3e4e960454ebb2fc7b78a840493f5315" name="server.c" role="src" />
@ -118,5 +113,20 @@ Update to wrap gRPC C Core version 0.10.0
- update to wrap gRPC C core library beta version 0.11.0
</notes>
</release>
<release>
<version>
<release>0.6.1</release>
<api>0.6.0</api>
</version>
<stability>
<release>beta</release>
<api>beta</api>
</stability>
<date>2015-10-07</date>
<license>BSD</license>
<notes>
- fixed undefined constant fatal error when run with apache/nginx #2275
</notes>
</release>
</changelog>
</package>

@ -150,7 +150,7 @@ PHP_MINIT_FUNCTION(grpc) {
CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("Grpc\\STATUS_INVALID_ARGUMENT",
GRPC_STATUS_INVALID_ARGUMENT,
CONST_CS | CONST_PERSISTENT);
CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("Grpc\\STATUS_DEADLINE_EXCEEDED",
GRPC_STATUS_DEADLINE_EXCEEDED,
CONST_CS | CONST_PERSISTENT);
@ -173,7 +173,8 @@ PHP_MINIT_FUNCTION(grpc) {
CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("Grpc\\STATUS_ABORTED", GRPC_STATUS_ABORTED,
CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("Grpc\\STATUS_OUT_OF_RANGE", GRPC_STATUS_OUT_OF_RANGE,
REGISTER_LONG_CONSTANT("Grpc\\STATUS_OUT_OF_RANGE",
GRPC_STATUS_OUT_OF_RANGE,
CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("Grpc\\STATUS_UNIMPLEMENTED",
GRPC_STATUS_UNIMPLEMENTED,
@ -202,7 +203,8 @@ PHP_MINIT_FUNCTION(grpc) {
GRPC_OP_RECV_INITIAL_METADATA,
CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("Grpc\\OP_RECV_MESSAGE",
GRPC_OP_RECV_MESSAGE, CONST_CS | CONST_PERSISTENT);
GRPC_OP_RECV_MESSAGE,
CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("Grpc\\OP_RECV_STATUS_ON_CLIENT",
GRPC_OP_RECV_STATUS_ON_CLIENT,
CONST_CS | CONST_PERSISTENT);
@ -212,11 +214,14 @@ PHP_MINIT_FUNCTION(grpc) {
/* Register connectivity state constants */
REGISTER_LONG_CONSTANT("Grpc\\CHANNEL_IDLE",
GRPC_CHANNEL_IDLE, CONST_CS | CONST_PERSISTENT);
GRPC_CHANNEL_IDLE,
CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("Grpc\\CHANNEL_CONNECTING",
GRPC_CHANNEL_CONNECTING, CONST_CS | CONST_PERSISTENT);
GRPC_CHANNEL_CONNECTING,
CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("Grpc\\CHANNEL_READY",
GRPC_CHANNEL_READY, CONST_CS | CONST_PERSISTENT);
GRPC_CHANNEL_READY,
CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("Grpc\\CHANNEL_TRANSIENT_FAILURE",
GRPC_CHANNEL_TRANSIENT_FAILURE,
CONST_CS | CONST_PERSISTENT);

@ -114,7 +114,7 @@ class BaseStub {
return true;
}
if ($new_state == \Grpc\CHANNEL_FATAL_FAILURE) {
throw new Exception('Failed to connect to server');
throw new \Exception('Failed to connect to server');
}
return false;
}
@ -153,6 +153,25 @@ class BaseStub {
return array($metadata_copy, $timeout);
}
/**
* validate and normalize the metadata array
* @param $metadata The metadata map
* @return $metadata Validated and key-normalized metadata map
* @throw InvalidArgumentException if key contains invalid characters
*/
private function _validate_and_normalize_metadata($metadata) {
$metadata_copy = array();
foreach ($metadata as $key => $value) {
if (!preg_match('/^[A-Za-z\d_-]+$/', $key)) {
throw new \InvalidArgumentException(
'Metadata keys must be nonempty strings containing only '.
'alphanumeric characters, hyphens and underscores');
}
$metadata_copy[strtolower($key)] = $value;
}
return $metadata_copy;
}
/* This class is intended to be subclassed by generated code, so all functions
begin with "_" to avoid name collisions. */
@ -178,6 +197,7 @@ class BaseStub {
$actual_metadata,
$jwt_aud_uri);
}
$actual_metadata = $this->_validate_and_normalize_metadata($actual_metadata);
$call->start($argument, $actual_metadata, $options);
return $call;
}
@ -204,6 +224,7 @@ class BaseStub {
$actual_metadata,
$jwt_aud_uri);
}
$actual_metadata = $this->_validate_and_normalize_metadata($actual_metadata);
$call->start($actual_metadata);
return $call;
}
@ -231,6 +252,7 @@ class BaseStub {
$actual_metadata,
$jwt_aud_uri);
}
$actual_metadata = $this->_validate_and_normalize_metadata($actual_metadata);
$call->start($argument, $actual_metadata, $options);
return $call;
}
@ -254,6 +276,7 @@ class BaseStub {
$actual_metadata,
$jwt_aud_uri);
}
$actual_metadata = $this->_validate_and_normalize_metadata($actual_metadata);
$call->start($actual_metadata);
return $call;
}

@ -51,6 +51,14 @@ abstract class AbstractGeneratedCodeTest extends PHPUnit_Framework_TestCase {
$this->assertTrue(is_string(self::$client->getTarget()));
}
/**
* @expectedException InvalidArgumentException
*/
public function testInvalidMetadata() {
$div_arg = new math\DivArgs();
$call = self::$client->Div($div_arg, array(' ' => 'abc123'));
}
public function testWriteFlags() {
$div_arg = new math\DivArgs();
$div_arg->setDividend(7);

@ -250,6 +250,23 @@ function pingPong($stub) {
'Call did not complete successfully');
}
/**
* Run the empty_stream test.
* Passes when run against the Node server as of 2015-10-09
* @param $stub Stub object that has service methods.
*/
function emptyStream($stub) {
// for the current PHP implementation, $call->read() will wait
// forever for a server response if the server is not sending any.
// so this test is imeplemented as a timeout to indicate the absence
// of receiving any response from the server
$call = $stub->FullDuplexCall(array('timeout' => 100000));
$call->writesDone();
hardAssert($call->read() === null, 'Server returned too many responses');
hardAssert($call->getStatus()->code === Grpc\STATUS_OK,
'Call did not complete successfully');
}
/**
* Run the cancel_after_begin test.
* Passes when run against the Node server as of 2015-08-28
@ -370,6 +387,9 @@ switch ($args['test_case']) {
case 'ping_pong':
pingPong($stub);
break;
case 'empty_stream':
emptyStream($stub);
break;
case 'cancel_after_begin':
cancelAfterBegin($stub);
break;

@ -176,8 +176,7 @@ module GRPC
deadline: deadline,
timeout: timeout,
parent: parent)
kw_with_jwt_uri = self.class.update_with_jwt_aud_uri(kw, @host, method)
md = @update_metadata.nil? ? kw : @update_metadata.call(kw_with_jwt_uri)
md = update_metadata(kw, method)
return c.request_response(req, **md) unless return_op
# return the operation view of the active_call; define #execute as a
@ -244,8 +243,7 @@ module GRPC
deadline: deadline,
timeout: timeout,
parent: parent)
kw_with_jwt_uri = self.class.update_with_jwt_aud_uri(kw, @host, method)
md = @update_metadata.nil? ? kw : @update_metadata.call(kw_with_jwt_uri)
md = update_metadata(kw, method)
return c.client_streamer(requests, **md) unless return_op
# return the operation view of the active_call; define #execute as a
@ -322,8 +320,7 @@ module GRPC
deadline: deadline,
timeout: timeout,
parent: parent)
kw_with_jwt_uri = self.class.update_with_jwt_aud_uri(kw, @host, method)
md = @update_metadata.nil? ? kw : @update_metadata.call(kw_with_jwt_uri)
md = update_metadata(kw, method)
return c.server_streamer(req, **md, &blk) unless return_op
# return the operation view of the active_call; define #execute
@ -439,8 +436,7 @@ module GRPC
deadline: deadline,
timeout: timeout,
parent: parent)
kw_with_jwt_uri = self.class.update_with_jwt_aud_uri(kw, @host, method)
md = @update_metadata.nil? ? kw : @update_metadata.call(kw_with_jwt_uri)
md = update_metadata(kw, method)
return c.bidi_streamer(requests, **md, &blk) unless return_op
# return the operation view of the active_call; define #execute
@ -454,6 +450,16 @@ module GRPC
private
def update_metadata(kw, method)
return kw if @update_metadata.nil?
just_jwt_uri = self.class.update_with_jwt_aud_uri({}, @host, method)
updated = @update_metadata.call(just_jwt_uri)
# keys should be lowercase
updated = Hash[updated.each_pair.map { |k, v| [k.downcase, v] }]
kw.merge(updated)
end
# Creates a new active stub
#
# @param method [string] the method being called.

@ -159,6 +159,20 @@ describe 'ClientStub' do
th.join
end
it 'should downcase the keys provided by the metadata updater' do
server_port = create_test_server
host = "localhost:#{server_port}"
th = run_request_response(@sent_msg, @resp, @pass,
k1: 'downcased-key-v1', k2: 'v2')
update_md = proc do |md|
md[:K1] = 'downcased-key-v1'
md
end
stub = GRPC::ClientStub.new(host, @cq, update_metadata: update_md)
expect(get_response(stub)).to eq(@resp)
th.join
end
it 'should send a request when configured using an override channel' do
server_port = create_test_server
alt_host = "localhost:#{server_port}"

@ -1,7 +1,7 @@
%YAML 1.2
--- |
# GRPC gyp file
# This currently builds C code.
# GRPC Node gyp file
# This currently builds the Node extension and dependencies
# This file has been automatically generated from a template file.
# Please look at the templates directory instead.
# This file can be regenerated from the template by running
@ -39,54 +39,24 @@
# Some of this file is built with the help of
# https://n8.io/converting-a-c-library-to-gyp/
{
'variables': {
'config': '<!(echo $CONFIG)'
},
# TODO: Finish windows support
'target_defaults': {
'default_configuration': 'Debug',
'configurations': {
'Debug': {
'defines': [ 'DEBUG', '_DEBUG' ],
'msvs_settings': {
'VCCLCompilerTool': {
'RuntimeLibrary': 1, # static debug
},
},
},
'Release': {
'defines': [ 'NDEBUG' ],
'msvs_settings': {
'VCCLCompilerTool': {
'RuntimeLibrary': 0, # static release
},
},
}
},
'msvs_settings': {
'VCLinkerTool': {
'GenerateDebugInformation': 'true',
},
},
# TODO: Add fallback for Windows, and if pkg-config is not available
# Empirically, Node only exports ALPN symbols if its major version is >0.
# io.js always reports versions >0 and always exports ALPN symbols.
# Therefore, Node's major version will be truthy if and only if it
# supports ALPN. The output of "node -v" is v[major].[minor].[patch],
# like "v4.1.1" in a recent version. We use grep to extract just the
# major version. "4", would be the output for the example.
'defines': [
'TSI_OPENSSL_ALPN_SUPPORT=<!(pkg-config --atleast-version=1.0.2 openssl >/dev/null 2>&1 && echo 1 || echo 0)'
'TSI_OPENSSL_ALPN_SUPPORT=<!(node -v | grep -oP "(?<=v)(\d+)(?=\.\d+\.\d+)")'
],
'include_dirs': [
'.',
'include'
],
# TODO: Check for libraries with pkg-config
'libraries': [
'-lcrypto',
'-lssl',
'-ldl',
'-lpthread',
'-lz'
],
'direct_dependent_settings': {
'include_dirs': [
'.',
'include'
],
}
]
},
'targets': [
% for lib in libs:
@ -108,5 +78,65 @@
},
% endif
% endfor
{
'include_dirs': [
"<!(node -e \"require('nan')\")"
],
'cflags': [
'-std=c++0x',
'-Wall',
'-pthread',
'-g',
'-zdefs',
'-Werror',
'-Wno-error=deprecated-declarations'
],
'ldflags': [
'-g'
],
"conditions": [
['OS != "win"', {
'conditions': [
['config=="gcov"', {
'cflags': [
'-ftest-coverage',
'-fprofile-arcs',
'-O0'
],
'ldflags': [
'-ftest-coverage',
'-fprofile-arcs'
]
}
]
]
}],
['OS == "mac"', {
'xcode_settings': {
'MACOSX_DEPLOYMENT_TARGET': '10.9',
'OTHER_CFLAGS': [
'-std=c++11',
'-stdlib=libc++'
]
}
}]
],
"target_name": "grpc_node",
"sources": [
"src/node/ext/byte_buffer.cc",
"src/node/ext/call.cc",
"src/node/ext/call_credentials.cc",
"src/node/ext/channel.cc",
"src/node/ext/channel_credentials.cc",
"src/node/ext/completion_queue_async_worker.cc",
"src/node/ext/node_grpc.cc",
"src/node/ext/server.cc",
"src/node/ext/server_credentials.cc",
"src/node/ext/timeval.cc"
],
"dependencies": [
"grpc"
]
}
]
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save