thrift 0.24.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.
Files changed (120) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +107 -4
  3. data/ext/binary_protocol_accelerated.c +52 -17
  4. data/ext/compact_protocol.c +135 -70
  5. data/ext/constants.h +3 -0
  6. data/ext/extconf.rb +4 -4
  7. data/ext/macros.h +11 -0
  8. data/ext/memory_buffer.c +35 -17
  9. data/ext/struct.c +185 -64
  10. data/ext/thrift_native.c +6 -0
  11. data/lib/thrift/bytes.rb +2 -2
  12. data/lib/thrift/client.rb +31 -22
  13. data/lib/thrift/exceptions.rb +10 -8
  14. data/lib/thrift/multiplexed_processor.rb +5 -6
  15. data/lib/thrift/processor.rb +24 -3
  16. data/lib/thrift/protocol/base_protocol.rb +53 -27
  17. data/lib/thrift/protocol/binary_protocol.rb +54 -40
  18. data/lib/thrift/protocol/binary_protocol_accelerated.rb +6 -2
  19. data/lib/thrift/protocol/compact_protocol.rb +193 -88
  20. data/lib/thrift/protocol/header_protocol.rb +14 -3
  21. data/lib/thrift/protocol/json_protocol.rb +146 -104
  22. data/lib/thrift/protocol/multiplexed_protocol.rb +2 -3
  23. data/lib/thrift/protocol/protocol_decorator.rb +5 -2
  24. data/lib/thrift/serializer/serializer.rb +6 -0
  25. data/lib/thrift/server/base_server.rb +10 -2
  26. data/lib/thrift/server/nonblocking_server.rb +49 -26
  27. data/lib/thrift/server/rack_application.rb +69 -0
  28. data/lib/thrift/server/simple_server.rb +27 -23
  29. data/lib/thrift/server/thin_http_server.rb +20 -44
  30. data/lib/thrift/server/thread_pool_server.rb +20 -17
  31. data/lib/thrift/server/threaded_server.rb +22 -26
  32. data/lib/thrift/struct.rb +33 -18
  33. data/lib/thrift/struct_union.rb +36 -30
  34. data/lib/thrift/transport/base_transport.rb +23 -5
  35. data/lib/thrift/transport/buffered_transport.rb +4 -4
  36. data/lib/thrift/transport/framed_transport.rb +32 -7
  37. data/lib/thrift/transport/header_transport.rb +130 -50
  38. data/lib/thrift/transport/http_client_transport.rb +27 -14
  39. data/lib/thrift/transport/io_stream_transport.rb +2 -1
  40. data/lib/thrift/transport/memory_buffer_transport.rb +8 -10
  41. data/lib/thrift/transport/server_socket.rb +4 -5
  42. data/lib/thrift/transport/socket.rb +20 -22
  43. data/lib/thrift/transport/ssl_server_socket.rb +64 -4
  44. data/lib/thrift/transport/ssl_socket.rb +32 -5
  45. data/lib/thrift/transport/unix_server_socket.rb +1 -1
  46. data/lib/thrift/transport/unix_socket.rb +4 -6
  47. data/lib/thrift/types.rb +22 -22
  48. data/lib/thrift/union.rb +20 -11
  49. data/lib/thrift/uuid.rb +8 -8
  50. data/lib/thrift.rb +39 -39
  51. metadata +5 -230
  52. data/benchmark/Benchmark.thrift +0 -24
  53. data/benchmark/benchmark.rb +0 -286
  54. data/benchmark/client.rb +0 -118
  55. data/benchmark/server.rb +0 -121
  56. data/benchmark/thin_server.rb +0 -46
  57. data/lib/thrift/server/mongrel_http_server.rb +0 -61
  58. data/spec/BaseService.thrift +0 -27
  59. data/spec/ExtendedService.thrift +0 -25
  60. data/spec/Referenced.thrift +0 -44
  61. data/spec/ThriftNamespacedSpec.thrift +0 -53
  62. data/spec/ThriftSpec.thrift +0 -203
  63. data/spec/base_protocol_spec.rb +0 -244
  64. data/spec/base_transport_spec.rb +0 -428
  65. data/spec/binary_protocol_accelerated_spec.rb +0 -47
  66. data/spec/binary_protocol_spec.rb +0 -73
  67. data/spec/binary_protocol_spec_shared.rb +0 -509
  68. data/spec/bytes_spec.rb +0 -117
  69. data/spec/client_spec.rb +0 -167
  70. data/spec/compact_protocol_spec.rb +0 -295
  71. data/spec/constants_demo_spec.rb +0 -102
  72. data/spec/exception_spec.rb +0 -141
  73. data/spec/flat_spec.rb +0 -63
  74. data/spec/header_protocol_spec.rb +0 -476
  75. data/spec/header_transport_spec.rb +0 -431
  76. data/spec/http_client_spec.rb +0 -160
  77. data/spec/json_protocol_spec.rb +0 -574
  78. data/spec/multiplexed_processor_spec.rb +0 -75
  79. data/spec/namespaced_spec.rb +0 -67
  80. data/spec/nonblocking_server_spec.rb +0 -429
  81. data/spec/processor_spec.rb +0 -80
  82. data/spec/recursion_depth_spec.rb +0 -223
  83. data/spec/serializer_spec.rb +0 -67
  84. data/spec/server_socket_spec.rb +0 -121
  85. data/spec/server_spec.rb +0 -238
  86. data/spec/socket_spec.rb +0 -174
  87. data/spec/socket_spec_shared.rb +0 -168
  88. data/spec/spec_helper.rb +0 -70
  89. data/spec/ssl_server_socket_spec.rb +0 -85
  90. data/spec/ssl_socket_spec.rb +0 -248
  91. data/spec/struct_nested_containers_spec.rb +0 -191
  92. data/spec/struct_spec.rb +0 -398
  93. data/spec/support/header_protocol_helper.rb +0 -55
  94. data/spec/thin_http_server_spec.rb +0 -127
  95. data/spec/types_spec.rb +0 -118
  96. data/spec/union_spec.rb +0 -273
  97. data/spec/unix_socket_spec.rb +0 -131
  98. data/spec/uuid_validation_spec.rb +0 -239
  99. data/test/fuzz/Makefile +0 -779
  100. data/test/fuzz/Makefile.am +0 -173
  101. data/test/fuzz/Makefile.in +0 -775
  102. data/test/fuzz/README.md +0 -149
  103. data/test/fuzz/fuzz_common.rb +0 -96
  104. data/test/fuzz/fuzz_parse_binary_protocol.rb +0 -23
  105. data/test/fuzz/fuzz_parse_binary_protocol_accelerated.rb +0 -23
  106. data/test/fuzz/fuzz_parse_binary_protocol_accelerated_harness.rb +0 -23
  107. data/test/fuzz/fuzz_parse_binary_protocol_harness.rb +0 -23
  108. data/test/fuzz/fuzz_parse_compact_protocol.rb +0 -23
  109. data/test/fuzz/fuzz_parse_compact_protocol_harness.rb +0 -23
  110. data/test/fuzz/fuzz_parse_json_protocol.rb +0 -23
  111. data/test/fuzz/fuzz_parse_json_protocol_harness.rb +0 -23
  112. data/test/fuzz/fuzz_roundtrip_binary_protocol.rb +0 -23
  113. data/test/fuzz/fuzz_roundtrip_binary_protocol_accelerated.rb +0 -23
  114. data/test/fuzz/fuzz_roundtrip_binary_protocol_accelerated_harness.rb +0 -23
  115. data/test/fuzz/fuzz_roundtrip_binary_protocol_harness.rb +0 -23
  116. data/test/fuzz/fuzz_roundtrip_compact_protocol.rb +0 -23
  117. data/test/fuzz/fuzz_roundtrip_compact_protocol_harness.rb +0 -23
  118. data/test/fuzz/fuzz_roundtrip_json_protocol.rb +0 -23
  119. data/test/fuzz/fuzz_roundtrip_json_protocol_harness.rb +0 -23
  120. data/test/fuzz/fuzz_tracer.rb +0 -29
