thrift 0.22.0 → 0.24.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.
Files changed (119) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +235 -17
  3. data/benchmark/benchmark.rb +23 -8
  4. data/benchmark/client.rb +50 -6
  5. data/benchmark/server.rb +46 -7
  6. data/benchmark/thin_server.rb +2 -0
  7. data/ext/binary_protocol_accelerated.c +154 -42
  8. data/ext/bytes.c +14 -0
  9. data/ext/compact_protocol.c +138 -45
  10. data/ext/constants.h +12 -0
  11. data/ext/extconf.rb +17 -8
  12. data/ext/memory_buffer.c +44 -7
  13. data/ext/protocol.c +29 -0
  14. data/ext/protocol.h +35 -0
  15. data/ext/struct.c +48 -17
  16. data/ext/thrift_native.c +28 -3
  17. data/lib/thrift/bytes.rb +70 -100
  18. data/lib/thrift/client.rb +54 -13
  19. data/lib/thrift/exceptions.rb +6 -5
  20. data/lib/thrift/multiplexed_processor.rb +20 -10
  21. data/lib/thrift/processor.rb +7 -6
  22. data/lib/thrift/protocol/base_protocol.rb +52 -21
  23. data/lib/thrift/protocol/binary_protocol.rb +65 -20
  24. data/lib/thrift/protocol/binary_protocol_accelerated.rb +6 -5
  25. data/lib/thrift/protocol/compact_protocol.rb +76 -41
  26. data/lib/thrift/protocol/header_protocol.rb +321 -0
  27. data/lib/thrift/protocol/json_protocol.rb +44 -27
  28. data/lib/thrift/protocol/multiplexed_protocol.rb +6 -5
  29. data/lib/thrift/protocol/protocol_decorator.rb +13 -4
  30. data/lib/thrift/serializer/deserializer.rb +6 -5
  31. data/lib/thrift/serializer/serializer.rb +5 -5
  32. data/lib/thrift/server/base_server.rb +5 -4
  33. data/lib/thrift/server/mongrel_http_server.rb +7 -6
  34. data/lib/thrift/server/nonblocking_server.rb +35 -9
  35. data/lib/thrift/server/simple_server.rb +13 -5
  36. data/lib/thrift/server/thin_http_server.rb +4 -3
  37. data/lib/thrift/server/thread_pool_server.rb +7 -6
  38. data/lib/thrift/server/threaded_server.rb +13 -5
  39. data/lib/thrift/struct.rb +12 -11
  40. data/lib/thrift/struct_union.rb +14 -9
  41. data/lib/thrift/thrift_native.rb +3 -2
  42. data/lib/thrift/transport/base_server_transport.rb +8 -5
  43. data/lib/thrift/transport/base_transport.rb +18 -14
  44. data/lib/thrift/transport/buffered_transport.rb +7 -6
  45. data/lib/thrift/transport/framed_transport.rb +8 -7
  46. data/lib/thrift/transport/header_transport.rb +562 -0
  47. data/lib/thrift/transport/http_client_transport.rb +2 -1
  48. data/lib/thrift/transport/io_stream_transport.rb +4 -3
  49. data/lib/thrift/transport/memory_buffer_transport.rb +13 -6
  50. data/lib/thrift/transport/server_socket.rb +14 -8
  51. data/lib/thrift/transport/socket.rb +126 -60
  52. data/lib/thrift/transport/ssl_server_socket.rb +4 -3
  53. data/lib/thrift/transport/ssl_socket.rb +45 -13
  54. data/lib/thrift/transport/unix_server_socket.rb +9 -5
  55. data/lib/thrift/transport/unix_socket.rb +7 -6
  56. data/lib/thrift/types.rb +10 -6
  57. data/lib/thrift/union.rb +15 -8
  58. data/lib/thrift/uuid.rb +50 -0
  59. data/lib/thrift.rb +4 -1
  60. data/spec/ThriftSpec.thrift +21 -1
  61. data/spec/base_protocol_spec.rb +21 -2
  62. data/spec/base_transport_spec.rb +48 -8
  63. data/spec/binary_protocol_accelerated_spec.rb +1 -0
  64. data/spec/binary_protocol_spec.rb +1 -2
  65. data/spec/binary_protocol_spec_shared.rb +206 -155
  66. data/spec/bytes_spec.rb +71 -114
  67. data/spec/client_spec.rb +86 -19
  68. data/spec/compact_protocol_spec.rb +153 -16
  69. data/spec/constants_demo_spec.rb +102 -0
  70. data/spec/exception_spec.rb +1 -1
  71. data/spec/flat_spec.rb +1 -0
  72. data/spec/header_protocol_spec.rb +476 -0
  73. data/spec/header_transport_spec.rb +431 -0
  74. data/spec/http_client_spec.rb +5 -6
  75. data/spec/json_protocol_spec.rb +69 -47
  76. data/spec/multiplexed_processor_spec.rb +75 -0
  77. data/spec/namespaced_spec.rb +1 -1
  78. data/spec/nonblocking_server_spec.rb +174 -8
  79. data/spec/processor_spec.rb +1 -1
  80. data/spec/recursion_depth_spec.rb +223 -0
  81. data/spec/serializer_spec.rb +1 -1
  82. data/spec/server_socket_spec.rb +38 -1
  83. data/spec/server_spec.rb +60 -9
  84. data/spec/socket_spec.rb +119 -13
  85. data/spec/socket_spec_shared.rb +73 -9
  86. data/spec/spec_helper.rb +2 -1
  87. data/spec/ssl_server_socket_spec.rb +52 -1
  88. data/spec/ssl_socket_spec.rb +181 -11
  89. data/spec/struct_nested_containers_spec.rb +2 -2
  90. data/spec/struct_spec.rb +114 -9
  91. data/spec/support/header_protocol_helper.rb +55 -0
  92. data/spec/thin_http_server_spec.rb +4 -18
  93. data/spec/types_spec.rb +26 -26
  94. data/spec/union_spec.rb +70 -11
  95. data/spec/unix_socket_spec.rb +17 -2
  96. data/spec/uuid_validation_spec.rb +239 -0
  97. data/test/fuzz/Makefile +779 -0
  98. data/test/fuzz/Makefile.am +173 -0
  99. data/test/fuzz/Makefile.in +775 -0
  100. data/test/fuzz/README.md +149 -0
  101. data/test/fuzz/fuzz_common.rb +96 -0
  102. data/{lib/thrift/core_ext.rb → test/fuzz/fuzz_parse_binary_protocol.rb} +4 -4
  103. data/{lib/thrift/core_ext/fixnum.rb → test/fuzz/fuzz_parse_binary_protocol_accelerated.rb} +7 -13
  104. data/test/fuzz/fuzz_parse_binary_protocol_accelerated_harness.rb +23 -0
  105. data/test/fuzz/fuzz_parse_binary_protocol_harness.rb +23 -0
  106. data/test/fuzz/fuzz_parse_compact_protocol.rb +23 -0
  107. data/test/fuzz/fuzz_parse_compact_protocol_harness.rb +23 -0
  108. data/test/fuzz/fuzz_parse_json_protocol.rb +23 -0
  109. data/test/fuzz/fuzz_parse_json_protocol_harness.rb +23 -0
  110. data/test/fuzz/fuzz_roundtrip_binary_protocol.rb +23 -0
  111. data/test/fuzz/fuzz_roundtrip_binary_protocol_accelerated.rb +23 -0
  112. data/test/fuzz/fuzz_roundtrip_binary_protocol_accelerated_harness.rb +23 -0
  113. data/test/fuzz/fuzz_roundtrip_binary_protocol_harness.rb +23 -0
  114. data/test/fuzz/fuzz_roundtrip_compact_protocol.rb +23 -0
  115. data/test/fuzz/fuzz_roundtrip_compact_protocol_harness.rb +23 -0
  116. data/test/fuzz/fuzz_roundtrip_json_protocol.rb +23 -0
  117. data/test/fuzz/fuzz_roundtrip_json_protocol_harness.rb +23 -0
  118. data/test/fuzz/fuzz_tracer.rb +29 -0
  119. metadata +105 -70
