thrift 0.8.0 → 0.13.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (99) hide show
  1. checksums.yaml +7 -0
  2. data/{README → README.md} +0 -0
  3. data/ext/binary_protocol_accelerated.c +33 -14
  4. data/ext/bytes.c +36 -0
  5. data/ext/bytes.h +31 -0
  6. data/ext/compact_protocol.c +27 -8
  7. data/ext/constants.h +8 -5
  8. data/ext/extconf.rb +5 -1
  9. data/ext/memory_buffer.c +12 -9
  10. data/ext/protocol.c +0 -185
  11. data/ext/protocol.h +0 -20
  12. data/ext/strlcpy.h +7 -3
  13. data/ext/struct.c +27 -7
  14. data/ext/thrift_native.c +16 -11
  15. data/lib/thrift.rb +10 -4
  16. data/lib/thrift/bytes.rb +131 -0
  17. data/lib/thrift/client.rb +13 -4
  18. data/lib/thrift/exceptions.rb +3 -0
  19. data/lib/thrift/multiplexed_processor.rb +76 -0
  20. data/lib/thrift/processor.rb +24 -6
  21. data/lib/thrift/protocol/base_protocol.rb +109 -12
  22. data/lib/thrift/protocol/binary_protocol.rb +22 -7
  23. data/lib/thrift/protocol/binary_protocol_accelerated.rb +8 -0
  24. data/lib/thrift/protocol/compact_protocol.rb +23 -6
  25. data/lib/thrift/protocol/json_protocol.rb +786 -0
  26. data/lib/thrift/protocol/multiplexed_protocol.rb +44 -0
  27. data/lib/thrift/protocol/protocol_decorator.rb +194 -0
  28. data/lib/thrift/server/base_server.rb +8 -2
  29. data/lib/thrift/server/mongrel_http_server.rb +2 -0
  30. data/lib/thrift/server/simple_server.rb +5 -1
  31. data/lib/thrift/server/thin_http_server.rb +91 -0
  32. data/lib/thrift/server/thread_pool_server.rb +5 -1
  33. data/lib/thrift/server/threaded_server.rb +5 -1
  34. data/lib/thrift/struct.rb +1 -1
  35. data/lib/thrift/struct_union.rb +2 -2
  36. data/lib/thrift/transport/base_server_transport.rb +1 -1
  37. data/lib/thrift/transport/base_transport.rb +30 -20
  38. data/lib/thrift/transport/buffered_transport.rb +25 -11
  39. data/lib/thrift/transport/framed_transport.rb +20 -11
  40. data/lib/thrift/transport/http_client_transport.rb +16 -6
  41. data/lib/thrift/transport/io_stream_transport.rb +5 -2
  42. data/lib/thrift/transport/memory_buffer_transport.rb +10 -6
  43. data/lib/thrift/transport/server_socket.rb +6 -1
  44. data/lib/thrift/transport/socket.rb +23 -17
  45. data/lib/thrift/transport/ssl_server_socket.rb +41 -0
  46. data/lib/thrift/transport/ssl_socket.rb +51 -0
  47. data/lib/thrift/transport/unix_server_socket.rb +5 -1
  48. data/lib/thrift/transport/unix_socket.rb +5 -1
  49. data/lib/thrift/union.rb +3 -6
  50. data/spec/BaseService.thrift +27 -0
  51. data/spec/ExtendedService.thrift +25 -0
  52. data/spec/Referenced.thrift +44 -0
  53. data/spec/ThriftNamespacedSpec.thrift +53 -0
  54. data/spec/ThriftSpec.thrift +52 -1
  55. data/spec/base_protocol_spec.rb +158 -93
  56. data/spec/base_transport_spec.rb +194 -157
  57. data/spec/binary_protocol_accelerated_spec.rb +14 -14
  58. data/spec/binary_protocol_spec.rb +29 -16
  59. data/spec/binary_protocol_spec_shared.rb +148 -65
  60. data/spec/bytes_spec.rb +160 -0
  61. data/spec/client_spec.rb +45 -47
  62. data/spec/compact_protocol_spec.rb +36 -22
  63. data/spec/exception_spec.rb +79 -80
  64. data/spec/flat_spec.rb +62 -0
  65. data/spec/http_client_spec.rb +91 -16
  66. data/spec/json_protocol_spec.rb +552 -0
  67. data/spec/namespaced_spec.rb +67 -0
  68. data/spec/nonblocking_server_spec.rb +26 -28
  69. data/spec/processor_spec.rb +29 -32
  70. data/spec/serializer_spec.rb +31 -33
  71. data/spec/server_socket_spec.rb +32 -28
  72. data/spec/server_spec.rb +112 -84
  73. data/spec/socket_spec.rb +27 -20
  74. data/spec/socket_spec_shared.rb +32 -32
  75. data/spec/spec_helper.rb +17 -11
  76. data/spec/ssl_server_socket_spec.rb +34 -0
  77. data/spec/ssl_socket_spec.rb +78 -0
  78. data/spec/struct_nested_containers_spec.rb +191 -0
  79. data/spec/struct_spec.rb +159 -161
  80. data/spec/thin_http_server_spec.rb +141 -0
  81. data/spec/types_spec.rb +71 -69
  82. data/spec/union_spec.rb +97 -76
  83. data/spec/unix_socket_spec.rb +49 -41
  84. metadata +268 -188
  85. data/CHANGELOG +0 -1
  86. data/benchmark/gen-rb/benchmark_constants.rb +0 -10
  87. data/benchmark/gen-rb/benchmark_service.rb +0 -80
  88. data/benchmark/gen-rb/benchmark_types.rb +0 -9
  89. data/spec/gen-rb/nonblocking_service.rb +0 -272
  90. data/spec/gen-rb/thrift_spec_constants.rb +0 -10
  91. data/spec/gen-rb/thrift_spec_types.rb +0 -345
  92. data/spec/mongrel_http_server_spec.rb +0 -117
  93. data/test/debug_proto/gen-rb/debug_proto_test_constants.rb +0 -273
  94. data/test/debug_proto/gen-rb/debug_proto_test_types.rb +0 -760
  95. data/test/debug_proto/gen-rb/empty_service.rb +0 -24
  96. data/test/debug_proto/gen-rb/inherited.rb +0 -79
  97. data/test/debug_proto/gen-rb/reverse_order_service.rb +0 -82
  98. data/test/debug_proto/gen-rb/service_for_exception_with_a_map.rb +0 -81
  99. data/test/debug_proto/gen-rb/srv.rb +0 -330