@@ -18,15 +18,20 @@
18
18
  # under the License.
19
19
  #
20
20
 
21
- require 'logger'
22
- require 'thread'
21
+ require "logger"
22
+ require "thread"
23
23
 
24
24
  module Thrift
25
25
  # this class expects to always use a FramedTransport for reading messages
26
26
  class NonblockingServer < BaseServer
27
- def initialize(processor, server_transport, transport_factory = nil, protocol_factory = nil, num = 20, logger = nil)
27
+ def initialize(processor, server_transport, transport_factory = nil, protocol_factory = nil, num = 20, logger = nil,
28
+ max_frame_size: FramedTransport::DEFAULT_MAX_FRAME_SIZE)
28
29
  super(processor, server_transport, transport_factory, protocol_factory)
30
+ unless max_frame_size > 0 && max_frame_size <= FramedTransport::HARD_MAX_FRAME_SIZE
31
+ raise ArgumentError, "max_frame_size must be > 0 and <= #{FramedTransport::HARD_MAX_FRAME_SIZE}"
32
+ end
29
33
  @num_threads = num
34
+ @max_frame_size = max_frame_size
30
35
  if logger.nil?
31
36
  @logger = Logger.new(STDERR)
32
37
  @logger.level = Logger::WARN
@@ -53,11 +58,16 @@ module Thrift
53
58
  break