@@ -1,5 +1,6 @@
1
1
  # encoding: ascii-8bit
2
- #
2
+ # frozen_string_literal: true
3
+ #
3
4
  # Licensed to the Apache Software Foundation (ASF) under one
4
5
  # or more contributor license agreements. See the NOTICE file
5
6
  # distributed with this work for additional information
@@ -7,23 +8,23 @@
7
8
  # to you under the Apache License, Version 2.0 (the
8
9
  # "License"); you may not use this file except in compliance
9
10
  # with the License. You may obtain a copy of the License at
10
- #
11
+ #
11
12
  # http://www.apache.org/licenses/LICENSE-2.0
12
- #
13
+ #
13
14
  # Unless required by applicable law or agreed to in writing,
14
15
  # software distributed under the License is distributed on an
15
16
  # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16
17
  # KIND, either express or implied. See the License for the
17
18
  # specific language governing permissions and limitations
18
19
  # under the License.
19
- #
20
+ #
20
21
 
21
22
  require 'socket'
22
23
 
23
24
  module Thrift
24
25
  class ServerSocket < BaseServerTransport
25
- # call-seq: initialize(host = nil, port)
26
- def initialize(host_or_port, port = nil)
26
+ # call-seq: initialize(host = nil, port, client_timeout: DEFAULT_CLIENT_TIMEOUT)
27
+ def initialize(host_or_port, port = nil, client_timeout: DEFAULT_CLIENT_TIMEOUT)
27
28
  if port
