thrift-mavericks 0.8.0 → 0.9.0.1

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 (59) hide show
  1. checksums.yaml +8 -8
  2. data/ext/binary_protocol_accelerated.c +21 -2
  3. data/ext/bytes.c +36 -0
  4. data/ext/bytes.h +31 -0
  5. data/ext/compact_protocol.c +24 -7
  6. data/ext/constants.h +5 -5
  7. data/ext/extconf.rb +3 -1
  8. data/ext/memory_buffer.c +11 -8
  9. data/ext/protocol.c +0 -185
  10. data/ext/protocol.h +0 -20
  11. data/ext/struct.c +0 -3
  12. data/ext/thrift_native.c +10 -11
  13. data/lib/thrift.rb +3 -0
  14. data/lib/thrift/bytes.rb +131 -0
  15. data/lib/thrift/exceptions.rb +3 -0
  16. data/lib/thrift/protocol/base_protocol.rb +96 -9
  17. data/lib/thrift/protocol/binary_protocol.rb +15 -7
  18. data/lib/thrift/protocol/compact_protocol.rb +14 -6
  19. data/lib/thrift/protocol/json_protocol.rb +766 -0
  20. data/lib/thrift/server/mongrel_http_server.rb +2 -0
  21. data/lib/thrift/server/thin_http_server.rb +91 -0
  22. data/lib/thrift/struct.rb +1 -1
  23. data/lib/thrift/struct_union.rb +2 -2
  24. data/lib/thrift/transport/base_transport.rb +22 -20
  25. data/lib/thrift/transport/buffered_transport.rb +16 -10
  26. data/lib/thrift/transport/framed_transport.rb +11 -10
  27. data/lib/thrift/transport/http_client_transport.rb +11 -6
  28. data/lib/thrift/transport/io_stream_transport.rb +1 -1
  29. data/lib/thrift/transport/memory_buffer_transport.rb +6 -6
  30. data/lib/thrift/transport/socket.rb +4 -2
  31. data/spec/ThriftSpec.thrift +52 -1
  32. data/spec/base_protocol_spec.rb +108 -51
  33. data/spec/base_transport_spec.rb +49 -50
  34. data/spec/binary_protocol_accelerated_spec.rb +9 -13
  35. data/spec/binary_protocol_spec.rb +15 -10
  36. data/spec/binary_protocol_spec_shared.rb +92 -12
  37. data/spec/bytes_spec.rb +160 -0
  38. data/spec/client_spec.rb +13 -14
  39. data/spec/compact_protocol_spec.rb +4 -5
  40. data/spec/exception_spec.rb +39 -40
  41. data/spec/gen-rb/thrift_spec_types.rb +192 -0
  42. data/spec/http_client_spec.rb +65 -9
  43. data/spec/json_protocol_spec.rb +513 -0
  44. data/spec/nonblocking_server_spec.rb +18 -20
  45. data/spec/processor_spec.rb +13 -16
  46. data/spec/serializer_spec.rb +17 -19
  47. data/spec/server_socket_spec.rb +6 -7
  48. data/spec/server_spec.rb +46 -58
  49. data/spec/socket_spec.rb +11 -11
  50. data/spec/socket_spec_shared.rb +1 -1
  51. data/spec/spec_helper.rb +13 -10
  52. data/spec/struct_nested_containers_spec.rb +191 -0
  53. data/spec/struct_spec.rb +84 -86
  54. data/spec/thin_http_server_spec.rb +140 -0
  55. data/spec/types_spec.rb +65 -66
  56. data/spec/union_spec.rb +57 -47
  57. data/spec/unix_socket_spec.rb +8 -9
  58. metadata +72 -14
  59. data/spec/mongrel_http_server_spec.rb +0 -117
@@ -20,6 +20,7 @@
20
20
  require 'mongrel'
21
21
 
22
22
  ## Sticks a service on a URL, using mongrel to do the HTTP work
23
+ # <b>DEPRECATED:</b> Please use <tt>Thrift::ThinHTTPServer</tt> instead.
23
24
  module Thrift
