thrift-mavericks 0.8.0 → 0.9.0.1

Sign up to get free protection for your applications and to get access to all the features.
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