@@ -24,8 +24,8 @@ module Thrift
24
24
 
25
25
  def initialize(transport)
26
26
  @transport = transport
27
- @wbuf = ''
28
- @rbuf = ''
27
+ @wbuf = Bytes.empty_byte_buffer
28
+ @rbuf = Bytes.empty_byte_buffer
29
29
  @index = 0
30
30
  end
31
31
 
@@ -44,12 +44,12 @@ module Thrift
44
44
 
45
45
  def read(sz)
46
46
  @index += sz
47
- ret = @rbuf.slice(@index - sz, sz) || ''
47
+ ret = @rbuf.slice(@index - sz, sz) || Bytes.empty_byte_buffer
48
48
 
49
49
  if ret.length == 0
50
50
  @rbuf = @transport.read([sz, DEFAULT_BUFFER].max)
51
51
  @index = sz
52
- ret = @rbuf.slice(0, sz) || ''
52
+ ret = @rbuf.slice(0, sz) || Bytes.empty_byte_buffer
53
53
  end
54
54
 
55
55
  ret
@@ -65,9 +65,15 @@ module Thrift
65
65
  # The read buffer has some data now, read a single byte. Using get_string_byte() avoids
66
66
  # allocating a temp string of size 1 unnecessarily.
67
67
  @index += 1
68
- return ::Thrift::TransportUtils.get_string_byte(@rbuf, @index - 1)
68
+ return Bytes.get_string_byte(@rbuf, @index - 1)
69
69
  end
70
70
 
71
+ # Reads a number of bytes from the transport into the buffer passed.
72
+ #
73
+ # buffer - The String (byte buffer) to write data to; this is assumed to have a BINARY encoding.
74
+ # size - The number of bytes to read from the transport and write to the buffer.
75
+ #
76
+ # Returns the number of bytes read.
71
77
  def read_into_buffer(buffer, size)
72
78
  i = 0
73
79
  while i < size
@@ -78,8 +84,8 @@ module Thrift
78
84
  end
79
85
 
80
86
  # The read buffer has some data now, so copy bytes over to the output buffer.
81
- byte = ::Thrift::TransportUtils.get_string_byte(@rbuf, @index)
82
- ::Thrift::TransportUtils.set_string_byte(buffer, i, byte)
87
+ byte = Bytes.get_string_byte(@rbuf, @index)
88
+ Bytes.set_string_byte(buffer, i, byte)
83
89
  @index += 1