54
59
  end
55
60
  next if rd.nil?
56
- socket = @server_transport.accept
61
+ begin
62
+ socket = @server_transport.accept
63
+ rescue => e
64
+ next if defined?(OpenSSL::SSL::SSLError) && e.is_a?(OpenSSL::SSL::SSLError)
65
+ raise
66
+ end
57
67
  @logger.debug "Accepted socket: #{socket.inspect}"
58
68
  @io_manager.add_connection socket
59
69
  end
60
- rescue IOError => e
70
+ rescue IOError
61
71
  end
62
72
  # we must be shutting down
63
73
  @logger.info "#{self} is shutting down, goodbye"
@@ -84,14 +94,17 @@ module Thrift
84
94
  if block
85
95
  shutdown_proc.call
86
96
  else
87
- Thread.new &shutdown_proc
97
+ Thread.new(&shutdown_proc)
88
98
  end
89
99
  end
90
100
 
91
101
  private
92
102
 
93
103
  def start_io_manager
94
- iom = IOManager.new(@processor, @server_transport, @transport_factory, @protocol_factory, @num_threads, @logger)
104
+ iom = IOManager.new(
105
+ @processor, @server_transport, @transport_factory, @protocol_factory, @num_threads, @logger,
106
+ max_frame_size: @max_frame_size,
107
+ )
95
108
  iom.spawn
96
109
  iom
97
110
  end
@@ -99,13 +112,15 @@ module Thrift
99
112
  class IOManager # :nodoc:
100
113
  DEFAULT_BUFFER = 2**20
101
114
 
102
- def initialize(processor, server_transport, transport_factory, protocol_factory, num, logger)
115
+ def initialize(processor, server_transport, transport_factory, protocol_factory, num, logger,
116
+ max_frame_size: FramedTransport::DEFAULT_MAX_FRAME_SIZE)
103
117
  @processor = processor
104
118
  @server_transport = server_transport
105
119
  @transport_factory = transport_factory
106
120
  @protocol_factory = protocol_factory
107
121
  @num_threads = num
108
122
  @logger = logger
123
+ @max_frame_size = max_frame_size
109
124
  @connections = []
110
125
  @buffers = Hash.new { |h, k| h[k] = Bytes.empty_byte_buffer }
111
126
  @signal_queue = Queue.new
@@ -158,15 +173,13 @@ module Thrift
158
173
  break if read_signals == :shutdown
159
174
  end
160
175
  rd.each do |fd|
161
- begin
162
- if fd.handle.eof?
163
- remove_connection fd
164
- else
165
- read_connection fd
166
- end
167
- rescue Errno::ECONNRESET
176
+ if fd.handle.eof?
168
177
  remove_connection fd
178
+ else
179
+ read_connection fd
169
180
  end
181
+ rescue Errno::ECONNRESET
182
+ remove_connection fd
170
183
  end