24
25
  class MongrelHTTPServer < BaseServer
25
26
  class Handler < Mongrel::HttpHandler
@@ -43,6 +44,7 @@ module Thrift
43
44
  end
44
45
 
45
46
  def initialize(processor, opts={})
47
+ Kernel.warn "[DEPRECATION WARNING] `Thrift::MongrelHTTPServer` is deprecated. Please use `Thrift::ThinHTTPServer` instead."
46
48
  port = opts[:port] || 80
47
49
  ip = opts[:ip] || "0.0.0.0"
48
50
  path = opts[:path] || ""
@@ -0,0 +1,91 @@
1
+ #
2
+ # Licensed to the Apache Software Foundation (ASF) under one
3
+ # or more contributor license agreements. See the NOTICE file
4
+ # distributed with this work for additional information
5
+ # regarding copyright ownership. The ASF licenses this file
6
+ # to you under the Apache License, Version 2.0 (the
7
+ # "License"); you may not use this file except in compliance
8
+ # with the License. You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing,
13
+ # software distributed under the License is distributed on an
14
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15
+ # KIND, either express or implied. See the License for the
16
+ # specific language governing permissions and limitations
17
+ # under the License.
18
+ #
19
+
20
+ require 'rack'
21
+ require 'thin'
22
+
23
+ ##
24
+ # Wraps the Thin web server to provide a Thrift server over HTTP.
25
+ module Thrift
26
+ class ThinHTTPServer < BaseServer
27
+
28
+ ##
29
+ # Accepts a Thrift::Processor
30
+ # Options include:
31
+ # * :port
32
+ # * :ip
33
+ # * :path
34
+ # * :protocol_factory
35
+ def initialize(processor, options={})
36
+ port = options[:port] || 80
37
+ ip = options[:ip] || "0.0.0.0"
38
+ path = options[:path] || "/"
39
+ protocol_factory = options[:protocol_factory] || BinaryProtocolFactory.new
40
+ app = RackApplication.for(path, processor, protocol_factory)
41
+ @server = Thin::Server.new(ip, port, app)
42
+ end
43
+
44
+ ##
45
+ # Starts the server
46
+ def serve
47
+ @server.start
48
+ end
49
+
50
+ class RackApplication
51
+
52
+ THRIFT_HEADER = "application/x-thrift"
53
+
54
+ def self.for(path, processor, protocol_factory)
55
+ Rack::Builder.new do
56
+ use Rack::CommonLogger
57
+ use Rack::ShowExceptions
58
+ use Rack::Lint
59
+ map path do
60
+ run lambda { |env|
61
+ request = Rack::Request.new(env)
62
+ if RackApplication.valid_thrift_request?(request)
63
+ RackApplication.successful_request(request, processor, protocol_factory)
64
+ else
65
+ RackApplication.failed_request
66
+ end
67
+ }
68
+ end
69
+ end
70
+ end
71
+
72
+ def self.successful_request(rack_request, processor, protocol_factory)
73
+ response = Rack::Response.new([], 200, {'Content-Type' => THRIFT_HEADER})
74
+ transport = IOStreamTransport.new rack_request.body, response
75
+ protocol = protocol_factory.get_protocol transport
76
+ processor.process protocol, protocol
77
+ response
78
+ end
79
+
80
+ def self.failed_request
81
+ Rack::Response.new(['Not Found'], 404, {'Content-Type' => THRIFT_HEADER})
82
+ end
83
+
84
+ def self.valid_thrift_request?(rack_request)
85
+ rack_request.post? && rack_request.env["CONTENT_TYPE"] == THRIFT_HEADER
86
+ end
87
+
88
+ end
89
+
90
+ end
91
+ end
data/lib/thrift/struct.rb CHANGED
@@ -105,7 +105,7 @@ module Thrift
105
105
  write_container(oprot, value, field_info)
106
106
  oprot.write_field_end
107
107
  else
108
- oprot.write_field(name, type, fid, value)
108
+ oprot.write_field(field_info, fid, value)
109
109
  end
110
110
  end
111
111
  end
