thrift 0.23.0 → 0.25.0
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/README.md +203 -40
- data/ext/binary_protocol_accelerated.c +130 -40
- data/ext/bytes.c +14 -0
- data/ext/compact_protocol.c +184 -91
- data/ext/constants.h +3 -0
- data/ext/extconf.rb +12 -4
- data/ext/macros.h +11 -0
- data/ext/memory_buffer.c +67 -12
- data/ext/struct.c +192 -71
- data/ext/thrift_native.c +7 -0
- data/lib/thrift/bytes.rb +6 -3
- data/lib/thrift/client.rb +31 -33
- data/lib/thrift/exceptions.rb +11 -8
- data/lib/thrift/multiplexed_processor.rb +17 -8
- data/lib/thrift/processor.rb +25 -3
- data/lib/thrift/protocol/base_protocol.rb +66 -31
- data/lib/thrift/protocol/binary_protocol.rb +80 -37
- data/lib/thrift/protocol/binary_protocol_accelerated.rb +7 -2
- data/lib/thrift/protocol/compact_protocol.rb +204 -88
- data/lib/thrift/protocol/header_protocol.rb +15 -3
- data/lib/thrift/protocol/json_protocol.rb +158 -109
- data/lib/thrift/protocol/multiplexed_protocol.rb +3 -3
- data/lib/thrift/protocol/protocol_decorator.rb +6 -2
- data/lib/thrift/serializer/deserializer.rb +1 -0
- data/lib/thrift/serializer/serializer.rb +7 -0
- data/lib/thrift/server/base_server.rb +11 -2
- data/lib/thrift/server/nonblocking_server.rb +69 -20
- data/lib/thrift/server/rack_application.rb +69 -0
- data/lib/thrift/server/simple_server.rb +27 -15
- data/lib/thrift/server/thin_http_server.rb +21 -44
- data/lib/thrift/server/thread_pool_server.rb +21 -17
- data/lib/thrift/server/threaded_server.rb +22 -18
- data/lib/thrift/struct.rb +34 -18
- data/lib/thrift/struct_union.rb +37 -36
- data/lib/thrift/thrift_native.rb +2 -1
- data/lib/thrift/transport/base_server_transport.rb +3 -0
- data/lib/thrift/transport/base_transport.rb +26 -4
- data/lib/thrift/transport/buffered_transport.rb +5 -4
- data/lib/thrift/transport/framed_transport.rb +33 -7
- data/lib/thrift/transport/header_transport.rb +159 -33
- data/lib/thrift/transport/http_client_transport.rb +28 -14
- data/lib/thrift/transport/io_stream_transport.rb +3 -1
- data/lib/thrift/transport/memory_buffer_transport.rb +14 -9
- data/lib/thrift/transport/server_socket.rb +10 -8
- data/lib/thrift/transport/socket.rb +85 -48
- data/lib/thrift/transport/ssl_server_socket.rb +67 -6
- data/lib/thrift/transport/ssl_socket.rb +73 -14
- data/lib/thrift/transport/unix_server_socket.rb +6 -2
- data/lib/thrift/transport/unix_socket.rb +5 -6
- data/lib/thrift/types.rb +23 -22
- data/lib/thrift/union.rb +21 -11
- data/lib/thrift/uuid.rb +9 -8
- data/lib/thrift.rb +40 -39
- metadata +7 -266
- data/benchmark/Benchmark.thrift +0 -24
- data/benchmark/benchmark.rb +0 -285
- data/benchmark/client.rb +0 -117
- data/benchmark/server.rb +0 -120
- data/benchmark/thin_server.rb +0 -45
- data/lib/thrift/server/mongrel_http_server.rb +0 -60
- data/spec/BaseService.thrift +0 -27
- data/spec/ExtendedService.thrift +0 -25
- data/spec/Referenced.thrift +0 -44
- data/spec/ThriftNamespacedSpec.thrift +0 -53
- data/spec/ThriftSpec.thrift +0 -187
- data/spec/base_protocol_spec.rb +0 -224
- data/spec/base_transport_spec.rb +0 -387
- data/spec/binary_protocol_accelerated_spec.rb +0 -46
- data/spec/binary_protocol_spec.rb +0 -72
- data/spec/binary_protocol_spec_shared.rb +0 -445
- data/spec/bytes_spec.rb +0 -99
- data/spec/client_spec.rb +0 -166
- data/spec/compact_protocol_spec.rb +0 -196
- data/spec/constants_demo_spec.rb +0 -101
- data/spec/exception_spec.rb +0 -140
- data/spec/flat_spec.rb +0 -62
- data/spec/header_protocol_spec.rb +0 -475
- data/spec/header_transport_spec.rb +0 -386
- data/spec/http_client_spec.rb +0 -159
- data/spec/json_protocol_spec.rb +0 -552
- data/spec/namespaced_spec.rb +0 -66
- data/spec/nonblocking_server_spec.rb +0 -361
- data/spec/processor_spec.rb +0 -79
- data/spec/serializer_spec.rb +0 -66
- data/spec/server_socket_spec.rb +0 -84
- data/spec/server_spec.rb +0 -186
- data/spec/socket_spec.rb +0 -67
- data/spec/socket_spec_shared.rb +0 -167
- data/spec/spec_helper.rb +0 -69
- data/spec/ssl_server_socket_spec.rb +0 -45
- data/spec/ssl_socket_spec.rb +0 -87
- data/spec/struct_nested_containers_spec.rb +0 -190
- data/spec/struct_spec.rb +0 -397
- data/spec/support/header_protocol_helper.rb +0 -54
- data/spec/thin_http_server_spec.rb +0 -126
- data/spec/types_spec.rb +0 -117
- data/spec/union_spec.rb +0 -272
- data/spec/unix_socket_spec.rb +0 -115
- data/spec/uuid_validation_spec.rb +0 -238
- data/test/fuzz/Makefile.am +0 -173
- data/test/fuzz/README.md +0 -149
- data/test/fuzz/fuzz_common.rb +0 -95
- data/test/fuzz/fuzz_parse_binary_protocol.rb +0 -22
- data/test/fuzz/fuzz_parse_binary_protocol_accelerated.rb +0 -22
- data/test/fuzz/fuzz_parse_binary_protocol_accelerated_harness.rb +0 -22
- data/test/fuzz/fuzz_parse_binary_protocol_harness.rb +0 -22
- data/test/fuzz/fuzz_parse_compact_protocol.rb +0 -22
- data/test/fuzz/fuzz_parse_compact_protocol_harness.rb +0 -22
- data/test/fuzz/fuzz_parse_json_protocol.rb +0 -22
- data/test/fuzz/fuzz_parse_json_protocol_harness.rb +0 -22
- data/test/fuzz/fuzz_roundtrip_binary_protocol.rb +0 -22
- data/test/fuzz/fuzz_roundtrip_binary_protocol_accelerated.rb +0 -22
- data/test/fuzz/fuzz_roundtrip_binary_protocol_accelerated_harness.rb +0 -22
- data/test/fuzz/fuzz_roundtrip_binary_protocol_harness.rb +0 -22
- data/test/fuzz/fuzz_roundtrip_compact_protocol.rb +0 -22
- data/test/fuzz/fuzz_roundtrip_compact_protocol_harness.rb +0 -22
- data/test/fuzz/fuzz_roundtrip_json_protocol.rb +0 -22
- data/test/fuzz/fuzz_roundtrip_json_protocol_harness.rb +0 -22
- data/test/fuzz/fuzz_tracer.rb +0 -28
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
# encoding: ascii-8bit
|
|
2
|
+
# frozen_string_literal: true
|
|
2
3
|
#
|
|
3
4
|
# Licensed to the Apache Software Foundation (ASF) under one
|
|
4
5
|
# or more contributor license agreements. See the NOTICE file
|
|
@@ -18,11 +19,11 @@
|
|
|
18
19
|
# under the License.
|
|
19
20
|
#
|
|
20
21
|
|
|
21
|
-
require
|
|
22
|
+
require "socket"
|
|
22
23
|
|
|
23
24
|
module Thrift
|
|
24
25
|
class Socket < BaseTransport
|
|
25
|
-
def initialize(host =
|
|
26
|
+
def initialize(host = "localhost", port = 9090, timeout = nil)
|
|
26
27
|
@host = host
|
|
27
28
|
@port = port
|
|
28
29
|
@timeout = timeout
|
|
@@ -33,39 +34,21 @@ module Thrift
|
|
|
33
34
|
attr_accessor :handle, :timeout
|
|
34
35
|
|
|
35
36
|
def open
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
sockaddr = ::Socket.sockaddr_in(addrinfo[1], addrinfo[3])
|
|
41
|
-
begin
|
|
42
|
-
socket.connect_nonblock(sockaddr)
|
|
43
|
-
rescue Errno::EINPROGRESS
|
|
44
|
-
unless IO.select(nil, [ socket ], nil, @timeout)
|
|
45
|
-
next
|
|
46
|
-
end
|
|
47
|
-
begin
|
|
48
|
-
socket.connect_nonblock(sockaddr)
|
|
49
|
-
rescue Errno::EISCONN
|
|
50
|
-
end
|
|
51
|
-
end
|
|
52
|
-
return @handle = socket
|
|
53
|
-
rescue StandardError => e
|
|
54
|
-
next
|
|
55
|
-
end
|
|
56
|
-
end
|
|
57
|
-
raise TransportException.new(TransportException::NOT_OPEN, "Could not connect to #{@desc}: #{e}")
|
|
37
|
+
raise TransportException.new(TransportException::ALREADY_OPEN, "Socket already open") if open?
|
|
38
|
+
|
|
39
|
+
deadline = Process.clock_gettime(Process::CLOCK_MONOTONIC) + @timeout unless @timeout.nil? || @timeout == 0
|
|
40
|
+
@handle = connect_socket(deadline)
|
|
58
41
|
end
|
|
59
42
|
|
|
60
43
|
def open?
|
|
61
|
-
!@handle.nil?
|
|
44
|
+
!@handle.nil? && !@handle.closed?
|
|
62
45
|
end
|
|
63
46
|
|
|
64
47
|
def write(str)
|
|
65
48
|
raise TransportException.new(TransportException::NOT_OPEN, "closed stream") unless open?
|
|
66
49
|
str = Bytes.force_binary_encoding(str)
|
|
67
50
|
begin
|
|
68
|
-
if @timeout.nil?
|
|
51
|
+
if @timeout.nil? || @timeout == 0
|
|
69
52
|
@handle.write(str)
|
|
70
53
|
else
|
|
71
54
|
deadline = Process.clock_gettime(Process::CLOCK_MONOTONIC) + @timeout
|
|
@@ -73,7 +56,7 @@ module Thrift
|
|
|
73
56
|
|
|
74
57
|
while len < str.length
|
|
75
58
|
begin
|
|
76
|
-
len += @handle.write_nonblock(str[len
|
|
59
|
+
len += @handle.write_nonblock(str[len..])
|
|
77
60
|
rescue IO::WaitWritable
|
|
78
61
|
wait_for(:write, deadline, str.length)
|
|
79
62
|
rescue IO::WaitReadable
|
|
@@ -83,12 +66,11 @@ module Thrift
|
|
|
83
66
|
|
|
84
67
|
len
|
|
85
68
|
end
|
|
86
|
-
rescue TransportException
|
|
87
|
-
|
|
88
|
-
raise
|
|
69
|
+
rescue TransportException
|
|
70
|
+
close
|
|
71
|
+
raise
|
|
89
72
|
rescue StandardError => e
|
|
90
|
-
|
|
91
|
-
@handle = nil
|
|
73
|
+
close
|
|
92
74
|
raise TransportException.new(TransportException::NOT_OPEN, e.message)
|
|
93
75
|
end
|
|
94
76
|
end
|
|
@@ -97,42 +79,39 @@ module Thrift
|
|
|
97
79
|
raise TransportException.new(TransportException::NOT_OPEN, "closed stream") unless open?
|
|
98
80
|
|
|
99
81
|
begin
|
|
100
|
-
if @timeout.nil?
|
|
82
|
+
if @timeout.nil? || @timeout == 0
|
|
101
83
|
data = @handle.readpartial(sz)
|
|
102
84
|
else
|
|
103
85
|
deadline = Process.clock_gettime(Process::CLOCK_MONOTONIC) + @timeout
|
|
104
86
|
|
|
105
87
|
data = loop do
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
wait_for(:write, deadline, sz)
|
|
112
|
-
end
|
|
88
|
+
break @handle.read_nonblock(sz)
|
|
89
|
+
rescue IO::WaitReadable
|
|
90
|
+
wait_for(:read, deadline, sz)
|
|
91
|
+
rescue IO::WaitWritable
|
|
92
|
+
wait_for(:write, deadline, sz)
|
|
113
93
|
end
|
|
114
94
|
end
|
|
115
|
-
rescue TransportException
|
|
116
|
-
|
|
117
|
-
raise
|
|
95
|
+
rescue TransportException
|
|
96
|
+
close
|
|
97
|
+
raise
|
|
118
98
|
rescue StandardError => e
|
|
119
|
-
|
|
120
|
-
@handle = nil
|
|
99
|
+
close
|
|
121
100
|
raise TransportException.new(TransportException::NOT_OPEN, e.message)
|
|
122
101
|
end
|
|
123
|
-
if
|
|
102
|
+
if data.nil? || data.length == 0
|
|
124
103
|
raise TransportException.new(TransportException::UNKNOWN, "Socket: Could not read #{sz} bytes from #{@desc}")
|
|
125
104
|
end
|
|
126
105
|
data
|
|
127
106
|
end
|
|
128
107
|
|
|
129
108
|
def close
|
|
130
|
-
@handle
|
|
109
|
+
close_socket(@handle)
|
|
131
110
|
@handle = nil
|
|
132
111
|
end
|
|
133
112
|
|
|
134
113
|
def to_io
|
|
135
|
-
@handle&.to_io || raise(IOError,
|
|
114
|
+
@handle&.to_io || raise(IOError, "closed stream")
|
|
136
115
|
end
|
|
137
116
|
|
|
138
117
|
def to_s
|
|
@@ -141,6 +120,64 @@ module Thrift
|
|
|
141
120
|
|
|
142
121
|
private
|
|
143
122
|
|
|
123
|
+
def connect_socket(deadline)
|
|
124
|
+
last_error = nil
|
|
125
|
+
connected_socket = nil
|
|
126
|
+
|
|
127
|
+
Addrinfo.foreach(@host, @port, nil, :STREAM) do |addrinfo|
|
|
128
|
+
socket = nil
|
|
129
|
+
|
|
130
|
+
begin
|
|
131
|
+
socket = if deadline
|
|
132
|
+
remaining = deadline - Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
133
|
+
raise TransportException.new(TransportException::TIMED_OUT, "Socket: Timed out opening connection to #{@desc}") if remaining <= 0
|
|
134
|
+
|
|
135
|
+
addrinfo.connect(timeout: remaining)
|
|
136
|
+
else
|
|
137
|
+
addrinfo.connect
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
socket.setsockopt(::Socket::IPPROTO_TCP, ::Socket::TCP_NODELAY, 1)
|
|
141
|
+
connected_socket = socket
|
|
142
|
+
break
|
|
143
|
+
rescue Errno::ETIMEDOUT => e
|
|
144
|
+
close_socket(socket)
|
|
145
|
+
last_error = e
|
|
146
|
+
rescue TransportException
|
|
147
|
+
close_socket(socket)
|
|
148
|
+
raise
|
|
149
|
+
rescue StandardError => e
|
|
150
|
+
close_socket(socket)
|
|
151
|
+
last_error = e
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
return connected_socket if connected_socket
|
|
156
|
+
|
|
157
|
+
if last_error.is_a?(Errno::ETIMEDOUT)
|
|
158
|
+
raise TransportException.new(TransportException::TIMED_OUT, "Socket: Timed out opening connection to #{@desc}")
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
if deadline && deadline - Process.clock_gettime(Process::CLOCK_MONOTONIC) <= 0
|
|
162
|
+
raise TransportException.new(TransportException::TIMED_OUT, "Socket: Timed out opening connection to #{@desc}")
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
raise TransportException.new(TransportException::NOT_OPEN, "Could not connect to #{@desc}"), cause: last_error
|
|
166
|
+
rescue TransportException
|
|
167
|
+
raise
|
|
168
|
+
rescue StandardError
|
|
169
|
+
raise TransportException.new(TransportException::NOT_OPEN, "Could not connect to #{@desc}")
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
def close_socket(socket)
|
|
173
|
+
return if socket.nil?
|
|
174
|
+
return if socket.respond_to?(:closed?) && socket.closed?
|
|
175
|
+
|
|
176
|
+
socket.close
|
|
177
|
+
rescue StandardError
|
|
178
|
+
nil
|
|
179
|
+
end
|
|
180
|
+
|
|
144
181
|
def wait_for(operation, deadline, sz)
|
|
145
182
|
rd_ary, wr_ary = case operation
|
|
146
183
|
when :read
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
# encoding: ascii-8bit
|
|
2
|
+
# frozen_string_literal: true
|
|
2
3
|
#
|
|
3
4
|
# Licensed to the Apache Software Foundation (ASF) under one
|
|
4
5
|
# or more contributor license agreements. See the NOTICE file
|
|
@@ -18,24 +19,84 @@
|
|
|
18
19
|
# under the License.
|
|
19
20
|
#
|
|
20
21
|
|
|
21
|
-
require
|
|
22
|
+
require "io/wait"
|
|
23
|
+
require "socket"
|
|
22
24
|
|
|
23
25
|
module Thrift
|
|
24
26
|
class SSLServerSocket < ServerSocket
|
|
25
|
-
def initialize(host_or_port, port = nil, ssl_context = nil)
|
|
26
|
-
super(host_or_port, port)
|
|
27
|
+
def initialize(host_or_port, port = nil, ssl_context = nil, client_timeout: DEFAULT_CLIENT_TIMEOUT)
|
|
28
|
+
super(host_or_port, port, client_timeout: client_timeout)
|
|
27
29
|
@ssl_context = ssl_context
|
|
28
30
|
end
|
|
29
31
|
|
|
30
32
|
attr_accessor :ssl_context
|
|
31
33
|
|
|
32
34
|
def listen
|
|
33
|
-
|
|
34
|
-
@handle = OpenSSL::SSL::SSLServer.new(
|
|
35
|
+
tcp_server = TCPServer.new(@host, @port)
|
|
36
|
+
@handle = OpenSSL::SSL::SSLServer.new(tcp_server, @ssl_context).tap do |server|
|
|
37
|
+
server.start_immediately = false
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def accept
|
|
42
|
+
return if @handle.nil?
|
|
43
|
+
|
|
44
|
+
transport = nil
|
|
45
|
+
ssl_socket = @handle.accept
|
|
46
|
+
deadline = Process.clock_gettime(Process::CLOCK_MONOTONIC) + @client_timeout unless @client_timeout.nil? || @client_timeout == 0
|
|
47
|
+
ssl_socket.to_io.setsockopt(::Socket::IPPROTO_TCP, ::Socket::TCP_NODELAY, 1)
|
|
48
|
+
accept_ssl_socket(ssl_socket, deadline)
|
|
49
|
+
|
|
50
|
+
transport = Socket.new.tap do |accepted_transport|
|
|
51
|
+
accepted_transport.timeout = @client_timeout
|
|
52
|
+
accepted_transport.handle = ssl_socket
|
|
53
|
+
end
|
|
54
|
+
ensure
|
|
55
|
+
# Thread#kill leaves $! nil, but marks the thread as aborting.
|
|
56
|
+
close_accepted_socket(ssl_socket) if transport.nil? || $! || Thread.current.status == "aborting"
|
|
35
57
|
end
|
|
36
58
|
|
|
37
59
|
def to_s
|
|
38
|
-
"ssl(#{super
|
|
60
|
+
"ssl(#{super})"
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
private
|
|
64
|
+
|
|
65
|
+
def accept_ssl_socket(ssl_socket, deadline)
|
|
66
|
+
return ssl_socket.accept unless deadline
|
|
67
|
+
|
|
68
|
+
loop do
|
|
69
|
+
case ssl_socket.accept_nonblock(exception: false)
|
|
70
|
+
when ssl_socket
|
|
71
|
+
return ssl_socket
|
|
72
|
+
when :wait_readable
|
|
73
|
+
wait_for_handshake(ssl_socket, :read, deadline)
|
|
74
|
+
when :wait_writable
|
|
75
|
+
wait_for_handshake(ssl_socket, :write, deadline)
|
|
76
|
+
else
|
|
77
|
+
raise TransportException.new(TransportException::NOT_OPEN, "SSL server socket: Unexpected TLS handshake result")
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def wait_for_handshake(ssl_socket, direction, deadline)
|
|
83
|
+
remaining = deadline - Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
84
|
+
ready = if remaining > 0
|
|
85
|
+
if direction == :read
|
|
86
|
+
ssl_socket.to_io.wait_readable(remaining)
|
|
87
|
+
else
|
|
88
|
+
ssl_socket.to_io.wait_writable(remaining)
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
return if ready
|
|
92
|
+
|
|
93
|
+
raise OpenSSL::SSL::SSLError, "SSL server socket: Timed out accepting TLS connection"
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def close_accepted_socket(ssl_socket)
|
|
97
|
+
ssl_socket&.close
|
|
98
|
+
rescue StandardError
|
|
99
|
+
nil
|
|
39
100
|
end
|
|
40
101
|
end
|
|
41
102
|
end
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
# encoding: ascii-8bit
|
|
2
|
+
# frozen_string_literal: true
|
|
2
3
|
#
|
|
3
4
|
# Licensed to the Apache Software Foundation (ASF) under one
|
|
4
5
|
# or more contributor license agreements. See the NOTICE file
|
|
@@ -17,35 +18,93 @@
|
|
|
17
18
|
# specific language governing permissions and limitations
|
|
18
19
|
# under the License.
|
|
19
20
|
|
|
21
|
+
require "io/wait"
|
|
22
|
+
require "ipaddr"
|
|
23
|
+
|
|
20
24
|
module Thrift
|
|
21
25
|
class SSLSocket < Socket
|
|
22
|
-
def initialize(host =
|
|
26
|
+
def initialize(host = "localhost", port = 9090, timeout = nil, ssl_context = nil, server_hostname: host)
|
|
23
27
|
super(host, port, timeout)
|
|
24
28
|
@ssl_context = ssl_context
|
|
29
|
+
@server_hostname = server_hostname
|
|
25
30
|
end
|
|
26
31
|
|
|
27
32
|
attr_accessor :ssl_context
|
|
33
|
+
attr_accessor :server_hostname
|
|
28
34
|
|
|
29
35
|
def open
|
|
30
|
-
|
|
31
|
-
|
|
36
|
+
deadline = Process.clock_gettime(Process::CLOCK_MONOTONIC) + @timeout unless @timeout.nil? || @timeout == 0
|
|
37
|
+
socket = connect_socket(deadline)
|
|
38
|
+
|
|
32
39
|
begin
|
|
33
|
-
|
|
34
|
-
|
|
40
|
+
ssl_context = configured_ssl_context
|
|
41
|
+
ssl_socket = OpenSSL::SSL::SSLSocket.new(socket, ssl_context)
|
|
42
|
+
ssl_socket.hostname = @server_hostname if send_server_hostname?
|
|
43
|
+
ssl_socket.sync_close = true
|
|
44
|
+
@handle = ssl_socket
|
|
45
|
+
|
|
46
|
+
if deadline
|
|
47
|
+
loop do
|
|
48
|
+
result = @handle.connect_nonblock(exception: false)
|
|
49
|
+
|
|
50
|
+
case result
|
|
51
|
+
when @handle
|
|
52
|
+
break
|
|
53
|
+
when :wait_readable
|
|
54
|
+
remaining = deadline - Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
55
|
+
if remaining <= 0 || !@handle.to_io.wait_readable(remaining)
|
|
56
|
+
raise TransportException.new(TransportException::TIMED_OUT, "SSL socket: Timed out establishing session with #{@desc}")
|
|
57
|
+
end
|
|
58
|
+
when :wait_writable
|
|
59
|
+
remaining = deadline - Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
60
|
+
if remaining <= 0 || !@handle.to_io.wait_writable(remaining)
|
|
61
|
+
raise TransportException.new(TransportException::TIMED_OUT, "SSL socket: Timed out establishing session with #{@desc}")
|
|
62
|
+
end
|
|
63
|
+
else
|
|
64
|
+
raise TransportException.new(TransportException::NOT_OPEN, "Could not connect to #{@desc}: unexpected SSL connect result #{result.inspect}")
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
else
|
|
68
|
+
@handle.connect
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
@handle.post_connection_check(server_hostname_for_verification)
|
|
35
72
|
@handle
|
|
36
|
-
rescue
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
raise TransportException.new(TransportException::NOT_OPEN, "Could not connect to #{@desc}
|
|
73
|
+
rescue TransportException
|
|
74
|
+
close_socket(@handle)
|
|
75
|
+
@handle = nil
|
|
76
|
+
raise
|
|
77
|
+
rescue StandardError
|
|
78
|
+
close_socket(@handle || socket)
|
|
79
|
+
@handle = nil
|
|
80
|
+
raise TransportException.new(TransportException::NOT_OPEN, "Could not connect to #{@desc}")
|
|
44
81
|
end
|
|
45
82
|
end
|
|
46
83
|
|
|
47
84
|
def to_s
|
|
48
|
-
"ssl(#{super
|
|
85
|
+
"ssl(#{super})"
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
private
|
|
89
|
+
|
|
90
|
+
def configured_ssl_context
|
|
91
|
+
@ssl_context ||= OpenSSL::SSL::SSLContext.new.tap do |context|
|
|
92
|
+
context.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
|
93
|
+
context.cert_store = OpenSSL::X509::Store.new.tap(&:set_default_paths)
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def send_server_hostname?
|
|
98
|
+
return false if @server_hostname.nil? || @server_hostname.empty?
|
|
99
|
+
|
|
100
|
+
IPAddr.new(@server_hostname)
|
|
101
|
+
false
|
|
102
|
+
rescue IPAddr::InvalidAddressError
|
|
103
|
+
true
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def server_hostname_for_verification
|
|
107
|
+
@server_hostname.nil? || @server_hostname.empty? ? @host : @server_hostname
|
|
49
108
|
end
|
|
50
109
|
end
|
|
51
110
|
end
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
# encoding: ascii-8bit
|
|
2
|
+
# frozen_string_literal: true
|
|
2
3
|
#
|
|
3
4
|
# Licensed to the Apache Software Foundation (ASF) under one
|
|
4
5
|
# or more contributor license agreements. See the NOTICE file
|
|
@@ -18,16 +19,18 @@
|
|
|
18
19
|
# under the License.
|
|
19
20
|
#
|
|
20
21
|
|
|
21
|
-
require
|
|
22
|
+
require "socket"
|
|
22
23
|
|
|
23
24
|
module Thrift
|
|
24
25
|
class UNIXServerSocket < BaseServerTransport
|
|
25
|
-
def initialize(path)
|
|
26
|
+
def initialize(path, client_timeout: DEFAULT_CLIENT_TIMEOUT)
|
|
26
27
|
@path = path
|
|
28
|
+
@client_timeout = client_timeout
|
|
27
29
|
@handle = nil
|
|
28
30
|
end
|
|
29
31
|
|
|
30
32
|
attr_accessor :handle
|
|
33
|
+
attr_reader :client_timeout
|
|
31
34
|
|
|
32
35
|
def listen
|
|
33
36
|
@handle = ::UNIXServer.new(@path)
|
|
@@ -37,6 +40,7 @@ module Thrift
|
|
|
37
40
|
unless @handle.nil?
|
|
38
41
|
sock = @handle.accept
|
|
39
42
|
trans = UNIXSocket.new(nil)
|
|
43
|
+
trans.timeout = @client_timeout
|
|
40
44
|
trans.handle = sock
|
|
41
45
|
trans
|
|
42
46
|
end
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
# encoding: ascii-8bit
|
|
2
|
+
# frozen_string_literal: true
|
|
2
3
|
#
|
|
3
4
|
# Licensed to the Apache Software Foundation (ASF) under one
|
|
4
5
|
# or more contributor license agreements. See the NOTICE file
|
|
@@ -18,7 +19,7 @@
|
|
|
18
19
|
# under the License.
|
|
19
20
|
#
|
|
20
21
|
|
|
21
|
-
require
|
|
22
|
+
require "socket"
|
|
22
23
|
|
|
23
24
|
module Thrift
|
|
24
25
|
class UNIXSocket < Socket
|
|
@@ -30,11 +31,9 @@ module Thrift
|
|
|
30
31
|
end
|
|
31
32
|
|
|
32
33
|
def open
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
raise TransportException.new(TransportException::NOT_OPEN, "Could not open UNIX socket at #{@path}")
|
|
37
|
-
end
|
|
34
|
+
@handle = ::UNIXSocket.new(@path)
|
|
35
|
+
rescue StandardError
|
|
36
|
+
raise TransportException.new(TransportException::NOT_OPEN, "Could not open UNIX socket at #{@path}")
|
|
38
37
|
end
|
|
39
38
|
|
|
40
39
|
def to_s
|
data/lib/thrift/types.rb
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
#
|
|
2
3
|
# Licensed to the Apache Software Foundation (ASF) under one
|
|
3
4
|
# or more contributor license agreements. See the NOTICE file
|
|
@@ -17,7 +18,7 @@
|
|
|
17
18
|
# under the License.
|
|
18
19
|
#
|
|
19
20
|
|
|
20
|
-
require
|
|
21
|
+
require "set"
|
|
21
22
|
|
|
22
23
|
module Thrift
|
|
23
24
|
module Types
|
|
@@ -47,27 +48,27 @@ module Thrift
|
|
|
47
48
|
def self.check_type(value, field, name, skip_nil = true)
|
|
48
49
|
return if value.nil? and skip_nil
|
|
49
50
|
klasses = case field[:type]
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
51
|
+
when Types::VOID
|
|
52
|
+
NilClass
|
|
53
|
+
when Types::BOOL
|
|
54
|
+
[TrueClass, FalseClass]
|
|
55
|
+
when Types::BYTE, Types::I16, Types::I32, Types::I64
|
|
56
|
+
Integer
|
|
57
|
+
when Types::DOUBLE
|
|
58
|
+
Float
|
|
59
|
+
when Types::STRING
|
|
60
|
+
String
|
|
61
|
+
when Types::UUID
|
|
62
|
+
String
|
|
63
|
+
when Types::STRUCT
|
|
64
|
+
[Struct, Union]
|
|
65
|
+
when Types::MAP
|
|
66
|
+
Hash
|
|
67
|
+
when Types::SET
|
|
68
|
+
Set
|
|
69
|
+
when Types::LIST
|
|
70
|
+
Array
|
|
71
|
+
end
|
|
71
72
|
valid = klasses && [*klasses].any? { |klass| klass === value }
|
|
72
73
|
raise TypeError, "Expected #{type_name(field[:type])}, received #{value.class} for field #{name}" unless valid
|
|
73
74
|
# check elements now
|
data/lib/thrift/union.rb
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
#
|
|
2
3
|
# Licensed to the Apache Software Foundation (ASF) under one
|
|
3
4
|
# or more contributor license agreements. See the NOTICE file
|
|
@@ -17,6 +18,8 @@
|
|
|
17
18
|
# under the License.
|
|
18
19
|
#
|
|
19
20
|
|
|
21
|
+
require "thrift/struct_union"
|
|
22
|
+
|
|
20
23
|
module Thrift
|
|
21
24
|
class Union
|
|
22
25
|
def initialize(name = nil, value = nil)
|
|
@@ -53,13 +56,17 @@ module Thrift
|
|
|
53
56
|
end
|
|
54
57
|
end
|
|
55
58
|
|
|
56
|
-
def read(iprot)
|
|
59
|
+
def read(iprot, remaining_depth = DEFAULT_RECURSION_DEPTH)
|
|
60
|
+
raise ProtocolException.new(ProtocolException::DEPTH_LIMIT, "Maximum recursion depth exceeded") if remaining_depth <= 0
|
|
61
|
+
@setfield = nil
|
|
62
|
+
@value = nil
|
|
63
|
+
|
|
57
64
|
iprot.read_struct_begin
|
|
58
|
-
|
|
59
|
-
handle_message(iprot, fid, ftype)
|
|
65
|
+
_, ftype, fid = iprot.read_field_begin
|
|
66
|
+
handle_message(iprot, fid, ftype, remaining_depth)
|
|
60
67
|
iprot.read_field_end
|
|
61
68
|
|
|
62
|
-
|
|
69
|
+
_, ftype, _ = iprot.read_field_begin
|
|
63
70
|
unless (ftype == Types::STOP)
|
|
64
71
|
raise ProtocolException.new(ProtocolException::INVALID_DATA, "Too many fields for union")
|
|
65
72
|
end
|
|
@@ -68,11 +75,12 @@ module Thrift
|
|
|
68
75
|
validate
|
|
69
76
|
end
|
|
70
77
|
|
|
71
|
-
def write(oprot)
|
|
78
|
+
def write(oprot, remaining_depth = DEFAULT_RECURSION_DEPTH)
|
|
79
|
+
raise ProtocolException.new(ProtocolException::DEPTH_LIMIT, "Maximum recursion depth exceeded") if remaining_depth <= 0
|
|
72
80
|
validate
|
|
73
81
|
oprot.write_struct_begin(self.class.name)
|
|
74
82
|
|
|
75
|
-
fid =
|
|
83
|
+
fid = name_to_id(@setfield.to_s)
|
|
76
84
|
|
|
77
85
|
field_info = struct_fields[fid]
|
|
78
86
|
unless field_info
|
|
@@ -82,8 +90,10 @@ module Thrift
|
|
|
82
90
|
type = field_info[:type]
|
|
83
91
|
if is_container? type
|
|
84
92
|
oprot.write_field_begin(@setfield, type, fid)
|
|
85
|
-
write_container(oprot, @value, field_info)
|
|
93
|
+
write_container(oprot, @value, field_info, remaining_depth)
|
|
86
94
|
oprot.write_field_end
|
|
95
|
+
elsif type == Types::STRUCT
|
|
96
|
+
oprot.write_field(field_info, fid, @value, remaining_depth)
|
|
87
97
|
else
|
|
88
98
|
oprot.write_field(@setfield, type, fid, @value)
|
|
89
99
|
end
|
|
@@ -93,7 +103,7 @@ module Thrift
|
|
|
93
103
|
end
|
|
94
104
|
|
|
95
105
|
def ==(other)
|
|
96
|
-
other.equal?(self) || other.instance_of?(self.class) && @setfield == other.get_set_field && @value == other.get_value
|
|
106
|
+
other.equal?(self) || (other.instance_of?(self.class) && @setfield == other.get_set_field && @value == other.get_value)
|
|
97
107
|
end
|
|
98
108
|
alias_method :eql?, :==
|
|
99
109
|
|
|
@@ -106,7 +116,7 @@ module Thrift
|
|
|
106
116
|
if field_info[:name].to_sym == @setfield
|
|
107
117
|
@value
|
|
108
118
|
else
|
|
109
|
-
raise
|
|
119
|
+
raise "#{field_info[:name]} is not union's set field."
|
|
110
120
|
end
|
|
111
121
|
end
|
|
112
122
|
|
|
@@ -168,10 +178,10 @@ module Thrift
|
|
|
168
178
|
|
|
169
179
|
protected
|
|
170
180
|
|
|
171
|
-
def handle_message(iprot, fid, ftype)
|
|
181
|
+
def handle_message(iprot, fid, ftype, remaining_depth)
|
|
172
182
|
field = struct_fields[fid]
|
|
173
183
|
if field and field[:type] == ftype
|
|
174
|
-
@value = read_field(iprot, field)
|
|
184
|
+
@value = read_field(iprot, field, remaining_depth)
|
|
175
185
|
name = field[:name].to_sym
|
|
176
186
|
@setfield = name
|
|
177
187
|
else
|
data/lib/thrift/uuid.rb
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
#
|
|
2
3
|
# Licensed to the Apache Software Foundation (ASF) under one
|
|
3
4
|
# or more contributor license agreements. See the NOTICE file
|
|
@@ -17,32 +18,32 @@
|
|
|
17
18
|
# under the License.
|
|
18
19
|
#
|
|
19
20
|
|
|
20
|
-
require
|
|
21
|
+
require "thrift/protocol/base_protocol"
|
|
21
22
|
|
|
22
23
|
module Thrift
|
|
23
24
|
module UUID
|
|
24
|
-
UUID_REGEX = /\A[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}\z
|
|
25
|
+
UUID_REGEX = /\A[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}\z/
|
|
25
26
|
|
|
26
27
|
def self.validate_uuid!(uuid)
|
|
27
28
|
unless uuid.is_a?(String)
|
|
28
|
-
raise ProtocolException.new(ProtocolException::INVALID_DATA,
|
|
29
|
+
raise ProtocolException.new(ProtocolException::INVALID_DATA, "UUID must be a string")
|
|
29
30
|
end
|
|
30
31
|
|
|
31
|
-
unless uuid
|
|
32
|
-
raise ProtocolException.new(ProtocolException::INVALID_DATA,
|
|
32
|
+
unless UUID_REGEX.match?(uuid)
|
|
33
|
+
raise ProtocolException.new(ProtocolException::INVALID_DATA, "Invalid UUID format")
|
|
33
34
|
end
|
|
34
35
|
end
|
|
35
36
|
|
|
36
37
|
def self.uuid_bytes(uuid)
|
|
37
|
-
[uuid.delete(
|
|
38
|
+
[uuid.delete("-")].pack("H*")
|
|
38
39
|
end
|
|
39
40
|
|
|
40
41
|
def self.uuid_from_bytes(bytes)
|
|
41
42
|
unless bytes.bytesize == 16
|
|
42
|
-
raise ProtocolException.new(ProtocolException::INVALID_DATA,
|
|
43
|
+
raise ProtocolException.new(ProtocolException::INVALID_DATA, "Invalid UUID data length")
|
|
43
44
|
end
|
|
44
45
|
|
|
45
|
-
hex = bytes.
|
|
46
|
+
hex = bytes.unpack1("H*")
|
|
46
47
|
"#{hex[0, 8]}-#{hex[8, 4]}-#{hex[12, 4]}-#{hex[16, 4]}-#{hex[20, 12]}"
|
|
47
48
|
end
|
|
48
49
|
end
|