171
184
  end
172
185
  join_worker_threads(@shutdown_timeout)
@@ -175,8 +188,22 @@ module Thrift
175
188
  end
176
189
 
177
190
  def read_connection(fd)
178
- @buffers[fd] << fd.read(DEFAULT_BUFFER)
179
- while(frame = slice_frame!(@buffers[fd]))
191
+ buf = @buffers[fd]
192
+ buf << fd.read(DEFAULT_BUFFER)
193
+ while buf.length >= 4
194
+ # Refuse the size before collecting the frame: the four-byte length
195
+ # is read here and the bytes are then buffered as they arrive, for as
196
+ # long as the declared length allows. FramedTransport applies the
197
+ # same maximum to the frame the worker later reads back.
198
+ size = buf.unpack1("N")
199
+ if size > @max_frame_size
200
+ @logger.error "Frame size #{size} exceeds maximum #{@max_frame_size}, closing connection"
201
+ fd.close
202
+ remove_connection fd
203
+ break
204
+ end
205
+ frame = slice_frame!(buf)
206
+ break if frame.nil?
180
207
  @logger.debug "#{self} is processing a frame"
181
208
  @worker_queue.push [:frame, fd, frame]
182
209
  end
@@ -254,10 +281,8 @@ module Thrift
254
281
 
255
282
  def close_connections
256
283
  @connections.each do |fd|
257
- begin
258
- fd.close
259
- rescue IOError, SystemCallError, TransportException
260
- end
284
+ fd.close
285
+ rescue IOError, SystemCallError, TransportException
261
286
  end
262
287
  @connections.clear
263
288
  @buffers.clear
@@ -265,16 +290,14 @@ module Thrift
265
290
 
266
291
  def close_signal_pipes
267
292
  @signal_pipes.each do |pipe|
268
- begin
269
- pipe.close unless pipe.closed?
270
- rescue IOError
271
- end
293
+ pipe.close unless pipe.closed?
294
+ rescue IOError
272
295
  end
273
296
  end
274
297
 
275
298
  def slice_frame!(buf)
276
299
  if buf.length >= 4
277
- size = buf.unpack('N').first
300
+ size = buf.unpack1("N")
278
301
  if buf.length >= size + 4
279
302
  buf.slice!(0, size + 4)
280
303
  else
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+ #
3
+ # Licensed to the Apache Software Foundation (ASF) under one
4
+ # or more contributor license agreements. See the NOTICE file
5
+ # distributed with this work for additional information
6
+ # regarding copyright ownership. The ASF licenses this file
7
+ # to you under the Apache License, Version 2.0 (the
8
+ # "License"); you may not use this file except in compliance
9
+ # with the License. You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing,
14
+ # software distributed under the License is distributed on an
15
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16
+ # KIND, either express or implied. See the License for the
17
+ # specific language governing permissions and limitations
18
+ # under the License.
19
+ #
20
+
21
+ require "rack"
22
+ require "thrift/transport/io_stream_transport"
23
+
24
+ module Thrift
25
+ class RackApplication
26
+ THRIFT_HEADER = "application/x-thrift"
27
+
28
+ def initialize(processor, protocol_factory = BinaryProtocolFactory.new)
29
+ @processor = processor
30
+ @protocol_factory = protocol_factory
31
+ end
32
+
33
+ def call(env)
34
+ request = Rack::Request.new(env)
35
+
36
+ if self.class.valid_thrift_request?(request)
37
+ self.class.successful_request(request, @processor, @protocol_factory).finish
38
+ else
39
+ self.class.failed_request.finish
40
+ end
41
+ end
42
+
43
+ def self.mapped(path, processor, protocol_factory = BinaryProtocolFactory.new)
44
+ Rack::Builder.new do
45
+ use Rack::ContentLength
46
+ map path do
47
+ run RackApplication.new(processor, protocol_factory)
48
+ end
49
+ end
50
+ end
51
+
52
+ def self.successful_request(rack_request, processor, protocol_factory)
53
+ response = Rack::Response.new([], 200, {Rack::CONTENT_TYPE => THRIFT_HEADER})
54
+ transport = IOStreamTransport.new(rack_request.body, response)
55
+ protocol = protocol_factory.get_protocol(transport)
56
+ processor.process protocol, protocol
57
+
58
+ response
59
+ end
60
+
61
+ def self.failed_request
62
+ Rack::Response.new(["Not Found"], 404, {Rack::CONTENT_TYPE => THRIFT_HEADER})
63
+ end
64
+
65
+ def self.valid_thrift_request?(rack_request)
66
+ rack_request.post? && rack_request.media_type == THRIFT_HEADER
67
+ end
68
+ end
69
+ end
@@ -21,35 +21,39 @@
21
21
  module Thrift