28
29
  @host = host_or_port
29
30
  @port = port
@@ -31,10 +32,11 @@ module Thrift
31
32
  @host = nil
32
33
  @port = host_or_port
33
34
  end
35
+ @client_timeout = client_timeout
34
36
  @handle = nil
35
37
  end
36
38
 
37
- attr_reader :handle
39
+ attr_reader :handle, :client_timeout
38
40
 
39
41
  def listen
40
42
  @handle = TCPServer.new(@host, @port)
@@ -43,7 +45,9 @@ module Thrift
43
45
  def accept
44
46
  unless @handle.nil?
45
47
  sock = @handle.accept
48
+ sock.setsockopt(::Socket::IPPROTO_TCP, ::Socket::TCP_NODELAY, 1)
46
49
  trans = Socket.new
50
+ trans.timeout = @client_timeout
47
51
  trans.handle = sock
48
52
  trans
49
53
  end
@@ -58,7 +62,9 @@ module Thrift
58
62
  @handle.nil? or @handle.closed?
59
63
  end
60
64
 
61
- alias to_io handle
65
+ def to_io
66
+ @handle&.to_io || raise(IOError, 'closed stream')
67
+ end
62
68
 
63
69
  def to_s
64
70
  "socket(#{@host}:#{@port})"
@@ -1,5 +1,6 @@
1
1
  # encoding: ascii-8bit
2
- #
2
+ # frozen_string_literal: true
3
+ #
3
4
  # Licensed to the Apache Software Foundation (ASF) under one
4
5
  # or more contributor license agreements. See the NOTICE file
5
6
  # distributed with this work for additional information
@@ -7,22 +8,22 @@
7
8
  # to you under the Apache License, Version 2.0 (the
8
9
  # "License"); you may not use this file except in compliance
9
10
  # with the License. You may obtain a copy of the License at
10
- #
11
+ #
11
12
  # http://www.apache.org/licenses/LICENSE-2.0
12
- #
13
+ #
13
14
  # Unless required by applicable law or agreed to in writing,
14
15
  # software distributed under the License is distributed on an
15
16
  # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16
17
  # KIND, either express or implied. See the License for the
17
18
  # specific language governing permissions and limitations
18
19
  # under the License.
19
- #
20
+ #
20
21
 
21
22
  require 'socket'
22
23
 
23
24
  module Thrift
24
25
  class Socket < BaseTransport
25
- def initialize(host='localhost', port=9090, timeout=nil)
26
+ def initialize(host = 'localhost', port = 9090, timeout = nil)
26
27
  @host = host