84
90
  i += 1
85
91
  end
@@ -87,22 +93,30 @@ module Thrift
87
93
  end
88
94
 
89
95
  def write(buf)
90
- @wbuf << buf
96
+ @wbuf << Bytes.force_binary_encoding(buf)
91
97
  end
92
98
 
93
99
  def flush
94
- if @wbuf != ''
100
+ unless @wbuf.empty?
95
101
  @transport.write(@wbuf)
96
- @wbuf = ''
102
+ @wbuf = Bytes.empty_byte_buffer
97
103
  end
98
104
 
99
105
  @transport.flush
100
106
  end
107
+
108
+ def to_s
109
+ "buffered(#{@transport.to_s})"
110
+ end
101
111
  end
102
112
 
103
113
  class BufferedTransportFactory < BaseTransportFactory
104
114
  def get_transport(transport)
105
115
  return BufferedTransport.new(transport)
106
116
  end
117
+
118
+ def to_s
119
+ "buffered"
120
+ end
107
121
  end
108
- end
122
+ end
@@ -22,8 +22,8 @@ module Thrift
22
22
  class FramedTransport < BaseTransport
23
23
  def initialize(transport, read=true, write=true)
24
24
  @transport = transport
25
- @rbuf = ''
26
- @wbuf = ''
25
+ @rbuf = Bytes.empty_byte_buffer
26
+ @wbuf = Bytes.empty_byte_buffer
27
27
  @read = read
28
28
  @write = write
29
29
  @index = 0
@@ -44,12 +44,12 @@ module Thrift
44
44
  def read(sz)
45
45
  return @transport.read(sz) unless @read
46
46
 
47
- return '' if sz <= 0
47
+ return Bytes.empty_byte_buffer if sz <= 0
48
48
 
49
49
  read_frame if @index >= @rbuf.length
50
50
 
51
51
  @index += sz
52
- @rbuf.slice(@index - sz, sz) || ''
52
+ @rbuf.slice(@index - sz, sz) || Bytes.empty_byte_buffer
53
53
  end
54
54
 
55
55
  def read_byte
@@ -60,7 +60,7 @@ module Thrift
60
60
  # The read buffer has some data now, read a single byte. Using get_string_byte() avoids
61
61
  # allocating a temp string of size 1 unnecessarily.
62
62
  @index += 1
63
- return ::Thrift::TransportUtils.get_string_byte(@rbuf, @index - 1)
63
+ return Bytes.get_string_byte(@rbuf, @index - 1)
64
64
  end
65
65
 
66
66
  def read_into_buffer(buffer, size)
@@ -69,18 +69,18 @@ module Thrift
69
69
  read_frame if @index >= @rbuf.length
70
70
 
71
71
  # The read buffer has some data now, so copy bytes over to the output buffer.
72
- byte = ::Thrift::TransportUtils.get_string_byte(@rbuf, @index)
73
- ::Thrift::TransportUtils.set_string_byte(buffer, i, byte)
72
+ byte = Bytes.get_string_byte(@rbuf, @index)
73
+ Bytes.set_string_byte(buffer, i, byte)
74
74
  @index += 1
75
75
  i += 1
76
76
  end
77
77
  i
78
78
  end
79
79
 
80
-
81
- def write(buf,sz=nil)
80
+ def write(buf, sz=nil)
82
81
  return @transport.write(buf) unless @write
83
82
 
83
+ buf = Bytes.force_binary_encoding(buf)
84
84
  @wbuf << (sz ? buf[0...sz] : buf)
85
85
  end
86
86
 
@@ -92,10 +92,15 @@ module Thrift
92
92
  return @transport.flush unless @write
93
93
 
94
94
  out = [@wbuf.length].pack('N')
95
+ # Array#pack should return a BINARY encoded String, so it shouldn't be necessary to force encoding
95
96
  out << @wbuf
96
97
  @transport.write(out)
97
98
  @transport.flush
98
- @wbuf = ''
99
+ @wbuf = Bytes.empty_byte_buffer
100
+ end
101
+
102
+ def to_s
103
+ "framed(#{@transport.to_s})"
99
104
  end
100
105
 
101
106
  private
@@ -112,5 +117,9 @@ module Thrift
112
117
  def get_transport(transport)
113
118
  return FramedTransport.new(transport)
114
119
  end
120
+
121
+ def to_s
122
+ "framed"
123
+ end
115
124
  end
