grpc 1.81.1-x86_64-linux-gnu → 1.82.0.pre1-x86_64-linux-gnu
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/src/ruby/ext/grpc/rb_byte_buffer.c +1 -0
- data/src/ruby/ext/grpc/rb_call.c +3 -0
- data/src/ruby/ext/grpc/rb_call_credentials.c +1 -0
- data/src/ruby/ext/grpc/rb_channel.c +1 -0
- data/src/ruby/ext/grpc/rb_channel_args.c +1 -0
- data/src/ruby/ext/grpc/rb_channel_credentials.c +1 -0
- data/src/ruby/ext/grpc/rb_completion_queue.c +1 -0
- data/src/ruby/ext/grpc/rb_compression_options.c +1 -0
- data/src/ruby/ext/grpc/rb_grpc_imports.generated.c +4 -4
- data/src/ruby/ext/grpc/rb_grpc_imports.generated.h +6 -6
- data/src/ruby/ext/grpc/rb_server.c +1 -0
- data/src/ruby/ext/grpc/rb_server_credentials.c +1 -0
- data/src/ruby/ext/grpc/rb_xds_channel_credentials.c +1 -0
- data/src/ruby/ext/grpc/rb_xds_server_credentials.c +1 -0
- data/src/ruby/lib/grpc/3.2/grpc_c.so +0 -0
- data/src/ruby/lib/grpc/3.3/grpc_c.so +0 -0
- data/src/ruby/lib/grpc/3.4/grpc_c.so +0 -0
- data/src/ruby/lib/grpc/4.0/grpc_c.so +0 -0
- data/src/ruby/lib/grpc/core/call_credentials.rb +86 -0
- data/src/ruby/lib/grpc/core/channel_credentials.rb +69 -0
- data/src/ruby/lib/grpc/core/credentials_helper.rb +126 -0
- data/src/ruby/lib/grpc/generic/client_stub.rb +86 -73
- data/src/ruby/lib/grpc/generic/interceptors.rb +1 -1
- data/src/ruby/lib/grpc/version.rb +1 -1
- data/src/ruby/lib/grpc.rb +25 -0
- data/src/ruby/spec/call_credentials_spec.rb +52 -2
- data/src/ruby/spec/credentials_helper_spec.rb +80 -0
- data/src/ruby/spec/generic/client_stub_spec.rb +27 -4
- data/src/ruby/spec/generic/server_interceptors_spec.rb +17 -3
- metadata +7 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5881bb63318f3857ae2ce5e34641762b423bb32d9b56bdae2199712a7ec3f134
|
|
4
|
+
data.tar.gz: 04b0842077a131d977ae3582be631dd6ca0f193519c8ed0ef0e0bab90261feb5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a8d113a85c9b333084878e443ca590a614d0880369ee26ea494d1682925542fffccadb72057f93ec1b2e7f02e8aec84749acd3fd32f4f4a6e987c8008194119c
|
|
7
|
+
data.tar.gz: 4ecb955656af24bf55fdc4b859cbc634094245a747c7f08adc0553174825c4f95d74d3c27c2d23d3b3145ce80f5761f9ece4b5b000d7f457edfaf1953b6063a2
|
data/src/ruby/ext/grpc/rb_call.c
CHANGED
|
@@ -23,8 +23,11 @@
|
|
|
23
23
|
#include <grpc/grpc.h>
|
|
24
24
|
#include <grpc/impl/codegen/compression_types.h>
|
|
25
25
|
#include <grpc/support/alloc.h>
|
|
26
|
+
#include <stdbool.h>
|
|
26
27
|
|
|
27
28
|
#include "rb_byte_buffer.h"
|
|
29
|
+
/* TODO(nnepal): Include grpc/grpc_security.h for pure ruby call
|
|
30
|
+
* credentials after rb_call_credentials gets removed */
|
|
28
31
|
#include "rb_call_credentials.h"
|
|
29
32
|
#include "rb_completion_queue.h"
|
|
30
33
|
#include "rb_grpc.h"
|
|
@@ -159,9 +159,9 @@ grpc_server_register_method_type grpc_server_register_method_import;
|
|
|
159
159
|
grpc_server_request_registered_call_type grpc_server_request_registered_call_import;
|
|
160
160
|
grpc_server_create_type grpc_server_create_import;
|
|
161
161
|
grpc_server_register_completion_queue_type grpc_server_register_completion_queue_import;
|
|
162
|
+
grpc_server_config_fetcher_arg_vtable_type grpc_server_config_fetcher_arg_vtable_import;
|
|
162
163
|
grpc_server_config_fetcher_xds_create_type grpc_server_config_fetcher_xds_create_import;
|
|
163
|
-
|
|
164
|
-
grpc_server_set_config_fetcher_type grpc_server_set_config_fetcher_import;
|
|
164
|
+
grpc_server_config_fetcher_unref_type grpc_server_config_fetcher_unref_import;
|
|
165
165
|
grpc_server_add_http2_port_type grpc_server_add_http2_port_import;
|
|
166
166
|
grpc_server_start_type grpc_server_start_import;
|
|
167
167
|
grpc_server_shutdown_and_notify_type grpc_server_shutdown_and_notify_import;
|
|
@@ -448,9 +448,9 @@ void grpc_rb_load_imports(HMODULE library) {
|
|
|
448
448
|
grpc_server_request_registered_call_import = (grpc_server_request_registered_call_type) GetProcAddress(library, "grpc_server_request_registered_call");
|
|
449
449
|
grpc_server_create_import = (grpc_server_create_type) GetProcAddress(library, "grpc_server_create");
|
|
450
450
|
grpc_server_register_completion_queue_import = (grpc_server_register_completion_queue_type) GetProcAddress(library, "grpc_server_register_completion_queue");
|
|
451
|
+
grpc_server_config_fetcher_arg_vtable_import = (grpc_server_config_fetcher_arg_vtable_type) GetProcAddress(library, "grpc_server_config_fetcher_arg_vtable");
|
|
451
452
|
grpc_server_config_fetcher_xds_create_import = (grpc_server_config_fetcher_xds_create_type) GetProcAddress(library, "grpc_server_config_fetcher_xds_create");
|
|
452
|
-
|
|
453
|
-
grpc_server_set_config_fetcher_import = (grpc_server_set_config_fetcher_type) GetProcAddress(library, "grpc_server_set_config_fetcher");
|
|
453
|
+
grpc_server_config_fetcher_unref_import = (grpc_server_config_fetcher_unref_type) GetProcAddress(library, "grpc_server_config_fetcher_unref");
|
|
454
454
|
grpc_server_add_http2_port_import = (grpc_server_add_http2_port_type) GetProcAddress(library, "grpc_server_add_http2_port");
|
|
455
455
|
grpc_server_start_import = (grpc_server_start_type) GetProcAddress(library, "grpc_server_start");
|
|
456
456
|
grpc_server_shutdown_and_notify_import = (grpc_server_shutdown_and_notify_type) GetProcAddress(library, "grpc_server_shutdown_and_notify");
|
|
@@ -453,15 +453,15 @@ extern grpc_server_create_type grpc_server_create_import;
|
|
|
453
453
|
typedef void(*grpc_server_register_completion_queue_type)(grpc_server* server, grpc_completion_queue* cq, void* reserved);
|
|
454
454
|
extern grpc_server_register_completion_queue_type grpc_server_register_completion_queue_import;
|
|
455
455
|
#define grpc_server_register_completion_queue grpc_server_register_completion_queue_import
|
|
456
|
+
typedef const grpc_arg_pointer_vtable*(*grpc_server_config_fetcher_arg_vtable_type)(void);
|
|
457
|
+
extern grpc_server_config_fetcher_arg_vtable_type grpc_server_config_fetcher_arg_vtable_import;
|
|
458
|
+
#define grpc_server_config_fetcher_arg_vtable grpc_server_config_fetcher_arg_vtable_import
|
|
456
459
|
typedef grpc_server_config_fetcher*(*grpc_server_config_fetcher_xds_create_type)(grpc_server_xds_status_notifier notifier, const grpc_channel_args* args);
|
|
457
460
|
extern grpc_server_config_fetcher_xds_create_type grpc_server_config_fetcher_xds_create_import;
|
|
458
461
|
#define grpc_server_config_fetcher_xds_create grpc_server_config_fetcher_xds_create_import
|
|
459
|
-
typedef void(*
|
|
460
|
-
extern
|
|
461
|
-
#define
|
|
462
|
-
typedef void(*grpc_server_set_config_fetcher_type)(grpc_server* server, grpc_server_config_fetcher* config_fetcher);
|
|
463
|
-
extern grpc_server_set_config_fetcher_type grpc_server_set_config_fetcher_import;
|
|
464
|
-
#define grpc_server_set_config_fetcher grpc_server_set_config_fetcher_import
|
|
462
|
+
typedef void(*grpc_server_config_fetcher_unref_type)(grpc_server_config_fetcher* config_fetcher);
|
|
463
|
+
extern grpc_server_config_fetcher_unref_type grpc_server_config_fetcher_unref_import;
|
|
464
|
+
#define grpc_server_config_fetcher_unref grpc_server_config_fetcher_unref_import
|
|
465
465
|
typedef int(*grpc_server_add_http2_port_type)(grpc_server* server, const char* addr, grpc_server_credentials* creds);
|
|
466
466
|
extern grpc_server_add_http2_port_type grpc_server_add_http2_port_import;
|
|
467
467
|
#define grpc_server_add_http2_port grpc_server_add_http2_port_import
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Copyright 2026 gRPC authors.
|
|
4
|
+
#
|
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
# you may not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
|
|
17
|
+
module GRPC
|
|
18
|
+
module Core
|
|
19
|
+
# CallCredentials represents per-call credentials.
|
|
20
|
+
class CallCredentials
|
|
21
|
+
attr_reader :auth_proc
|
|
22
|
+
|
|
23
|
+
def initialize(auth_proc = nil, &block)
|
|
24
|
+
@auth_proc = auth_proc || block
|
|
25
|
+
fail TypeError, 'Argument to CallCredentials#new must be a proc' unless @auth_proc.is_a?(Proc)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def get_metadata(context)
|
|
29
|
+
@auth_proc.call(context)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def composite?
|
|
33
|
+
false
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def compose(*others)
|
|
37
|
+
return self if others.empty?
|
|
38
|
+
valid_others = validate_credentials_list!(others)
|
|
39
|
+
CompositeCallCredentials.new([self] + valid_others)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
def validate_credentials_list!(list)
|
|
45
|
+
list.flatten.each do |o|
|
|
46
|
+
fail TypeError, "Argument to compose must be a CallCredentials, got #{o.class}" \
|
|
47
|
+
unless o.is_a?(CallCredentials)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
class CompositeCallCredentials < CallCredentials
|
|
53
|
+
def initialize(*creds)
|
|
54
|
+
flat_creds = creds.flatten.flat_map do |c|
|
|
55
|
+
c.composite? ? c.creds : c
|
|
56
|
+
end
|
|
57
|
+
@creds = flat_creds.uniq
|
|
58
|
+
super(proc { |context| get_metadata(context) })
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def composite?
|
|
62
|
+
true
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def get_metadata(context)
|
|
66
|
+
@creds.each_with_object({}) do |c, metadata|
|
|
67
|
+
creds_metadata = c.get_metadata(context)
|
|
68
|
+
next unless creds_metadata
|
|
69
|
+
metadata.merge!(
|
|
70
|
+
creds_metadata.is_a?(Hash) ? creds_metadata : fail(TypeError, "Call credentials must return Hash or nil, got #{creds_metadata.class}")
|
|
71
|
+
)
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def compose(*others)
|
|
76
|
+
return self if others.empty?
|
|
77
|
+
valid_others = validate_credentials_list!(others)
|
|
78
|
+
CompositeCallCredentials.new(@creds + valid_others)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
protected
|
|
82
|
+
|
|
83
|
+
attr_reader :creds
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Copyright 2026 gRPC authors.
|
|
4
|
+
#
|
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
# you may not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
|
|
17
|
+
module GRPC
|
|
18
|
+
module Core
|
|
19
|
+
# Provides shared #compose logic for channel credential classes.
|
|
20
|
+
# @api private
|
|
21
|
+
module ChannelCredentialsComposable
|
|
22
|
+
def compose(*others)
|
|
23
|
+
return self if others.empty?
|
|
24
|
+
flat_others = others.flatten
|
|
25
|
+
|
|
26
|
+
flat_others.each do |o|
|
|
27
|
+
fail TypeError, "Argument to compose must be a CallCredentials, got #{o.class}" \
|
|
28
|
+
unless o.is_a?(CallCredentials)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
call_creds = flat_others.size == 1 ? flat_others.first : CompositeCallCredentials.new(flat_others)
|
|
32
|
+
CompositeChannelCredentials.new(self, call_creds)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
class ChannelCredentials
|
|
37
|
+
prepend ChannelCredentialsComposable
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
class XdsChannelCredentials
|
|
41
|
+
prepend ChannelCredentialsComposable
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
class CompositeChannelCredentials
|
|
45
|
+
attr_reader :channel_credentials, :call_credentials
|
|
46
|
+
|
|
47
|
+
def initialize(channel_creds, call_creds)
|
|
48
|
+
@channel_credentials = channel_creds
|
|
49
|
+
@call_credentials = call_creds
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def compose(*others)
|
|
53
|
+
return self if others.empty?
|
|
54
|
+
flat_others = others.flatten
|
|
55
|
+
|
|
56
|
+
flat_others.each do |o|
|
|
57
|
+
fail TypeError, "Argument to compose must be a CallCredentials, got #{o.class}" \
|
|
58
|
+
unless o.is_a?(CallCredentials)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
if @call_credentials
|
|
62
|
+
CompositeChannelCredentials.new(@channel_credentials, @call_credentials.compose(*flat_others))
|
|
63
|
+
else
|
|
64
|
+
CompositeChannelCredentials.new(@channel_credentials, CompositeCallCredentials.new(flat_others))
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# Copyright 2026 gRPC authors.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
module GRPC
|
|
16
|
+
module Core
|
|
17
|
+
# Utility methods for resolving and applying call credentials to metadata.
|
|
18
|
+
# @api private
|
|
19
|
+
module CallCredentialsHelper
|
|
20
|
+
VALID_HEADER_KEY_PATTERN = /\A[a-z0-9\-_.]+\z/
|
|
21
|
+
|
|
22
|
+
# Composes channel and per-call credentials when both present, otherwise
|
|
23
|
+
# returns whichever is available.
|
|
24
|
+
def self.resolve(channel_call_creds, call_credentials)
|
|
25
|
+
return channel_call_creds.compose(call_credentials) if channel_call_creds && call_credentials
|
|
26
|
+
channel_call_creds || call_credentials
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Returns true if +key+ is a valid gRPC metadata header key.
|
|
30
|
+
def self.valid_header_key?(key)
|
|
31
|
+
!key.nil? && !key.empty? && VALID_HEADER_KEY_PATTERN.match?(key)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Parses an RPC method path into [service_url, method_name].
|
|
35
|
+
# e.g. '/echo.EchoServer/Echo' on 'foo.test.google.fr' gives
|
|
36
|
+
# ['https://foo.test.google.fr/echo.EchoServer', 'Echo'].
|
|
37
|
+
def self.parse_method_info(ssl_target, method)
|
|
38
|
+
return ["https://#{ssl_target}", nil] if method.nil? || method.empty?
|
|
39
|
+
last_slash = method.rindex('/')
|
|
40
|
+
service_path = last_slash&.positive? ? method[0, last_slash] : ''
|
|
41
|
+
[
|
|
42
|
+
"https://#{ssl_target}#{service_path}",
|
|
43
|
+
last_slash ? method[(last_slash + 1)..] : nil
|
|
44
|
+
]
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Merges +creds_metadata+ into +metadata+, validating all keys.
|
|
48
|
+
# Raises GRPC::Unavailable on invalid type or illegal header keys.
|
|
49
|
+
def self.merge_creds_metadata!(creds_metadata, metadata)
|
|
50
|
+
return if creds_metadata.nil?
|
|
51
|
+
unless creds_metadata.is_a?(Hash)
|
|
52
|
+
fail GRPC::Unavailable, "Call credentials must return Hash or nil, got #{creds_metadata.class}"
|
|
53
|
+
end
|
|
54
|
+
creds_metadata.each do |key, value|
|
|
55
|
+
key_str = key.to_s
|
|
56
|
+
unless valid_header_key?(key_str)
|
|
57
|
+
fail GRPC::Unavailable, "Illegal metadata: '#{key_str}' is an invalid header key"
|
|
58
|
+
end
|
|
59
|
+
metadata[key_str] = value.is_a?(Array) ? value.map(&:to_s) : value.to_s
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Calls +credentials.get_metadata+ and merges the result into +metadata+.
|
|
64
|
+
# No-op when +credentials+ is nil or the channel is insecure.
|
|
65
|
+
# Raises GRPC::Unavailable on failure.
|
|
66
|
+
def self.apply(credentials, metadata, ssl_target, channel_creds, method = nil)
|
|
67
|
+
return unless credentials
|
|
68
|
+
return if channel_creds == :this_channel_is_insecure
|
|
69
|
+
service_url, method_name = parse_method_info(ssl_target, method)
|
|
70
|
+
context = { service_url: service_url, jwt_aud_uri: service_url, method_name: method_name }
|
|
71
|
+
begin
|
|
72
|
+
merge_creds_metadata!(credentials.get_metadata(context), metadata)
|
|
73
|
+
rescue GRPC::BadStatus
|
|
74
|
+
raise
|
|
75
|
+
rescue StandardError => e
|
|
76
|
+
fail GRPC::Unavailable, "Call credentials failed: #{e.message}"
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Prepended into ClientStub when the pure Ruby credentials path is active.
|
|
82
|
+
# Handles CompositeChannelCredentials splitting and applies credentials via
|
|
83
|
+
# metadata injection instead of the C extension set_credentials! path.
|
|
84
|
+
# @api private
|
|
85
|
+
module CompositeCredentialsHandler
|
|
86
|
+
def initialize(host, creds,
|
|
87
|
+
channel_override: nil,
|
|
88
|
+
timeout: nil,
|
|
89
|
+
propagate_mask: nil,
|
|
90
|
+
channel_args: {},
|
|
91
|
+
interceptors: [])
|
|
92
|
+
if creds.is_a?(Core::CompositeChannelCredentials)
|
|
93
|
+
pure_call_creds = creds.call_credentials
|
|
94
|
+
creds = creds.channel_credentials
|
|
95
|
+
super(host, creds,
|
|
96
|
+
channel_override: channel_override,
|
|
97
|
+
timeout: timeout,
|
|
98
|
+
propagate_mask: propagate_mask,
|
|
99
|
+
channel_args: channel_args,
|
|
100
|
+
interceptors: interceptors)
|
|
101
|
+
@call_creds = pure_call_creds
|
|
102
|
+
else
|
|
103
|
+
super
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# credentials is intentionally overridden to nil in super to skip set_credentials!
|
|
108
|
+
def new_active_call(method, marshal, unmarshal,
|
|
109
|
+
deadline: nil,
|
|
110
|
+
parent: nil,
|
|
111
|
+
credentials: nil) # rubocop:disable Lint/UnusedMethodArgument
|
|
112
|
+
super(method, marshal, unmarshal,
|
|
113
|
+
deadline: deadline,
|
|
114
|
+
parent: parent,
|
|
115
|
+
credentials: nil)
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
private
|
|
119
|
+
|
|
120
|
+
def resolve_call_metadata(metadata, credentials, method)
|
|
121
|
+
resolved = CallCredentialsHelper.resolve(@call_creds, credentials)
|
|
122
|
+
metadata.dup.tap { |m| CallCredentialsHelper.apply(resolved, m, @host, @channel_creds, method) }
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
@@ -79,10 +79,9 @@ module GRPC
|
|
|
79
79
|
# when present, this is the default timeout used for calls
|
|
80
80
|
#
|
|
81
81
|
# @param host [String] the host the stub connects to
|
|
82
|
-
# @param creds [Core::ChannelCredentials|Symbol]
|
|
83
|
-
#
|
|
84
|
-
#
|
|
85
|
-
# ignored if the channel_override argument is provided.
|
|
82
|
+
# @param creds [Core::ChannelCredentials|Core::CallCredentials|Symbol]
|
|
83
|
+
# ChannelCredentials, CallCredentials (creates default SSL channel), or
|
|
84
|
+
# :this_channel_is_insecure. Ignored if channel_override is provided.
|
|
86
85
|
# @param channel_override [Core::Channel] a pre-created channel
|
|
87
86
|
# @param timeout [Number] the default timeout to use in requests
|
|
88
87
|
# @param propagate_mask [Number] A bitwise combination of flags in
|
|
@@ -101,7 +100,18 @@ module GRPC
|
|
|
101
100
|
propagate_mask: nil,
|
|
102
101
|
channel_args: {},
|
|
103
102
|
interceptors: [])
|
|
104
|
-
|
|
103
|
+
# Split credentials: CallCredentials alone create a default secure channel.
|
|
104
|
+
# CompositeChannelCredentials splitting is handled by Core::CompositeCredentialsHandler
|
|
105
|
+
# module when the pure Ruby toggle is enabled.
|
|
106
|
+
if creds.is_a?(Core::CallCredentials)
|
|
107
|
+
@call_creds = creds
|
|
108
|
+
@channel_creds = Core::ChannelCredentials.new
|
|
109
|
+
else
|
|
110
|
+
@call_creds = nil
|
|
111
|
+
@channel_creds = creds
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
@ch = ClientStub.setup_channel(channel_override, host, @channel_creds,
|
|
105
115
|
channel_args.dup)
|
|
106
116
|
alt_host = channel_args[Core::Channel::SSL_TARGET]
|
|
107
117
|
@host = alt_host.nil? ? host : alt_host
|
|
@@ -154,30 +164,19 @@ module GRPC
|
|
|
154
164
|
credentials: nil,
|
|
155
165
|
metadata: {})
|
|
156
166
|
c = new_active_call(method, marshal, unmarshal,
|
|
157
|
-
deadline: deadline,
|
|
158
|
-
parent: parent,
|
|
167
|
+
deadline: deadline, parent: parent,
|
|
159
168
|
credentials: credentials)
|
|
160
|
-
|
|
169
|
+
|
|
161
170
|
intercept_args = {
|
|
162
171
|
method: method,
|
|
163
172
|
request: req,
|
|
164
173
|
call: c.interceptable,
|
|
165
174
|
metadata: metadata
|
|
166
175
|
}
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
op = c.operation
|
|
172
|
-
op.define_singleton_method(:execute) do
|
|
173
|
-
interception_context.intercept!(:request_response, intercept_args) do
|
|
174
|
-
c.request_response(req, metadata: metadata)
|
|
175
|
-
end
|
|
176
|
-
end
|
|
177
|
-
op
|
|
178
|
-
else
|
|
179
|
-
interception_context.intercept!(:request_response, intercept_args) do
|
|
180
|
-
c.request_response(req, metadata: metadata)
|
|
176
|
+
|
|
177
|
+
handle_return_op(c, return_op, metadata, credentials, method) do
|
|
178
|
+
execute_with_interceptors(:request_response, intercept_args, credentials, method, c) do |resolved_md|
|
|
179
|
+
c.request_response(req, metadata: resolved_md)
|
|
181
180
|
end
|
|
182
181
|
end
|
|
183
182
|
end
|
|
@@ -231,30 +230,19 @@ module GRPC
|
|
|
231
230
|
credentials: nil,
|
|
232
231
|
metadata: {})
|
|
233
232
|
c = new_active_call(method, marshal, unmarshal,
|
|
234
|
-
deadline: deadline,
|
|
235
|
-
parent: parent,
|
|
233
|
+
deadline: deadline, parent: parent,
|
|
236
234
|
credentials: credentials)
|
|
237
|
-
|
|
235
|
+
|
|
238
236
|
intercept_args = {
|
|
239
237
|
method: method,
|
|
240
238
|
requests: requests,
|
|
241
239
|
call: c.interceptable,
|
|
242
240
|
metadata: metadata
|
|
243
241
|
}
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
op = c.operation
|
|
249
|
-
op.define_singleton_method(:execute) do
|
|
250
|
-
interception_context.intercept!(:client_streamer, intercept_args) do
|
|
251
|
-
c.client_streamer(requests)
|
|
252
|
-
end
|
|
253
|
-
end
|
|
254
|
-
op
|
|
255
|
-
else
|
|
256
|
-
interception_context.intercept!(:client_streamer, intercept_args) do
|
|
257
|
-
c.client_streamer(requests, metadata: metadata)
|
|
242
|
+
|
|
243
|
+
handle_return_op(c, return_op, metadata, credentials, method) do
|
|
244
|
+
execute_with_interceptors(:client_streamer, intercept_args, credentials, method, c) do |resolved_md|
|
|
245
|
+
c.client_streamer(requests, metadata: resolved_md)
|
|
258
246
|
end
|
|
259
247
|
end
|
|
260
248
|
end
|
|
@@ -323,30 +311,19 @@ module GRPC
|
|
|
323
311
|
metadata: {},
|
|
324
312
|
&blk)
|
|
325
313
|
c = new_active_call(method, marshal, unmarshal,
|
|
326
|
-
deadline: deadline,
|
|
327
|
-
parent: parent,
|
|
314
|
+
deadline: deadline, parent: parent,
|
|
328
315
|
credentials: credentials)
|
|
329
|
-
|
|
316
|
+
|
|
330
317
|
intercept_args = {
|
|
331
318
|
method: method,
|
|
332
319
|
request: req,
|
|
333
320
|
call: c.interceptable,
|
|
334
321
|
metadata: metadata
|
|
335
322
|
}
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
op = c.operation
|
|
341
|
-
op.define_singleton_method(:execute) do
|
|
342
|
-
interception_context.intercept!(:server_streamer, intercept_args) do
|
|
343
|
-
c.server_streamer(req, &blk)
|
|
344
|
-
end
|
|
345
|
-
end
|
|
346
|
-
op
|
|
347
|
-
else
|
|
348
|
-
interception_context.intercept!(:server_streamer, intercept_args) do
|
|
349
|
-
c.server_streamer(req, metadata: metadata, &blk)
|
|
323
|
+
|
|
324
|
+
handle_return_op(c, return_op, metadata, credentials, method) do
|
|
325
|
+
execute_with_interceptors(:server_streamer, intercept_args, credentials, method, c) do |resolved_md|
|
|
326
|
+
c.server_streamer(req, metadata: resolved_md, &blk)
|
|
350
327
|
end
|
|
351
328
|
end
|
|
352
329
|
end
|
|
@@ -445,30 +422,19 @@ module GRPC
|
|
|
445
422
|
metadata: {},
|
|
446
423
|
&blk)
|
|
447
424
|
c = new_active_call(method, marshal, unmarshal,
|
|
448
|
-
deadline: deadline,
|
|
449
|
-
parent: parent,
|
|
425
|
+
deadline: deadline, parent: parent,
|
|
450
426
|
credentials: credentials)
|
|
451
|
-
|
|
427
|
+
|
|
452
428
|
intercept_args = {
|
|
453
429
|
method: method,
|
|
454
430
|
requests: requests,
|
|
455
431
|
call: c.interceptable,
|
|
456
432
|
metadata: metadata
|
|
457
433
|
}
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
op = c.operation
|
|
463
|
-
op.define_singleton_method(:execute) do
|
|
464
|
-
interception_context.intercept!(:bidi_streamer, intercept_args) do
|
|
465
|
-
c.bidi_streamer(requests, &blk)
|
|
466
|
-
end
|
|
467
|
-
end
|
|
468
|
-
op
|
|
469
|
-
else
|
|
470
|
-
interception_context.intercept!(:bidi_streamer, intercept_args) do
|
|
471
|
-
c.bidi_streamer(requests, metadata: metadata, &blk)
|
|
434
|
+
|
|
435
|
+
handle_return_op(c, return_op, metadata, credentials, method) do
|
|
436
|
+
execute_with_interceptors(:bidi_streamer, intercept_args, credentials, method, c) do |resolved_md|
|
|
437
|
+
c.bidi_streamer(requests, metadata: resolved_md, &blk)
|
|
472
438
|
end
|
|
473
439
|
end
|
|
474
440
|
end
|
|
@@ -480,6 +446,7 @@ module GRPC
|
|
|
480
446
|
# @param method [string] the method being called.
|
|
481
447
|
# @param marshal [Function] f(obj)->string that marshals requests
|
|
482
448
|
# @param unmarshal [Function] f(string)->obj that unmarshals responses
|
|
449
|
+
# @param deadline [Time] (optional) the time the request should complete
|
|
483
450
|
# @param parent [Grpc::Call] a parent call, available when calls are
|
|
484
451
|
# made from server
|
|
485
452
|
# @param credentials [Core::CallCredentials] credentials to use when making
|
|
@@ -499,5 +466,51 @@ module GRPC
|
|
|
499
466
|
ActiveCall.new(call, marshal, unmarshal, deadline,
|
|
500
467
|
started: false)
|
|
501
468
|
end
|
|
469
|
+
|
|
470
|
+
# Runs the interceptor chain and resolves metadata/credentials exactly once
|
|
471
|
+
# at the end of the chain.
|
|
472
|
+
def execute_with_interceptors(rpc_type, intercept_args, credentials, method, call)
|
|
473
|
+
interception_context = @interceptors.build_context
|
|
474
|
+
call_started = false
|
|
475
|
+
already_finished = !call.status.nil?
|
|
476
|
+
begin
|
|
477
|
+
interception_context.intercept!(rpc_type, intercept_args) do
|
|
478
|
+
resolved_md = resolve_call_metadata(intercept_args[:metadata], credentials, method)
|
|
479
|
+
call_started = true
|
|
480
|
+
yield(resolved_md)
|
|
481
|
+
end
|
|
482
|
+
rescue StandardError => e
|
|
483
|
+
call.op_is_done unless call_started || already_finished
|
|
484
|
+
raise e
|
|
485
|
+
end
|
|
486
|
+
end
|
|
487
|
+
|
|
488
|
+
# Handles return_op lifecycle branching
|
|
489
|
+
def handle_return_op(call, return_op, metadata, credentials, method, &block)
|
|
490
|
+
if return_op
|
|
491
|
+
stub = self
|
|
492
|
+
op = call.operation
|
|
493
|
+
op.define_singleton_method(:execute) do
|
|
494
|
+
block.call
|
|
495
|
+
end
|
|
496
|
+
op.define_singleton_method(:start_call) do |op_metadata = {}|
|
|
497
|
+
resolved_md = stub.send(:resolve_call_metadata, metadata, credentials, method)
|
|
498
|
+
call.merge_metadata_to_send(resolved_md.merge(op_metadata))
|
|
499
|
+
call.send_initial_metadata
|
|
500
|
+
rescue StandardError => e
|
|
501
|
+
call.op_is_done unless call.metadata_sent
|
|
502
|
+
raise e
|
|
503
|
+
end
|
|
504
|
+
op
|
|
505
|
+
else
|
|
506
|
+
yield
|
|
507
|
+
end
|
|
508
|
+
end
|
|
509
|
+
|
|
510
|
+
def resolve_call_metadata(metadata, _credentials, _method)
|
|
511
|
+
metadata
|
|
512
|
+
end
|
|
513
|
+
|
|
514
|
+
private :resolve_call_metadata, :execute_with_interceptors, :handle_return_op
|
|
502
515
|
end
|
|
503
516
|
end
|
data/src/ruby/lib/grpc.rb
CHANGED
|
@@ -22,6 +22,25 @@ require_relative 'grpc/notifier'
|
|
|
22
22
|
require_relative 'grpc/version'
|
|
23
23
|
require_relative 'grpc/core/status_codes'
|
|
24
24
|
require_relative 'grpc/core/time_consts'
|
|
25
|
+
|
|
26
|
+
# Feature toggle: set GRPC_EXPERIMENTS=pure_ruby_call_credentials to enable.
|
|
27
|
+
# Default (false): uses C extension path for backward compatibility.
|
|
28
|
+
# NOTE: must be set before `require 'grpc'` — evaluated once at load time.
|
|
29
|
+
module GRPC
|
|
30
|
+
PURE_RUBY_CALL_CREDENTIALS_ENABLED =
|
|
31
|
+
ENV.fetch('GRPC_EXPERIMENTS', '')
|
|
32
|
+
.split(',')
|
|
33
|
+
.map(&:strip)
|
|
34
|
+
.include?('pure_ruby_call_credentials')
|
|
35
|
+
.freeze
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
if GRPC::PURE_RUBY_CALL_CREDENTIALS_ENABLED
|
|
39
|
+
require_relative 'grpc/core/call_credentials'
|
|
40
|
+
require_relative 'grpc/core/channel_credentials'
|
|
41
|
+
require_relative 'grpc/core/credentials_helper'
|
|
42
|
+
end
|
|
43
|
+
|
|
25
44
|
require_relative 'grpc/generic/active_call'
|
|
26
45
|
require_relative 'grpc/generic/client_stub'
|
|
27
46
|
require_relative 'grpc/generic/service'
|
|
@@ -35,3 +54,9 @@ begin
|
|
|
35
54
|
ensure
|
|
36
55
|
file.close
|
|
37
56
|
end
|
|
57
|
+
|
|
58
|
+
# Prepend CompositeCredentialsHandler if pure Ruby credentials are enabled.
|
|
59
|
+
# This must happen after all credential classes are loaded.
|
|
60
|
+
if GRPC::PURE_RUBY_CALL_CREDENTIALS_ENABLED
|
|
61
|
+
GRPC::ClientStub.class_eval { prepend GRPC::Core::CompositeCredentialsHandler }
|
|
62
|
+
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
# Copyright 2015 gRPC authors.
|
|
2
4
|
#
|
|
3
5
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
@@ -16,20 +18,35 @@ require 'spec_helper'
|
|
|
16
18
|
|
|
17
19
|
describe GRPC::Core::CallCredentials do
|
|
18
20
|
CallCredentials = GRPC::Core::CallCredentials
|
|
19
|
-
|
|
20
21
|
let(:auth_proc) { proc { { 'plugin_key' => 'plugin_value' } } }
|
|
22
|
+
let(:auth_proc2) { proc { { 'plugin_key2' => 'plugin_value2' } } }
|
|
21
23
|
|
|
22
24
|
describe '#new' do
|
|
23
25
|
it 'can successfully create a CallCredentials from a proc' do
|
|
24
26
|
expect { CallCredentials.new(auth_proc) }.not_to raise_error
|
|
25
27
|
end
|
|
28
|
+
|
|
29
|
+
context 'pure Ruby path only' do
|
|
30
|
+
before do
|
|
31
|
+
skip 'pure Ruby path only: set GRPC_EXPERIMENTS=pure_ruby_call_credentials' \
|
|
32
|
+
unless GRPC::PURE_RUBY_CALL_CREDENTIALS_ENABLED
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
it 'can successfully create a CallCredentials from a block' do
|
|
36
|
+
expect { CallCredentials.new { { 'foo' => 'bar' } } }.not_to raise_error
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
it 'fails if initialized without a proc or block' do
|
|
41
|
+
expect { CallCredentials.new('not a proc') }.to raise_error(TypeError)
|
|
42
|
+
end
|
|
26
43
|
end
|
|
27
44
|
|
|
28
45
|
describe '#compose' do
|
|
29
46
|
it 'can compose with another CallCredentials' do
|
|
30
47
|
creds1 = CallCredentials.new(auth_proc)
|
|
31
48
|
creds2 = CallCredentials.new(auth_proc)
|
|
32
|
-
expect { creds1.compose
|
|
49
|
+
expect { creds1.compose(creds2) }.not_to raise_error
|
|
33
50
|
end
|
|
34
51
|
|
|
35
52
|
it 'can compose with multiple CallCredentials' do
|
|
@@ -38,5 +55,38 @@ describe GRPC::Core::CallCredentials do
|
|
|
38
55
|
creds3 = CallCredentials.new(auth_proc)
|
|
39
56
|
expect { creds1.compose(creds2, creds3) }.not_to raise_error
|
|
40
57
|
end
|
|
58
|
+
|
|
59
|
+
context 'pure Ruby path only' do
|
|
60
|
+
before do
|
|
61
|
+
skip 'pure Ruby path only: set GRPC_EXPERIMENTS=pure_ruby_call_credentials' \
|
|
62
|
+
unless GRPC::PURE_RUBY_CALL_CREDENTIALS_ENABLED
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
it 'returns a CompositeCallCredentials with merged metadata' do
|
|
66
|
+
creds1 = CallCredentials.new(auth_proc)
|
|
67
|
+
creds2 = CallCredentials.new(auth_proc2)
|
|
68
|
+
composite = creds1.compose(creds2)
|
|
69
|
+
expect(composite).to be_a(GRPC::Core::CompositeCallCredentials)
|
|
70
|
+
expect(composite.get_metadata(nil))
|
|
71
|
+
.to eq({ 'plugin_key' => 'plugin_value', 'plugin_key2' => 'plugin_value2' })
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
it 'returns a CompositeCallCredentials when composing multiple' do
|
|
75
|
+
creds1 = CallCredentials.new(auth_proc)
|
|
76
|
+
creds2 = CallCredentials.new(auth_proc2)
|
|
77
|
+
creds3 = CallCredentials.new(proc { { 'plugin_key3' => 'plugin_value3' } })
|
|
78
|
+
composite = creds1.compose(creds2, creds3)
|
|
79
|
+
expect(composite).to be_a(GRPC::Core::CompositeCallCredentials)
|
|
80
|
+
expect(composite.get_metadata(nil))
|
|
81
|
+
.to eq({ 'plugin_key' => 'plugin_value',
|
|
82
|
+
'plugin_key2' => 'plugin_value2',
|
|
83
|
+
'plugin_key3' => 'plugin_value3' })
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
it 'fails if composed with non-CallCredentials' do
|
|
87
|
+
creds1 = CallCredentials.new(auth_proc)
|
|
88
|
+
expect { creds1.compose('not a cred') }.to raise_error(TypeError)
|
|
89
|
+
end
|
|
90
|
+
end
|
|
41
91
|
end
|
|
42
92
|
end
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# Copyright 2015 gRPC authors.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
require 'spec_helper'
|
|
16
|
+
require 'grpc/core/credentials_helper'
|
|
17
|
+
|
|
18
|
+
describe GRPC::Core::CallCredentialsHelper do
|
|
19
|
+
before(:each) do
|
|
20
|
+
skip 'pure Ruby path only: set GRPC_EXPERIMENTS=pure_ruby_call_credentials' \
|
|
21
|
+
unless GRPC::PURE_RUBY_CALL_CREDENTIALS_ENABLED
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
describe '.resolve' do
|
|
25
|
+
it 'returns nil if both are nil' do
|
|
26
|
+
expect(GRPC::Core::CallCredentialsHelper.resolve(nil, nil)).to eq(nil)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it 'returns channel creds if call creds are nil' do
|
|
30
|
+
creds = double('creds')
|
|
31
|
+
expect(GRPC::Core::CallCredentialsHelper.resolve(creds, nil)).to eq(creds)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it 'returns call creds if channel creds are nil' do
|
|
35
|
+
creds = double('creds')
|
|
36
|
+
expect(GRPC::Core::CallCredentialsHelper.resolve(nil, creds)).to eq(creds)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
it 'composes if both are present' do
|
|
40
|
+
creds1 = double('creds1')
|
|
41
|
+
creds2 = double('creds2')
|
|
42
|
+
expect(creds1).to receive(:compose).with(creds2).and_return('composite')
|
|
43
|
+
expect(GRPC::Core::CallCredentialsHelper.resolve(creds1, creds2)).to eq('composite')
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
describe '.apply' do
|
|
48
|
+
let(:metadata) { {} }
|
|
49
|
+
let(:creds) { double('creds') }
|
|
50
|
+
|
|
51
|
+
it 'does nothing if creds are nil' do
|
|
52
|
+
GRPC::Core::CallCredentialsHelper.apply(nil, metadata, 'host', 'channel_creds')
|
|
53
|
+
expect(metadata).to eq({})
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
it 'does nothing if channel is insecure' do
|
|
57
|
+
GRPC::Core::CallCredentialsHelper.apply(creds, metadata, 'host', :this_channel_is_insecure)
|
|
58
|
+
expect(metadata).to eq({})
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
it 'applies metadata if valid' do
|
|
62
|
+
expect(creds).to receive(:get_metadata).and_return({ 'foo' => 'bar' })
|
|
63
|
+
GRPC::Core::CallCredentialsHelper.apply(creds, metadata, 'host', 'secure_channel_creds')
|
|
64
|
+
expect(metadata).to eq({ 'foo' => 'bar' })
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
it 'handles exceptions' do
|
|
68
|
+
expect(creds).to receive(:get_metadata).and_raise('error')
|
|
69
|
+
expect do
|
|
70
|
+
GRPC::Core::CallCredentialsHelper.apply(creds, metadata, 'host', 'secure_channel_creds')
|
|
71
|
+
end.to raise_error(GRPC::BadStatus)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
it 'converts keys and values to strings' do
|
|
75
|
+
expect(creds).to receive(:get_metadata).and_return({ foo: :bar })
|
|
76
|
+
GRPC::Core::CallCredentialsHelper.apply(creds, metadata, 'host', 'secure_channel_creds')
|
|
77
|
+
expect(metadata).to eq({ 'foo' => 'bar' })
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
@@ -157,6 +157,29 @@ describe 'ClientStub' do # rubocop:disable Metrics/BlockLength
|
|
|
157
157
|
end
|
|
158
158
|
expect(&blk).to_not raise_error
|
|
159
159
|
end
|
|
160
|
+
|
|
161
|
+
it 'creates secure channel when only CallCredentials provided' do
|
|
162
|
+
call_creds = GRPC::Core::CallCredentials.new(proc { {} })
|
|
163
|
+
stub = GRPC::ClientStub.new(fake_host, call_creds)
|
|
164
|
+
# Verify the internal channel credentials are SSL (not insecure)
|
|
165
|
+
expect(stub.instance_variable_get(:@channel_creds)).to be_a(GRPC::Core::ChannelCredentials)
|
|
166
|
+
expect(stub.instance_variable_get(:@call_creds)).to eq(call_creds)
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
context 'with CompositeChannelCredentials (pure Ruby path)' do
|
|
170
|
+
it 'splits CompositeChannelCredentials into channel + call creds' do
|
|
171
|
+
skip 'CompositeChannelCredentials requires pure Ruby toggle ON' \
|
|
172
|
+
unless GRPC::PURE_RUBY_CALL_CREDENTIALS_ENABLED
|
|
173
|
+
require 'grpc/core/call_credentials'
|
|
174
|
+
require 'grpc/core/channel_credentials'
|
|
175
|
+
chan_creds = GRPC::Core::ChannelCredentials.new
|
|
176
|
+
call_creds = GRPC::Core::CallCredentials.new(proc { {} })
|
|
177
|
+
composite = chan_creds.compose(call_creds)
|
|
178
|
+
stub = GRPC::ClientStub.new(fake_host, composite)
|
|
179
|
+
expect(stub.instance_variable_get(:@channel_creds)).to eq(chan_creds)
|
|
180
|
+
expect(stub.instance_variable_get(:@call_creds)).to eq(call_creds)
|
|
181
|
+
end
|
|
182
|
+
end
|
|
160
183
|
end
|
|
161
184
|
|
|
162
185
|
describe '#request_response', request_response: true do
|
|
@@ -301,7 +324,7 @@ describe 'ClientStub' do # rubocop:disable Metrics/BlockLength
|
|
|
301
324
|
describe 'via a call operation' do
|
|
302
325
|
after(:each) do
|
|
303
326
|
# make sure op.wait doesn't freeze, even if there's a bad status
|
|
304
|
-
@op
|
|
327
|
+
@op&.wait
|
|
305
328
|
end
|
|
306
329
|
def get_response(stub, run_start_call_first: false, credentials: nil)
|
|
307
330
|
@op = stub.request_response(@method, @sent_msg, noop, noop,
|
|
@@ -403,7 +426,7 @@ describe 'ClientStub' do # rubocop:disable Metrics/BlockLength
|
|
|
403
426
|
describe 'via a call operation' do
|
|
404
427
|
after(:each) do
|
|
405
428
|
# make sure op.wait doesn't freeze, even if there's a bad status
|
|
406
|
-
@op
|
|
429
|
+
@op&.wait
|
|
407
430
|
end
|
|
408
431
|
def get_response(stub, run_start_call_first: false)
|
|
409
432
|
@op = stub.client_streamer(@method, @sent_msgs, noop, noop,
|
|
@@ -522,7 +545,7 @@ describe 'ClientStub' do # rubocop:disable Metrics/BlockLength
|
|
|
522
545
|
|
|
523
546
|
describe 'via a call operation' do
|
|
524
547
|
after(:each) do
|
|
525
|
-
@op
|
|
548
|
+
@op&.wait
|
|
526
549
|
end
|
|
527
550
|
def get_responses(stub, run_start_call_first: false, unmarshal: noop)
|
|
528
551
|
@op = stub.server_streamer(@method, @sent_msg, noop, unmarshal,
|
|
@@ -841,7 +864,7 @@ describe 'ClientStub' do # rubocop:disable Metrics/BlockLength
|
|
|
841
864
|
|
|
842
865
|
describe 'via a call operation' do
|
|
843
866
|
after(:each) do
|
|
844
|
-
@op
|
|
867
|
+
@op&.wait
|
|
845
868
|
end
|
|
846
869
|
def get_responses(stub, run_start_call_first: false, deadline: nil,
|
|
847
870
|
marshal_proc: noop)
|
|
@@ -84,7 +84,7 @@ describe 'Server Interceptors' do
|
|
|
84
84
|
run_services_on_server(@server, services: [service]) do
|
|
85
85
|
stub = build_insecure_stub(EchoStub)
|
|
86
86
|
expect_any_instance_of(GRPC::ActiveCall).to(
|
|
87
|
-
receive(:client_streamer).with(requests)
|
|
87
|
+
receive(:client_streamer).with(requests, metadata: client_metadata)
|
|
88
88
|
.once.and_call_original
|
|
89
89
|
)
|
|
90
90
|
op = stub.a_client_streaming_rpc(requests, client_call_opts)
|
|
@@ -122,7 +122,7 @@ describe 'Server Interceptors' do
|
|
|
122
122
|
run_services_on_server(@server, services: [service]) do
|
|
123
123
|
stub = build_insecure_stub(EchoStub)
|
|
124
124
|
expect_any_instance_of(GRPC::ActiveCall).to(
|
|
125
|
-
receive(:server_streamer).with(request)
|
|
125
|
+
receive(:server_streamer).with(request, metadata: client_metadata)
|
|
126
126
|
.once.and_call_original
|
|
127
127
|
)
|
|
128
128
|
op = stub.a_server_streaming_rpc(request, client_call_opts)
|
|
@@ -162,7 +162,7 @@ describe 'Server Interceptors' do
|
|
|
162
162
|
run_services_on_server(@server, services: [service]) do
|
|
163
163
|
stub = build_insecure_stub(EchoStub)
|
|
164
164
|
expect_any_instance_of(GRPC::ActiveCall).to(
|
|
165
|
-
receive(:bidi_streamer).with(requests)
|
|
165
|
+
receive(:bidi_streamer).with(requests, metadata: client_metadata)
|
|
166
166
|
.once.and_call_original
|
|
167
167
|
)
|
|
168
168
|
op = stub.a_bidi_rpc(requests, client_call_opts)
|
|
@@ -203,6 +203,20 @@ describe 'Server Interceptors' do
|
|
|
203
203
|
expect(stub.an_rpc(request)).to be_a(EchoMsg)
|
|
204
204
|
end
|
|
205
205
|
end
|
|
206
|
+
|
|
207
|
+
it 'should be invoked in FIFO order', server: true do
|
|
208
|
+
expect(interceptor).to receive(:request_response).ordered
|
|
209
|
+
.once.and_call_original
|
|
210
|
+
expect(interceptor2).to receive(:request_response).ordered
|
|
211
|
+
.once.and_call_original
|
|
212
|
+
expect(interceptor3).to receive(:request_response).ordered
|
|
213
|
+
.once.and_call_original
|
|
214
|
+
|
|
215
|
+
run_services_on_server(@server, services: [service]) do
|
|
216
|
+
stub = build_insecure_stub(EchoStub)
|
|
217
|
+
expect(stub.an_rpc(request)).to be_a(EchoMsg)
|
|
218
|
+
end
|
|
219
|
+
end
|
|
206
220
|
end
|
|
207
221
|
|
|
208
222
|
context 'when an interceptor is not added' do
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: grpc
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.82.0.pre1
|
|
5
5
|
platform: x86_64-linux-gnu
|
|
6
6
|
authors:
|
|
7
7
|
- gRPC Authors
|
|
@@ -271,6 +271,9 @@ files:
|
|
|
271
271
|
- src/ruby/lib/grpc/3.3/grpc_c.so
|
|
272
272
|
- src/ruby/lib/grpc/3.4/grpc_c.so
|
|
273
273
|
- src/ruby/lib/grpc/4.0/grpc_c.so
|
|
274
|
+
- src/ruby/lib/grpc/core/call_credentials.rb
|
|
275
|
+
- src/ruby/lib/grpc/core/channel_credentials.rb
|
|
276
|
+
- src/ruby/lib/grpc/core/credentials_helper.rb
|
|
274
277
|
- src/ruby/lib/grpc/core/status_codes.rb
|
|
275
278
|
- src/ruby/lib/grpc/core/time_consts.rb
|
|
276
279
|
- src/ruby/lib/grpc/errors.rb
|
|
@@ -312,6 +315,7 @@ files:
|
|
|
312
315
|
- src/ruby/spec/client_server_spec.rb
|
|
313
316
|
- src/ruby/spec/compression_options_spec.rb
|
|
314
317
|
- src/ruby/spec/core_spec.rb
|
|
318
|
+
- src/ruby/spec/credentials_helper_spec.rb
|
|
315
319
|
- src/ruby/spec/debug_message_spec.rb
|
|
316
320
|
- src/ruby/spec/error_sanity_spec.rb
|
|
317
321
|
- src/ruby/spec/errors_spec.rb
|
|
@@ -371,7 +375,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
371
375
|
- !ruby/object:Gem::Version
|
|
372
376
|
version: 3.3.22
|
|
373
377
|
requirements: []
|
|
374
|
-
rubygems_version: 4.0.
|
|
378
|
+
rubygems_version: 4.0.14
|
|
375
379
|
specification_version: 4
|
|
376
380
|
summary: GRPC system in Ruby
|
|
377
381
|
test_files:
|
|
@@ -387,6 +391,7 @@ test_files:
|
|
|
387
391
|
- src/ruby/spec/client_server_spec.rb
|
|
388
392
|
- src/ruby/spec/compression_options_spec.rb
|
|
389
393
|
- src/ruby/spec/core_spec.rb
|
|
394
|
+
- src/ruby/spec/credentials_helper_spec.rb
|
|
390
395
|
- src/ruby/spec/debug_message_spec.rb
|
|
391
396
|
- src/ruby/spec/error_sanity_spec.rb
|
|
392
397
|
- src/ruby/spec/errors_spec.rb
|