22
22
  class SimpleServer < BaseServer
23
23
  def serve
24
- begin
25
- @server_transport.listen
26
- loop do
27
- begin
28
- client = @server_transport.accept
29
- rescue Errno::ECONNRESET, Errno::EPIPE
30
- next
31
- rescue => e
32
- next if defined?(OpenSSL::SSL::SSLError) && e.is_a?(OpenSSL::SSL::SSLError)
33
- raise
34
- end
35
- trans = @transport_factory.get_transport(client)
36
- prot = @protocol_factory.get_protocol(trans)
37
- begin
38
- loop do
39
- @processor.process(prot, prot)
40
- end
41
- rescue Thrift::TransportException, Thrift::ProtocolException
42
- ensure
43
- trans.close
24
+ @server_transport.listen
25
+ loop do
26
+ begin
27
+ client = @server_transport.accept
28
+ rescue Errno::ECONNRESET, Errno::EPIPE
29
+ next
30
+ rescue => e
31
+ next if defined?(OpenSSL::SSL::SSLError) && e.is_a?(OpenSSL::SSL::SSLError)
32
+ raise
33
+ end
34
+ trans = @transport_factory.get_transport(client)
35
+ prot = @protocol_factory.get_protocol(trans)
36
+ begin
37
+ loop do
38
+ @processor.process(prot, prot)
44
39
  end
40
+ rescue Thrift::TransportException, Thrift::ProtocolException
41
+ # The client hung up or sent a message this connection could not
42
+ # read. Close it below and keep accepting other clients.
43
+ rescue => e
44
+ # Any other error raised while serving this one client must not end
45
+ # the accept loop. Log it, close the connection, and keep serving.
46
+ @logger.error("Error while serving a client connection: #{e.inspect}")
47
+ ensure
48
+ trans.close
45
49
  end
46
- ensure
47
- @server_transport.close
48
50
  end
51
+ ensure
52
+ @server_transport.close
49
53
  end
50
54
 
51
55
  def to_s
52
- "simple(#{super.to_s})"
56
+ "simple(#{super})"
53
57
  end
54
58
  end
55
59
  end
@@ -18,14 +18,16 @@
18
18
  # under the License.
19
19
  #
20
20
 
21
- require 'rack'
22
- require 'thin'
21
+ require "rack"
22
+ require "thin"
23
+ require "thrift/server/rack_application"
23
24
 
24
25
  ##
25
26
  # Wraps the Thin web server to provide a Thrift server over HTTP.
27
+ # <b>DEPRECATED:</b> Use <tt>Thrift::RackApplication</tt> with a maintained Rack
28
+ # server instead.
26
29
  module Thrift
27
30
  class ThinHTTPServer < BaseServer
28
-
29
31
  ##
30
32
  # Accepts a Thrift::Processor
31
33
  # Options include:
@@ -33,13 +35,26 @@ module Thrift
33
35
  # * :ip
34
36
  # * :path
35
37
  # * :protocol_factory
38
+ # * :ssl
39
+ # * :ssl_options
36
40
  def initialize(processor, options = {})
41
+ Kernel.warn "[DEPRECATION WARNING] `Thrift::ThinHTTPServer` is deprecated because Thin is no longer maintained. Please use `Thrift::RackApplication` with a maintained Rack server instead."
37
42
  port = options[:port] || 80
38
43
  ip = options[:ip] || "0.0.0.0"
39
44
  path = options[:path] || "/"