116
- end
125
+ end
@@ -20,21 +20,23 @@
20
20
 
21
21
  require 'net/http'
22
22
  require 'net/https'
23
+ require 'openssl'
23
24
  require 'uri'
24
25
  require 'stringio'
25
26
 
26
27
  module Thrift
27
28
  class HTTPClientTransport < BaseTransport
28
29
 
29
- def initialize(url)
30
+ def initialize(url, opts = {})
30
31
  @url = URI url
31
32
  @headers = {'Content-Type' => 'application/x-thrift'}
32
- @outbuf = ""
33
+ @outbuf = Bytes.empty_byte_buffer
34
+ @ssl_verify_mode = opts.fetch(:ssl_verify_mode, OpenSSL::SSL::VERIFY_PEER)
33
35
  end
34
36
 
35
37
  def open?; true end
36
38
  def read(sz); @inbuf.read sz end
37
- def write(buf); @outbuf << buf end
39
+ def write(buf); @outbuf << Bytes.force_binary_encoding(buf) end
38
40
 
39
41
  def add_headers(headers)
40
42
  @headers = @headers.merge(headers)
@@ -42,10 +44,18 @@ module Thrift
42
44
 
43
45
  def flush
44
46
  http = Net::HTTP.new @url.host, @url.port
45
- http.use_ssl = @url.scheme == "https"
46
- resp, data = http.post(@url.request_uri, @outbuf, @headers)
47
+ http.use_ssl = @url.scheme == 'https'
48
+ http.verify_mode = @ssl_verify_mode if @url.scheme == 'https'
49
+ resp = http.post(@url.request_uri, @outbuf, @headers)
50
+ data = resp.body
51
+ data = Bytes.force_binary_encoding(data)
47
52
  @inbuf = StringIO.new data
48
- @outbuf = ""
53
+ ensure
54
+ @outbuf = Bytes.empty_byte_buffer
55
+ end
56
+
57
+ def to_s
58
+ "@{self.url}"
49
59
  end
50
60
  end
51
61
  end
@@ -32,8 +32,11 @@ module Thrift
32
32
 
33
33
  def open?; not @input.closed? or not @output.closed? end
34
34
  def read(sz); @input.read(sz) end
35
- def write(buf); @output.write(buf) end
35
+ def write(buf); @output.write(Bytes.force_binary_encoding(buf)) end
36
36
  def close; @input.close; @output.close end
37
37
  def to_io; @input end # we're assuming this is used in a IO.select for reading
38
+ def to_s
39
+ "iostream(input=#{@input.to_s},output=#{@output.to_s})"
40
+ end
38
41
  end
39
- end
42
+ end
@@ -28,7 +28,7 @@ module Thrift
28
28
  # this behavior is no longer required. If you wish to change it
29
29
  # go ahead, just make sure the specs pass
30
30
  def initialize(buffer = nil)
31
- @buf = buffer || ''
31
+ @buf = buffer ? Bytes.force_binary_encoding(buffer) : Bytes.empty_byte_buffer
32
32
  @index = 0
33
33
  end
34
34
 
@@ -48,7 +48,7 @@ module Thrift
48
48
 
49
49
  # this method does not use the passed object directly but copies it
50
50
  def reset_buffer(new_buf = '')
51
- @buf.replace new_buf
51
+ @buf.replace Bytes.force_binary_encoding(new_buf)
52
52
  @index = 0
53
53
  end
54
54
 
@@ -72,7 +72,7 @@ module Thrift
72
72
 
73
73
  def read_byte
74
74
  raise EOFError.new("Not enough bytes remain in buffer") if @index >= @buf.size
75
- val = ::Thrift::TransportUtils.get_string_byte(@buf, @index)
75
+ val = Bytes.get_string_byte(@buf, @index)
76
76
  @index += 1
77
77
  if @index >= GARBAGE_BUFFER_SIZE
78
78
  @buf = @buf.slice(@index..-1)
@@ -87,8 +87,8 @@ module Thrift
87
87
  raise EOFError.new("Not enough bytes remain in buffer") if @index >= @buf.size
88
88
 
89
89
  # The read buffer has some data now, so copy bytes over to the output buffer.
90
- byte = ::Thrift::TransportUtils.get_string_byte(@buf, @index)
91
- ::Thrift::TransportUtils.set_string_byte(buffer, i, byte)
90
+ byte = Bytes.get_string_byte(@buf, @index)
91
+ Bytes.set_string_byte(buffer, i, byte)
92
92
  @index += 1