27
28
  @port = port
28
29
  @timeout = timeout
@@ -33,111 +34,176 @@ module Thrift
33
34
  attr_accessor :handle, :timeout
34
35
 
35
36
  def open
36
- for addrinfo in ::Socket::getaddrinfo(@host, @port, nil, ::Socket::SOCK_STREAM) do
37
- begin
38
- socket = ::Socket.new(addrinfo[4], ::Socket::SOCK_STREAM, 0)
39
- socket.setsockopt(::Socket::IPPROTO_TCP, ::Socket::TCP_NODELAY, 1)
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
+ deadline = Process.clock_gettime(Process::CLOCK_MONOTONIC) + @timeout unless @timeout.nil? || @timeout == 0
38
+ @handle = connect_socket(deadline)
58
39
  end
59
40
 
60
41
  def open?
61
- !@handle.nil? and !@handle.closed?
42
+ !@handle.nil? && !@handle.closed?
62
43
  end
63
44
 
64
45
  def write(str)
65
- raise IOError, "closed stream" unless open?
46
+ raise TransportException.new(TransportException::NOT_OPEN, "closed stream") unless open?
66
47
  str = Bytes.force_binary_encoding(str)
67
48
  begin
68
- if @timeout.nil? or @timeout == 0
49
+ if @timeout.nil? || @timeout == 0
69
50
  @handle.write(str)
70
51
  else
52
+ deadline = Process.clock_gettime(Process::CLOCK_MONOTONIC) + @timeout
71
53
  len = 0
72
- start = Time.now
73
- while Time.now - start < @timeout
74
- rd, wr, = IO.select(nil, [@handle], nil, @timeout)
75
- if wr and not wr.empty?
54
+
55
+ while len < str.length
56
+ begin
76
57
  len += @handle.write_nonblock(str[len..-1])
77
- break if len >= str.length
58
+ rescue IO::WaitWritable
59
+ wait_for(:write, deadline, str.length)
60
+ rescue IO::WaitReadable
61
+ wait_for(:read, deadline, str.length)
78
62
  end
79
63
  end
80
- if len < str.length
81
- raise TransportException.new(TransportException::TIMED_OUT, "Socket: Timed out writing #{str.length} bytes to #{@desc}")
82
- else
83
- len
84
- end
64
+
65
+ len
85
66
  end
86
67
  rescue TransportException => e
87
68
  # pass this on
88
69
  raise e
89
70
  rescue StandardError => e
90
- @handle.close
71
+ close_socket(@handle)
91
72
  @handle = nil
92
73
  raise TransportException.new(TransportException::NOT_OPEN, e.message)
93
74
  end
94
75
  end
95
76
 
96
77
  def read(sz)
97
- raise IOError, "closed stream" unless open?
78
+ raise TransportException.new(TransportException::NOT_OPEN, "closed stream") unless open?
98
79
 
99
80
  begin
100
- if @timeout.nil? or @timeout == 0
81
+ if @timeout.nil? || @timeout == 0
101
82
  data = @handle.readpartial(sz)
102
83
  else
103
- # it's possible to interrupt select for something other than the timeout
104
- # so we need to ensure we've waited long enough, but not too long
105
- start = Time.now
106
- timespent = 0
107
- rd = loop do
108
- rd, = IO.select([@handle], nil, nil, @timeout - timespent)
109
- timespent = Time.now - start
110
- break rd if (rd and not rd.empty?) or timespent >= @timeout
111
- end
112
- if rd.nil? or rd.empty?
113
- raise TransportException.new(TransportException::TIMED_OUT, "Socket: Timed out reading #{sz} bytes from #{@desc}")
114
- else
115
- data = @handle.readpartial(sz)
84
+ deadline = Process.clock_gettime(Process::CLOCK_MONOTONIC) + @timeout
85
+
86
+ data = loop do
87
+ begin
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)
93
+ end
116
94
  end
117
95
  end
118
96
  rescue TransportException => e
119
97
  # don't let this get caught by the StandardError handler
120
98
  raise e
121
99
  rescue StandardError => e