40
45
  protocol_factory = options[:protocol_factory] || BinaryProtocolFactory.new
41
- app = RackApplication.for(path, processor, protocol_factory)
46
+ endpoint = RackApplication.mapped(path, processor, protocol_factory)
47
+ app = Rack::Builder.new do
48
+ use Rack::CommonLogger
49
+ use Rack::ShowExceptions
50
+ use Rack::Lint
51
+ run endpoint
52
+ end
42
53
  @server = Thin::Server.new(ip, port, app)
54
+ if options[:ssl]
55
+ @server.ssl = true
56
+ @server.ssl_options = options[:ssl_options] || {}
57
+ end
43
58
  end
44
59
 
45
60
  ##
@@ -48,45 +63,6 @@ module Thrift
48
63
  @server.start
49
64
  end
50
65
 
51
- class RackApplication
52
-
53
- THRIFT_HEADER = "application/x-thrift"
54
-
55
- def self.for(path, processor, protocol_factory)
56
- Rack::Builder.new do
57
- use Rack::CommonLogger
58
- use Rack::ShowExceptions
59
- use Rack::Lint
60
- map path do
61
- run lambda { |env|
62
- request = Rack::Request.new(env)
63
- if RackApplication.valid_thrift_request?(request)
64
- RackApplication.successful_request(request, processor, protocol_factory).finish
65
- else
66
- RackApplication.failed_request.finish
67
- end
68
- }
69
- end
70
- end
71
- end
72
-
73
- def self.successful_request(rack_request, processor, protocol_factory)
74
- response = Rack::Response.new([], 200, {'Content-Type' => THRIFT_HEADER})
75
- transport = IOStreamTransport.new rack_request.body, response
76
- protocol = protocol_factory.get_protocol transport
77
- processor.process protocol, protocol
78
- response
79
- end
80
-
81
- def self.failed_request
82
- Rack::Response.new(['Not Found'], 404, {'Content-Type' => THRIFT_HEADER})
83
- end
84
-
85
- def self.valid_thrift_request?(rack_request)
86
- rack_request.post? && rack_request.env["CONTENT_TYPE"] == THRIFT_HEADER
87
- end
88
-
89
- end
90
-
66
+ RackApplication = Thrift::RackApplication
91
67
  end
92
68
  end
@@ -18,7 +18,7 @@
18
18
  # under the License.
19
19
  #
20
20
 
21
- require 'thread'
21
+ require "thread"
22
22
 
23
23
  module Thrift
24
24
  class ThreadPoolServer < BaseServer
@@ -47,25 +47,28 @@ module Thrift
47
47
  loop do
48
48
  @thread_q.push(:token)
49
49
  Thread.new do
50
- begin
51
- loop do
50
+ loop do
51
+ begin
52
52
  client = @server_transport.accept
53
- trans = @transport_factory.get_transport(client)
54
- prot = @protocol_factory.get_protocol(trans)
55
- begin
56
- loop do
57
- @processor.process(prot, prot)
58
- end
59
- rescue Thrift::TransportException, Thrift::ProtocolException => e
60
- ensure
61
- trans.close
53
+ rescue => e
54
+ next if defined?(OpenSSL::SSL::SSLError) && e.is_a?(OpenSSL::SSL::SSLError)
55
+ raise
56
+ end
57
+ trans = @transport_factory.get_transport(client)
58
+ prot = @protocol_factory.get_protocol(trans)
59
+ begin
60
+ loop do
61
+ @processor.process(prot, prot)
62
62
  end
63
+ rescue Thrift::TransportException, Thrift::ProtocolException
64
+ ensure
65
+ trans.close
63
66
  end
64
- rescue => e
65
- @exception_q.push(e)
66
- ensure
67
- @thread_q.pop # thread died!
68
67
  end
68
+ rescue => e
69
+ @exception_q.push(e)
70
+ ensure
71
+ @thread_q.pop # thread died!
69
72
  end
70
73
  end
71
74
  ensure
@@ -74,7 +77,7 @@ module Thrift
74
77
  end
75
78
 
76
79
  def to_s