@@ -101,7 +101,7 @@ module Thrift
101
101
  end
102
102
  iprot.read_set_end
103
103
  else
104
- value = iprot.read_type(field[:type])
104
+ value = iprot.read_type(field)
105
105
  end
106
106
  value
107
107
  end
@@ -110,7 +110,7 @@ module Thrift
110
110
  if is_container? field[:type]
111
111
  write_container(oprot, value, field)
112
112
  else
113
- oprot.write_type(field[:type], value)
113
+ oprot.write_type(field, value)
114
114
  end
115
115
  end
116
116
 
@@ -35,22 +35,14 @@ module Thrift
35
35
  end
36
36
 
37
37
  module TransportUtils
38
- if RUBY_VERSION >= '1.9'
39
- def self.get_string_byte(string, index)
40
- string.getbyte(index)
41
- end
42
-
43
- def self.set_string_byte(string, index, byte)
44
- string.setbyte(index, byte)
45
- end
46
- else
47
- def self.get_string_byte(string, index)
48
- string[index]
49
- end
38
+ # Deprecated: Use Thrift::Bytes instead
39
+ def self.get_string_byte(string, index)
40
+ Bytes.get_string_byte(string, index)
41
+ end
50
42
 
51
- def self.set_string_byte(string, index, byte)
52
- string[index] = byte
53
- end
43
+ # Deprecated: Use Thrift::Bytes instead
44
+ def self.set_string_byte(string, index, byte)
45
+ Bytes.set_string_byte(string, index, byte)
54
46
  end
55
47
  end
56
48
 
@@ -61,6 +53,11 @@ module Thrift
61
53
 
62
54
  def close; end
63
55
 
56
+ # Reads a number of bytes from the transports. In Ruby 1.9+, the String returned will have a BINARY (aka ASCII8BIT) encoding.
57
+ #
58
+ # sz - The number of bytes to read from the transport.
59
+ #
60
+ # Returns a String acting as a byte buffer.
64
61
  def read(sz)
65
62
  raise NotImplementedError
66
63
  end
@@ -68,7 +65,7 @@ module Thrift
68
65
  # Returns an unsigned byte as a Fixnum in the range (0..255).
69
66
  def read_byte
70
67
  buf = read_all(1)
71
- return ::Thrift::TransportUtils.get_string_byte(buf, 0)
68
+ return Bytes.get_string_byte(buf, 0)
72
69
  end
73
70
 
74
71
  # Reads size bytes and copies them into buffer[0..size].
@@ -76,14 +73,14 @@ module Thrift
76
73
  tmp = read_all(size)
77
74
  i = 0
78
75
  tmp.each_byte do |byte|
79
- ::Thrift::TransportUtils.set_string_byte(buffer, i, byte)
76
+ Bytes.set_string_byte(buffer, i, byte)
80
77
  i += 1
81
78
  end
82
79
  i
83
80
  end
84
81
 
85
82
  def read_all(size)
86
- return '' if size <= 0
83
+ return Bytes.empty_byte_buffer if size <= 0
87
84
  buf = read(size)
88
85
  while (buf.length < size)
89
86
  chunk = read(size - buf.length)
@@ -92,7 +89,12 @@ module Thrift
92
89
 
93
90
  buf
94
91
  end
95
-
92
+
93
+ # Writes the byte buffer to the transport. In Ruby 1.9+, the buffer will be forced into BINARY encoding.
94
+ #
95
+ # buf - A String acting as a byte buffer.
96
+ #
97
+ # Returns nothing.
96
98
  def write(buf); end
97
99
  alias_method :<<, :write
98
100
 
@@ -104,4 +106,4 @@ module Thrift
104
106
  return trans
105
107
  end
106
108
  end
107
- end
109
+ end
@@ -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,13 +93,13 @@ 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
@@ -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,11 @@ 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
99
100
  end
100
101
 
101
102
  private
@@ -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,13 @@ 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
+ @outbuf = Bytes.empty_byte_buffer
49
54
  end
50
55
  end
51
56
  end
@@ -32,7 +32,7 @@ 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
38
  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