122
- @handle.close unless @handle.closed?
100
+ close_socket(@handle)
123
101
  @handle = nil
124
102
  raise TransportException.new(TransportException::NOT_OPEN, e.message)
125
103
  end
126
- if (data.nil? or data.length == 0)
104
+ if (data.nil? || data.length == 0)
127
105
  raise TransportException.new(TransportException::UNKNOWN, "Socket: Could not read #{sz} bytes from #{@desc}")
128
106
  end
129
107
  data
130
108
  end
131
109
 
132
110
  def close
133
- @handle.close unless @handle.nil? or @handle.closed?
111
+ close_socket(@handle)
134
112
  @handle = nil
135
113
  end
136
114
 
137
- alias to_io handle
115
+ def to_io
116
+ @handle&.to_io || raise(IOError, 'closed stream')
117
+ end
138
118
 
139
119
  def to_s
140
120
  "socket(#{@host}:#{@port})"
141
121
  end
122
+
123
+ private
124
+
125
+ def connect_socket(deadline)
126
+ last_error = nil
127
+ connected_socket = nil
128
+
129
+ Addrinfo.foreach(@host, @port, nil, :STREAM) do |addrinfo|
130
+ socket = nil
131
+
132
+ begin
133
+ socket = if deadline
134
+ remaining = deadline - Process.clock_gettime(Process::CLOCK_MONOTONIC)
135
+ raise TransportException.new(TransportException::TIMED_OUT, "Socket: Timed out opening connection to #{@desc}") if remaining <= 0
136
+
137
+ addrinfo.connect(timeout: remaining)
138
+ else
139
+ addrinfo.connect
140
+ end
141
+
142
+ socket.setsockopt(::Socket::IPPROTO_TCP, ::Socket::TCP_NODELAY, 1)
143
+ connected_socket = socket
144
+ break
145
+ rescue Errno::ETIMEDOUT => e
146
+ close_socket(socket)
147
+ last_error = e
148
+ rescue TransportException
149
+ close_socket(socket)
150
+ raise
151
+ rescue StandardError => e
152
+ close_socket(socket)
153
+ last_error = e
154
+ end
155
+ end
156
+
157
+ return connected_socket if connected_socket
158
+
159
+ if last_error.is_a?(Errno::ETIMEDOUT)
160
+ raise TransportException.new(TransportException::TIMED_OUT, "Socket: Timed out opening connection to #{@desc}")
161
+ end
162
+
163
+ if deadline && deadline - Process.clock_gettime(Process::CLOCK_MONOTONIC) <= 0
164
+ raise TransportException.new(TransportException::TIMED_OUT, "Socket: Timed out opening connection to #{@desc}")
165
+ end
166
+
167
+ raise TransportException.new(TransportException::NOT_OPEN, "Could not connect to #{@desc}"), cause: last_error
168
+ rescue TransportException
169
+ raise
170
+ rescue StandardError
171
+ raise TransportException.new(TransportException::NOT_OPEN, "Could not connect to #{@desc}")
172
+ end
173
+
174
+ def close_socket(socket)
175
+ return if socket.nil?
176
+ return if socket.respond_to?(:closed?) && socket.closed?
177
+
178
+ socket.close
179
+ rescue StandardError
180
+ nil
181
+ end
182
+
183
+ def wait_for(operation, deadline, sz)
184
+ rd_ary, wr_ary = case operation
185
+ when :read
186
+ [[@handle], nil]
187
+ when :write
188
+ [nil, [@handle]]
189
+ else
190
+ raise ArgumentError, "Unknown IO wait operation: #{operation.inspect}"
191
+ end
192
+
193
+ loop do
194
+ remaining = deadline - Process.clock_gettime(Process::CLOCK_MONOTONIC)
195
+ if remaining <= 0
196
+ case operation
197
+ when :read
198
+ raise TransportException.new(TransportException::TIMED_OUT, "Socket: Timed out reading #{sz} bytes from #{@desc}")
199
+ when :write
200
+ raise TransportException.new(TransportException::TIMED_OUT, "Socket: Timed out writing #{sz} bytes to #{@desc}")
201
+ end
202
+ end
203
+
204
+ rd, wr, = IO.select(rd_ary, wr_ary, nil, remaining)
205
+ return if (rd && !rd.empty?) || (wr && !wr.empty?)
206
+ end
207
+ end
142
208
  end