93
93
  i += 1
94
94
  end
@@ -100,7 +100,7 @@ module Thrift
100
100
  end
101
101
 
102
102
  def write(wbuf)
103
- @buf << wbuf
103
+ @buf << Bytes.force_binary_encoding(wbuf)
104
104
  end
105
105
 
106
106
  def flush
@@ -121,5 +121,9 @@ module Thrift
121
121
  end
122
122
  out.join(" ")
123
123
  end
124
+
125
+ def to_s
126
+ "memory"
127
+ end
124
128
  end
125
129
  end
@@ -59,5 +59,10 @@ module Thrift
59
59
  end
60
60
 
61
61
  alias to_io handle
62
+
63
+ def to_s
64
+ "socket(#{@host}:#{@port})"
65
+ end
66
+
62
67
  end
63
- end
68
+ end
@@ -33,25 +33,28 @@ module Thrift
33
33
  attr_accessor :handle, :timeout
34
34
 
35
35
  def open
36
- begin
37
- addrinfo = ::Socket::getaddrinfo(@host, @port).first
38
- @handle = ::Socket.new(addrinfo[4], ::Socket::SOCK_STREAM, 0)
39
- sockaddr = ::Socket.sockaddr_in(addrinfo[1], addrinfo[3])
36
+ for addrinfo in ::Socket::getaddrinfo(@host, @port, nil, ::Socket::SOCK_STREAM) do
40
37
  begin
41
- @handle.connect_nonblock(sockaddr)
42
- rescue Errno::EINPROGRESS
43
- unless IO.select(nil, [ @handle ], nil, @timeout)
44
- raise TransportException.new(TransportException::NOT_OPEN, "Connection timeout to #{@desc}")
45
- end
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])
46
41
  begin
47
- @handle.connect_nonblock(sockaddr)
48
- rescue Errno::EISCONN
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
49
51
  end
52
+ return @handle = socket
53
+ rescue StandardError => e
54
+ next
50
55
  end
51
- @handle
52
- rescue StandardError => e
53
- raise TransportException.new(TransportException::NOT_OPEN, "Could not connect to #{@desc}: #{e}")
54
56
  end
57
+ raise TransportException.new(TransportException::NOT_OPEN, "Could not connect to #{@desc}: #{e}")
55
58
  end
56
59
 
57
60
  def open?
@@ -60,6 +63,7 @@ module Thrift
60
63
 
61
64
  def write(str)
62
65
  raise IOError, "closed stream" unless open?
66
+ str = Bytes.force_binary_encoding(str)
63
67
  begin
64
68
  if @timeout.nil? or @timeout == 0
65
69
  @handle.write(str)
@@ -130,8 +134,10 @@ module Thrift
130
134
  @handle = nil
131
135
  end
132
136
 
133
- def to_io
134
- @handle
137
+ alias to_io handle
138
+
139
+ def to_s
140
+ "socket(#{@host}:#{@port})"
135
141
  end
136
142
  end
137
- end
143
+ end
@@ -0,0 +1,41 @@
1
+ # encoding: ascii-8bit
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 'socket'
22
+
23
+ module Thrift
24
+ class SSLServerSocket < ServerSocket
25
+ def initialize(host_or_port, port = nil, ssl_context = nil)
26
+ super(host_or_port, port)
27
+ @ssl_context = ssl_context
28
+ end
29
+
30
+ attr_accessor :ssl_context
31
+
32
+ def listen
33
+ socket = TCPServer.new(@host, @port)
34
+ @handle = OpenSSL::SSL::SSLServer.new(socket, @ssl_context)
35
+ end
36
+
37
+ def to_s
38
+ "ssl(#{super.to_s})"
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,51 @@
1
+ # encoding: ascii-8bit
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
+ module Thrift
21
+ class SSLSocket < Socket
22
+ def initialize(host='localhost', port=9090, timeout=nil, ssl_context=nil)
23
+ super(host, port, timeout)
24
+ @ssl_context = ssl_context
25
+ end
26
+
27
+ attr_accessor :ssl_context
28
+
29
+ def open
30
+ socket = super
31
+ @handle = OpenSSL::SSL::SSLSocket.new(socket, @ssl_context)
32
+ begin
33
+ @handle.connect_nonblock
34
+ @handle.post_connection_check(@host)
35
+ @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}")
44
+ end
45
+ end
46
+
47
+ def to_s
48
+ "ssl(#{super.to_s})"
49
+ end
50
+ end
51
+ end