77
- "threadpool(#{super.to_s})"
80
+ "threadpool(#{super})"
78
81
  end
79
82
  end
80
83
  end
@@ -18,42 +18,38 @@
18
18
  # under the License.
19
19
  #
20
20
 
21
- require 'thread'
21
+ require "thread"
22
22
 
23
23
  module Thrift
24
24
  class ThreadedServer < BaseServer
25
25
  def serve
26
- begin
27
- @server_transport.listen
28
- loop do
29
- begin
30
- client = @server_transport.accept
31
- rescue Errno::ECONNRESET, Errno::EPIPE
32
- next
33
- rescue => e
34
- next if defined?(OpenSSL::SSL::SSLError) && e.is_a?(OpenSSL::SSL::SSLError)
35
- raise
36
- end
37
- trans = @transport_factory.get_transport(client)
38
- prot = @protocol_factory.get_protocol(trans)
39
- Thread.new(prot, trans) do |p, t|
40
- begin
41
- loop do
42
- @processor.process(p, p)
43
- end
44
- rescue Thrift::TransportException, Thrift::ProtocolException
45
- ensure
46
- t.close
47
- end
26
+ @server_transport.listen
27
+ loop do
28
+ begin
29
+ client = @server_transport.accept
30
+ rescue Errno::ECONNRESET, Errno::EPIPE
31
+ next
32
+ rescue => e
33
+ next if defined?(OpenSSL::SSL::SSLError) && e.is_a?(OpenSSL::SSL::SSLError)
34
+ raise
35
+ end
36
+ trans = @transport_factory.get_transport(client)
37
+ prot = @protocol_factory.get_protocol(trans)
38
+ Thread.new(prot, trans) do |p, t|
39
+ loop do
40
+ @processor.process(p, p)
48
41
  end
42
+ rescue Thrift::TransportException, Thrift::ProtocolException
43
+ ensure
44
+ t.close
49
45
  end
50
- ensure
51
- @server_transport.close
52
46
  end
47
+ ensure
48
+ @server_transport.close
53
49
  end
54
50
 
55
51
  def to_s
56
- "threaded(#{super.to_s})"
52
+ "threaded(#{super})"
57
53
  end
58
54
  end
59
55
  end
data/lib/thrift/struct.rb CHANGED
@@ -18,7 +18,8 @@
18
18
  # under the License.
19
19
  #
20
20
 
21
- require 'set'
21
+ require "set"
22
+ require "thrift/struct_union"
22
23
 
23
24
  module Thrift
24
25
  module Struct
@@ -52,7 +53,7 @@ module Thrift
52
53
  end
53
54
  end
54
55
 
55
- yield self if block_given?
56
+ yield self if block
56
57
  end
57
58
 
58
59
  def fields_with_default_values
@@ -81,19 +82,31 @@ module Thrift
81
82
  "<#{self.class} #{fields.join(", ")}>"
82
83
  end
83
84
 
84
- def read(iprot)
85
+ def read(iprot, remaining_depth = DEFAULT_RECURSION_DEPTH)
86
+ raise ProtocolException.new(ProtocolException::DEPTH_LIMIT, "Maximum recursion depth exceeded") if remaining_depth <= 0
87
+ unless instance_variables.empty?
88
+ defaults = fields_with_default_values
89
+ struct_fields.each_value do |field_info|
90
+ instance_variable_set("@#{field_info[:name]}", nil)
91
+ end
92
+ defaults.each do |name, default_value|
93
+ instance_variable_set("@#{name}", (default_value.dup rescue default_value))
94
+ end
95
+ end
96
+
85
97
  iprot.read_struct_begin
86
98
  loop do
87
- fname, ftype, fid = iprot.read_field_begin
99
+ _, ftype, fid = iprot.read_field_begin
88
100
  break if (ftype == Types::STOP)
89
- handle_message(iprot, fid, ftype)
101
+ handle_message(iprot, fid, ftype, remaining_depth)
90
102
  iprot.read_field_end
91
103
  end
92
104
  iprot.read_struct_end
93
105
  validate
94
106
  end
95
107
 