143
209
  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
@@ -22,8 +23,8 @@ require 'socket'
22
23
 
23
24
  module Thrift
24
25
  class SSLServerSocket < ServerSocket
25
- def initialize(host_or_port, port = nil, ssl_context = nil)
26
- super(host_or_port, port)
26
+ def initialize(host_or_port, port = nil, ssl_context = nil, client_timeout: DEFAULT_CLIENT_TIMEOUT)
27
+ super(host_or_port, port, client_timeout: client_timeout)
27
28
  @ssl_context = ssl_context
28
29
  end
29
30
 
@@ -33,7 +34,7 @@ module Thrift
33
34
  socket = TCPServer.new(@host, @port)
34
35
  @handle = OpenSSL::SSL::SSLServer.new(socket, @ssl_context)
35
36
  end
36
-
37
+
37
38
  def to_s
38
39
  "ssl(#{super.to_s})"
39
40
  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,9 +18,11 @@
17
18
  # specific language governing permissions and limitations
18
19
  # under the License.
19
20
 
21
+ require 'io/wait'
22
+
20
23
  module Thrift
21
24
  class SSLSocket < Socket
22
- def initialize(host='localhost', port=9090, timeout=nil, ssl_context=nil)
25
+ def initialize(host = 'localhost', port = 9090, timeout = nil, ssl_context = nil)
23
26
  super(host, port, timeout)
24
27
  @ssl_context = ssl_context
25
28
  end
@@ -27,23 +30,52 @@ module Thrift
27
30
  attr_accessor :ssl_context
28
31
 
29
32
  def open
30
- socket = super
31
- @handle = OpenSSL::SSL::SSLSocket.new(socket, @ssl_context)
33
+ deadline = Process.clock_gettime(Process::CLOCK_MONOTONIC) + @timeout unless @timeout.nil? || @timeout == 0
34
+ socket = connect_socket(deadline)
35
+
32
36
  begin
33
- @handle.connect_nonblock
37
+ ssl_socket = OpenSSL::SSL::SSLSocket.new(socket, @ssl_context)
38
+ ssl_socket.sync_close = true
39
+ @handle = ssl_socket
40
+
41
+ if deadline
42
+ loop do
43
+ result = @handle.connect_nonblock(exception: false)
44
+
45
+ case result
46
+ when @handle
47
+ break
48
+ when :wait_readable
49
+ remaining = deadline - Process.clock_gettime(Process::CLOCK_MONOTONIC)
50
+ if remaining <= 0 || !@handle.to_io.wait_readable(remaining)
51
+ raise TransportException.new(TransportException::TIMED_OUT, "SSL socket: Timed out establishing session with #{@desc}")
52
+ end
53
+ when :wait_writable
54
+ remaining = deadline - Process.clock_gettime(Process::CLOCK_MONOTONIC)
55
+ if remaining <= 0 || !@handle.to_io.wait_writable(remaining)
56
+ raise TransportException.new(TransportException::TIMED_OUT, "SSL socket: Timed out establishing session with #{@desc}")
57
+ end
58
+ else
59
+ raise TransportException.new(TransportException::NOT_OPEN, "Could not connect to #{@desc}: unexpected SSL connect result #{result.inspect}")
60
+ end
61
+ end
62
+ else
63
+ @handle.connect
64
+ end
65
+
34
66
  @handle.post_connection_check(@host)
35
67
  @handle
36
- rescue IO::WaitReadable
37
- IO.select([ @handle ], nil, nil, @timeout)
38
- retry
39
- rescue IO::WaitWritable
40
- IO.select(nil, [ @handle ], nil, @timeout)
41
- retry
42
- rescue StandardError => e
43
- raise TransportException.new(TransportException::NOT_OPEN, "Could not connect to #{@desc}: #{e}")
68
+ rescue TransportException
69
+ close_socket(@handle)
70
+ @handle = nil
71
+ raise
72
+ rescue StandardError
73
+ close_socket(@handle || socket)
74
+ @handle = nil
75
+ raise TransportException.new(TransportException::NOT_OPEN, "Could not connect to #{@desc}")
44
76
  end
45
77
  end
46
-
78
+
47
79
  def to_s
48
80
  "ssl(#{super.to_s})"
49
81
  end
@@ -1,5 +1,6 @@
1
1
  # encoding: ascii-8bit
2
- #
2
+ # frozen_string_literal: true
3
+ #
3
4
  # Licensed to the Apache Software Foundation (ASF) under one
4
5
  # or more contributor license agreements. See the NOTICE file
5
6
  # distributed with this work for additional information
@@ -7,27 +8,29 @@
7
8
  # to you under the Apache License, Version 2.0 (the
8
9
  # "License"); you may not use this file except in compliance
9
10
  # with the License. You may obtain a copy of the License at
10
- #
11
+ #
11
12
  # http://www.apache.org/licenses/LICENSE-2.0
12
- #
13
+ #
13
14
  # Unless required by applicable law or agreed to in writing,
14
15
  # software distributed under the License is distributed on an
15
16
  # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16
17
  # KIND, either express or implied. See the License for the
17
18
  # specific language governing permissions and limitations
18
19
  # under the License.
19
- #
20
+ #
20
21
 
21
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,5 +1,6 @@
1
1
  # encoding: ascii-8bit
2
- #
2
+ # frozen_string_literal: true
3
+ #
3
4
  # Licensed to the Apache Software Foundation (ASF) under one
4
5
  # or more contributor license agreements. See the NOTICE file
5
6
  # distributed with this work for additional information
@@ -7,22 +8,22 @@
7
8
  # to you under the Apache License, Version 2.0 (the
8
9
  # "License"); you may not use this file except in compliance
9
10
  # with the License. You may obtain a copy of the License at
10
- #
11
+ #
11
12
  # http://www.apache.org/licenses/LICENSE-2.0
12
- #
13
+ #
13
14
  # Unless required by applicable law or agreed to in writing,
14
15
  # software distributed under the License is distributed on an
15
16
  # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16
17
  # KIND, either express or implied. See the License for the
17
18
  # specific language governing permissions and limitations
18
19
  # under the License.
19
- #
20
+ #
20
21
 
21
22
  require 'socket'
22
23
 
23
24
  module Thrift
24
25
  class UNIXSocket < Socket
25
- def initialize(path, timeout=nil)
26
+ def initialize(path, timeout = nil)
26
27
  @path = path
27
28
  @timeout = timeout
28
29
  @desc = @path # for read()'s error
@@ -36,7 +37,7 @@ module Thrift
36
37
  raise TransportException.new(TransportException::NOT_OPEN, "Could not open UNIX socket at #{@path}")
37
38
  end
38
39
  end
39
-
40
+
40
41
  def to_s
41
42
  "domain(#{@path})"
42
43
  end
data/lib/thrift/types.rb CHANGED
@@ -1,4 +1,5 @@
1
- #
1
+ # frozen_string_literal: true
2
+ #
2
3
  # Licensed to the Apache Software Foundation (ASF) under one
3
4
  # or more contributor license agreements. See the NOTICE file
4
5
  # distributed with this work for additional information
@@ -6,16 +7,16 @@
6
7
  # to you under the Apache License, Version 2.0 (the
7
8
  # "License"); you may not use this file except in compliance
8
9
  # with the License. You may obtain a copy of the License at
9
- #
10
+ #
10
11
  # http://www.apache.org/licenses/LICENSE-2.0
11
- #
12
+ #
12
13
  # Unless required by applicable law or agreed to in writing,
13
14
  # software distributed under the License is distributed on an
14
15
  # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15
16
  # KIND, either express or implied. See the License for the
16
17
  # specific language governing permissions and limitations
17
18
  # under the License.
18
- #
19
+ #
19
20
 
20
21
  require 'set'
21
22
 