96
- def write(oprot)
108
+ def write(oprot, remaining_depth = DEFAULT_RECURSION_DEPTH)
109
+ raise ProtocolException.new(ProtocolException::DEPTH_LIMIT, "Maximum recursion depth exceeded") if remaining_depth <= 0
97
110
  validate
98
111
  oprot.write_struct_begin(self.class.name)
99
112
  each_field do |fid, field_info|
@@ -103,8 +116,10 @@ module Thrift
103
116
  unless value.nil?
104
117
  if is_container? type
105
118
  oprot.write_field_begin(name, type, fid)
106
- write_container(oprot, value, field_info)
119
+ write_container(oprot, value, field_info, remaining_depth)
107
120
  oprot.write_field_end
121
+ elsif type == Types::STRUCT
122
+ oprot.write_field(field_info, fid, value, remaining_depth)
108
123
  else
109
124
  oprot.write_field(field_info, fid, value)
110
125
  end
@@ -115,10 +130,10 @@ module Thrift
115
130
  end
116
131
 
117
132
  def ==(other)
118
- return false if other.nil?
133
+ return false unless other.instance_of?(self.class)
119
134
  each_field do |fid, field_info|
120
135
  name = field_info[:name]
121
- return false unless other.respond_to?(name) && self.send(name) == other.send(name)
136
+ return false unless other.respond_to?(name) && send(name) == other.send(name)
122
137
  end
123
138
  true
124
139
  end
@@ -132,8 +147,8 @@ module Thrift
132
147
  total = 17
133
148
  each_field do |fid, field_info|
134
149
  name = field_info[:name]
135
- value = self.send(name)
136
- total = (total * 37 + value.hash) & 0xffffffff
150
+ value = send(name)
151
+ total = ((total * 37) + value.hash) & 0xffffffff
137
152
  end
138
153
  total
139
154
  end
@@ -145,7 +160,7 @@ module Thrift
145
160
  else
146
161
  each_field do |fid, field_info|
147
162
  name = field_info[:name]
148
- diffs << "#{name} differs!" unless self.instance_variable_get("@#{name}") == other.instance_variable_get("@#{name}")
163
+ diffs << "#{name} differs!" unless instance_variable_get("@#{name}") == other.instance_variable_get("@#{name}")
149
164
  end
150
165
  end
151
166
  diffs
@@ -169,14 +184,14 @@ module Thrift
169
184
 
170
185
  def self.qmark_isset_method(klass, field_info)
171
186
  klass.send :define_method, "#{field_info[:name]}?" do
172
- !self.send(field_info[:name].to_sym).nil?
187
+ !send(field_info[:name].to_sym).nil?
173
188
  end
174
189
  end
175
190
 
176
191
  def <=>(other)
177
192
  if self.class == other.class
178
193
  each_field do |fid, field_info|
179
- v1 = self.send(field_info[:name])
194
+ v1 = send(field_info[:name])
180
195
  v1_set = !v1.nil?
181
196
  v2 = other.send(field_info[:name])
182
197
  v2_set = !v2.nil?
@@ -218,17 +233,17 @@ module Thrift
218
233
  else
219
234
  # call the Struct initializer first with no args
220
235
  # this will set our field default values
221
- method(:struct_initialize).call()
236
+ method(:struct_initialize).call
222
237
  # now give it to the exception
223
- self.class.send(:class_variable_get, :'@@__thrift_struct_real_initialize').bind(self).call(*args, &block) if args.size > 0
238
+ self.class.send(:class_variable_get, :'@@__thrift_struct_real_initialize').bind_call(self, *args, &block) if args.size > 0
224
239
  # self.class.instance_method(:initialize).bind(self).call(*args, &block)
225
240
  end
226
241
  end
227
242
 
228
- def handle_message(iprot, fid, ftype)
243
+ def handle_message(iprot, fid, ftype, remaining_depth)
229
244
  field = struct_fields[fid]
230
245
  if field and field[:type] == ftype
231
- value = read_field(iprot, field)
246
+ value = read_field(iprot, field, remaining_depth)
232
247
  instance_variable_set("@#{field[:name]}", value)
233
248
  else
234
249
  iprot.skip(ftype)