@@ -34,6 +35,7 @@ module Thrift
34
35
  MAP = 13
35
36
  SET = 14
36
37
  LIST = 15
38
+ UUID = 16
37
39
  end
38
40
 
39
41
  class << self
@@ -43,7 +45,7 @@ module Thrift
43
45
  class TypeError < Exception
44
46
  end
45
47
 
46
- def self.check_type(value, field, name, skip_nil=true)
48
+ def self.check_type(value, field, name, skip_nil = true)
47
49
  return if value.nil? and skip_nil
48
50
  klasses = case field[:type]
49
51
  when Types::VOID
@@ -56,6 +58,8 @@ module Thrift
56
58
  Float
57
59
  when Types::STRING
58
60
  String
61
+ when Types::UUID
62
+ String
59
63
  when Types::STRUCT
60
64
  [Struct, Union]
61
65
  when Types::MAP
@@ -70,7 +74,7 @@ module Thrift
70
74
  # check elements now
71
75
  case field[:type]
72
76
  when Types::MAP
73
- value.each_pair do |k,v|
77
+ value.each_pair do |k, v|
74
78
  check_type(k, field[:key], "#{name}.key", false)
75
79
  check_type(v, field[:value], "#{name}.value", false)
76
80
  end
data/lib/thrift/union.rb CHANGED
@@ -1,4 +1,5 @@
1
- #
1
+ # frozen_string_literal: true
2
+ #
2
3
  # Licensed to the Apache Software Foundation (ASF) under one
3
4
  # or more contributor license agreements. See the NOTICE file
4
5
  # distributed with this work for additional information
@@ -6,20 +7,20 @@
6
7
  # to you under the Apache License, Version 2.0 (the
7
8
  # "License"); you may not use this file except in compliance
8
9
  # with the License. You may obtain a copy of the License at
9
- #
10
+ #
10
11
  # http://www.apache.org/licenses/LICENSE-2.0
11
- #
12
+ #
12
13
  # Unless required by applicable law or agreed to in writing,
13
14
  # software distributed under the License is distributed on an
14
15
  # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15
16
  # KIND, either express or implied. See the License for the
16
17
  # specific language governing permissions and limitations
17
18
  # under the License.
18
- #
19
+ #
19
20
 
20
21
  module Thrift
21
22
  class Union
22
- def initialize(name=nil, value=nil)
23
+ def initialize(name = nil, value = nil)
23
24
  if name
24
25
  if name.is_a? Hash
25
26
  if name.size > 1
@@ -60,7 +61,9 @@ module Thrift
60
61
  iprot.read_field_end
61
62
 
62
63
  fname, ftype, fid = iprot.read_field_begin
63
- raise "Too many fields for union" unless (ftype == Types::STOP)
64
+ unless (ftype == Types::STOP)
65
+ raise ProtocolException.new(ProtocolException::INVALID_DATA, "Too many fields for union")
66
+ end
64
67
 
65
68
  iprot.read_struct_end
66
69
  validate
@@ -73,6 +76,10 @@ module Thrift
73
76
  fid = self.name_to_id(@setfield.to_s)
74
77
 
75
78
  field_info = struct_fields[fid]
79
+ unless field_info
80
+ raise ProtocolException.new(ProtocolException::INVALID_DATA, "set_field is not valid for this union!")
81
+ end
82
+
76
83
  type = field_info[:type]
77
84
  if is_container? type
78
85
  oprot.write_field_begin(@setfield, type, fid)
@@ -99,7 +106,7 @@ module Thrift
99
106
  klass.send :define_method, field_info[:name] do
100
107
  if field_info[:name].to_sym == @setfield
101
108
  @value
102
- else
109
+ else
103
110
  raise RuntimeError, "#{field_info[:name]} is not union's set field."
104
111
  end
105
112
  end
@@ -124,7 +131,7 @@ module Thrift
124
131
  end
125
132
  end
126
133
 
127
- # get the symbol that indicates what the currently set field type is.
134
+ # get the symbol that indicates what the currently set field type is.
128
135
  def get_set_field
129
136
  @setfield
130
137
  end