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
data/ext/protocol.h CHANGED
@@ -1,20 +0,0 @@
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
- void Init_protocol();
data/ext/struct.c CHANGED
@@ -627,9 +627,6 @@ static VALUE rb_thrift_union_read(VALUE self, VALUE protocol) {
627
627
  rb_raise(rb_eRuntimeError, "too many fields in union!");
628
628
  }
629
629
 
630
- // read field end
631
- default_read_field_end(protocol);
632
-
633
630
  // read struct end
634
631
  default_read_struct_end(protocol);
635
632
 
data/ext/thrift_native.c CHANGED
@@ -18,15 +18,16 @@
18
18
  */
19
19
 
20
20
  #include <ruby.h>
21
+ #include <bytes.h>
21
22
  #include <struct.h>
22
23
  #include <binary_protocol_accelerated.h>
23
24
  #include <compact_protocol.h>
24
- #include <protocol.h>
25
25
  #include <memory_buffer.h>
26
26
 
27
27
  // cached classes/modules
28
28
  VALUE rb_cSet;
29
29
  VALUE thrift_module;
30
+ VALUE thrift_bytes_module;
30
31
  VALUE thrift_types_module;
31
32
 
32
33
  // TType constants
@@ -62,7 +63,6 @@ ID write_list_begin_method_id;
62
63
  ID write_list_end_method_id;
63
64
  ID write_set_begin_method_id;
64
65
  ID write_set_end_method_id;
65
- ID size_method_id;
66
66
  ID read_bool_method_id;
67
67
  ID read_byte_method_id;
68
68
  ID read_i16_method_id;
@@ -81,15 +81,15 @@ ID read_struct_end_method_id;
81
81
  ID read_field_begin_method_id;
82
82
  ID read_field_end_method_id;
83
83
  ID keys_method_id;
84
- ID entries_method_id;
85
- ID name_method_id;
86
- ID sort_method_id;
84
+ ID entries_method_id;
87
85
  ID write_field_stop_method_id;
88
86
  ID skip_method_id;
89
87
  ID write_method_id;
90
88
  ID read_all_method_id;
91
89
  ID read_into_buffer_method_id;
92
- ID native_qmark_method_id;
90
+ ID force_binary_encoding_id;
91
+ ID convert_to_utf8_byte_buffer_id;
92
+ ID convert_to_string_id;
93
93
 
94
94
  // constant ids
95
95
  ID fields_const_id;
@@ -109,6 +109,7 @@ VALUE protocol_exception_class;
109
109
  void Init_thrift_native() {
110
110
  // cached classes
111
111
  thrift_module = rb_const_get(rb_cObject, rb_intern("Thrift"));
112
+ thrift_bytes_module = rb_const_get(thrift_module, rb_intern("Bytes"));
112
113
  thrift_types_module = rb_const_get(thrift_module, rb_intern("Types"));
113
114
  rb_cSet = rb_const_get(rb_cObject, rb_intern("Set"));
114
115
  protocol_exception_class = rb_const_get(thrift_module, rb_intern("ProtocolException"));
@@ -145,7 +146,6 @@ void Init_thrift_native() {
145
146
  write_list_end_method_id = rb_intern("write_list_end");
146
147
  write_set_begin_method_id = rb_intern("write_set_begin");
147
148
  write_set_end_method_id = rb_intern("write_set_end");
148
- size_method_id = rb_intern("size");
149
149
  read_bool_method_id = rb_intern("read_bool");
150
150
  read_byte_method_id = rb_intern("read_byte");
151
151
  read_i16_method_id = rb_intern("read_i16");
@@ -165,14 +165,14 @@ void Init_thrift_native() {
165
165
  read_field_end_method_id = rb_intern("read_field_end");
166
166
  keys_method_id = rb_intern("keys");
167
167
  entries_method_id = rb_intern("entries");
168
- name_method_id = rb_intern("name");
169
- sort_method_id = rb_intern("sort");
170
168
  write_field_stop_method_id = rb_intern("write_field_stop");
171
169
  skip_method_id = rb_intern("skip");
172
170
  write_method_id = rb_intern("write");
173
171
  read_all_method_id = rb_intern("read_all");
174
172
  read_into_buffer_method_id = rb_intern("read_into_buffer");
175
- native_qmark_method_id = rb_intern("native?");
173
+ force_binary_encoding_id = rb_intern("force_binary_encoding");
174
+ convert_to_utf8_byte_buffer_id = rb_intern("convert_to_utf8_byte_buffer");
175
+ convert_to_string_id = rb_intern("convert_to_string");
176
176
 
177
177
  // constant ids
178
178
  fields_const_id = rb_intern("FIELDS");
@@ -188,7 +188,6 @@ void Init_thrift_native() {
188
188
  element_sym = ID2SYM(rb_intern("element"));
189
189
  class_sym = ID2SYM(rb_intern("class"));
190
190
 
191
- Init_protocol();
192
191
  Init_struct();
193
192
  Init_binary_protocol_accelerated();
194
193
  Init_compact_protocol();
data/lib/thrift.rb CHANGED
@@ -22,6 +22,7 @@
22
22
 
23
23
  $:.unshift File.dirname(__FILE__)
24
24
 
25
+ require 'thrift/bytes'
25
26
  require 'thrift/core_ext'
26
27
  require 'thrift/exceptions'
27
28
  require 'thrift/types'
@@ -40,6 +41,7 @@ require 'thrift/protocol/base_protocol'
40
41
  require 'thrift/protocol/binary_protocol'
41
42
  require 'thrift/protocol/binary_protocol_accelerated'
42
43
  require 'thrift/protocol/compact_protocol'
44
+ require 'thrift/protocol/json_protocol'
43
45
 
44
46
  # transport
45
47
  require 'thrift/transport/base_transport'
@@ -60,5 +62,6 @@ require 'thrift/server/nonblocking_server'
60
62
  require 'thrift/server/simple_server'
61
63
  require 'thrift/server/threaded_server'
62
64
  require 'thrift/server/thread_pool_server'
65
+ require 'thrift/server/thin_http_server'
63
66
 
64
67
  require 'thrift/thrift_native'
@@ -0,0 +1,131 @@
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
+ module Thrift
22
+ # A collection of utilities for working with bytes and byte buffers.
23
+ module Bytes
24
+ if RUBY_VERSION >= '1.9'
25
+ # Creates and empty byte buffer (String with BINARY encoding)
26
+ #
27
+ # size - The Integer size of the buffer (default: nil) to create
28
+ #
29
+ # Returns a String with BINARY encoding, filled with null characters
30
+ # if size is greater than zero
31
+ def self.empty_byte_buffer(size = nil)
32
+ if (size && size > 0)
33
+ "\0".force_encoding(Encoding::BINARY) * size
34
+ else
35
+ ''.force_encoding(Encoding::BINARY)
36
+ end
37
+ end
38
+
39
+ # Forces the encoding of the buffer to BINARY. If the buffer
40
+ # passed is frozen, then it will be duplicated.
41
+ #
42
+ # buffer - The String to force the encoding of.
43
+ #
44
+ # Returns the String passed with an encoding of BINARY; returned
45
+ # String may be a duplicate.
46
+ def self.force_binary_encoding(buffer)
47
+ buffer = buffer.dup if buffer.frozen?
48
+ buffer.force_encoding(Encoding::BINARY)
49
+ end
50
+
51
+ # Gets the byte value of a given position in a String.
52
+ #
53
+ # string - The String to retrive the byte value from.
54
+ # index - The Integer location of the byte value to retrieve.
55
+ #
56
+ # Returns an Integer value between 0 and 255.
57
+ def self.get_string_byte(string, index)
58
+ string.getbyte(index)
59
+ end
60
+
61
+ # Sets the byte value given to a given index in a String.
62
+ #
63
+ # string - The String to set the byte value in.
64
+ # index - The Integer location to set the byte value at.
65
+ # byte - The Integer value (0 to 255) to set in the string.
66
+ #
67
+ # Returns an Integer value of the byte value to set.
68
+ def self.set_string_byte(string, index, byte)
69
+ string.setbyte(index, byte)
70
+ end
71
+
72
+ # Converts the given String to a UTF-8 byte buffer.
73
+ #
74
+ # string - The String to convert.
75
+ #
76
+ # Returns a new String with BINARY encoding, containing the UTF-8
77
+ # bytes of the original string.
78
+ def self.convert_to_utf8_byte_buffer(string)
79
+ if string.encoding != Encoding::UTF_8
80
+ # transcode to UTF-8
81
+ string = string.encode(Encoding::UTF_8)
82
+ else
83
+ # encoding is already UTF-8, but a duplicate is needed
84
+ string = string.dup
85
+ end
86
+ string.force_encoding(Encoding::BINARY)
87
+ end
88
+
89
+ # Converts the given UTF-8 byte buffer into a String
90
+ #
91
+ # utf8_buffer - A String, with BINARY encoding, containing UTF-8 bytes
92
+ #
93
+ # Returns a new String with UTF-8 encoding,
94
+ def self.convert_to_string(utf8_buffer)
95
+ # duplicate the buffer, force encoding to UTF-8
96
+ utf8_buffer.dup.force_encoding(Encoding::UTF_8)
97
+ end
98
+ else
99
+ def self.empty_byte_buffer(size = nil)
100
+ if (size && size > 0)
101
+ "\0" * size
102
+ else
103
+ ''
104
+ end
105
+ end
106
+
107
+ def self.force_binary_encoding(buffer)
108
+ buffer
109
+ end
110
+
111
+ def self.get_string_byte(string, index)
112
+ string[index]
113
+ end
114
+
115
+ def self.set_string_byte(string, index, byte)
116
+ string[index] = byte
117
+ end
118
+
119
+ def self.convert_to_utf8_byte_buffer(string)
120
+ # This assumes $KCODE is 'UTF8'/'U', which would mean the String is already a UTF-8 byte buffer
121
+ # TODO consider handling other $KCODE values and transcoding with iconv
122
+ string
123
+ end
124
+
125
+ def self.convert_to_string(utf8_buffer)
126
+ # See comment in 'convert_to_utf8_byte_buffer' for relevant assumptions.
127
+ utf8_buffer
128
+ end
129
+ end
130
+ end
131
+ end
@@ -37,6 +37,9 @@ module Thrift
37
37
  MISSING_RESULT = 5
38
38
  INTERNAL_ERROR = 6
39
39
  PROTOCOL_ERROR = 7
40
+ INVALID_TRANSFORM = 8
41
+ INVALID_PROTOCOL = 9
42
+ UNSUPPORTED_CLIENT_TYPE = 10
40
43
 
41
44
  attr_reader :type
42
45
 
@@ -114,10 +114,27 @@ module Thrift
114
114
  raise NotImplementedError
115
115
  end
116
116
 
117
+ # Writes a Thrift String. In Ruby 1.9+, the String passed will be transcoded to UTF-8.
118
+ #
119
+ # str - The String to write.
120
+ #
121
+ # Raises EncodingError if the transcoding to UTF-8 fails.
122
+ #
123
+ # Returns nothing.
117
124
  def write_string(str)
118
125
  raise NotImplementedError
119
126
  end
120
127
 
128
+ # Writes a Thrift Binary (Thrift String with no encoding). In Ruby 1.9+, the String passed
129
+ # will forced into BINARY encoding.
130
+ #
131
+ # buf - The String to write.
132
+ #
133
+ # Returns nothing.
134
+ def write_binary(buf)
135
+ raise NotImplementedError
136
+ end
137
+
121
138
  def read_message_begin
122
139
  raise NotImplementedError
123
140
  end
@@ -178,18 +195,67 @@ module Thrift
178
195
  raise NotImplementedError
179
196
  end
180
197
 
198
+ # Reads a Thrift String. In Ruby 1.9+, all Strings will be returned with an Encoding of UTF-8.
199
+ #
200
+ # Returns a String.
181
201
  def read_string
182
202
  raise NotImplementedError
183
203
  end
184
204
 
185
- def write_field(name, type, fid, value)
186
- write_field_begin(name, type, fid)
187
- write_type(type, value)
205
+ # Reads a Thrift Binary (Thrift String without encoding). In Ruby 1.9+, all Strings will be returned
206
+ # with an Encoding of BINARY.
207
+ #
208
+ # Returns a String.
209
+ def read_binary
210
+ raise NotImplementedError
211
+ end
212
+
213
+ # Writes a field based on the field information, field ID and value.
214
+ #
215
+ # field_info - A Hash containing the definition of the field:
216
+ # :name - The name of the field.
217
+ # :type - The type of the field, which must be a Thrift::Types constant.
218
+ # :binary - A Boolean flag that indicates if Thrift::Types::STRING is a binary string (string without encoding).
219
+ # fid - The ID of the field.
220
+ # value - The field's value to write; object type varies based on :type.
221
+ #
222
+ # Returns nothing.
223
+ def write_field(*args)
224
+ if args.size == 3
225
+ # handles the documented method signature - write_field(field_info, fid, value)
226
+ field_info = args[0]
227
+ fid = args[1]
228
+ value = args[2]
229
+ elsif args.size == 4
230
+ # handles the deprecated method signature - write_field(name, type, fid, value)
231
+ field_info = {:name => args[0], :type => args[1]}
232
+ fid = args[2]
233
+ value = args[3]
234
+ else
235
+ raise ArgumentError, "wrong number of arguments (#{args.size} for 3)"
236
+ end
237
+
238
+ write_field_begin(field_info[:name], field_info[:type], fid)
239
+ write_type(field_info, value)
188
240
  write_field_end
189
241
  end
190
242
 
191
- def write_type(type, value)
192
- case type
243
+ # Writes a field value based on the field information.
244
+ #
245
+ # field_info - A Hash containing the definition of the field:
246
+ # :type - The Thrift::Types constant that determines how the value is written.
247
+ # :binary - A Boolean flag that indicates if Thrift::Types::STRING is a binary string (string without encoding).
248
+ # value - The field's value to write; object type varies based on field_info[:type].
249
+ #
250
+ # Returns nothing.
251
+ def write_type(field_info, value)
252
+ # if field_info is a Fixnum, assume it is a Thrift::Types constant
253
+ # convert it into a field_info Hash for backwards compatibility
254
+ if field_info.is_a? Fixnum
255
+ field_info = {:type => field_info}
256
+ end
257
+
258
+ case field_info[:type]
193
259
  when Types::BOOL
194
260
  write_bool(value)
195
261
  when Types::BYTE
@@ -203,7 +269,11 @@ module Thrift
203
269
  when Types::I64
204
270
  write_i64(value)
205
271
  when Types::STRING
206
- write_string(value)
272
+ if field_info[:binary]
273
+ write_binary(value)
274
+ else
275
+ write_string(value)
276
+ end
207
277
  when Types::STRUCT
208
278
  value.write(self)
209
279
  else
@@ -211,8 +281,21 @@ module Thrift
211
281
  end
212
282
  end
213
283
 
214
- def read_type(type)
215
- case type
284
+ # Reads a field value based on the field information.
285
+ #
286
+ # field_info - A Hash containing the pertinent data to write:
287
+ # :type - The Thrift::Types constant that determines how the value is written.
288
+ # :binary - A flag that indicates if Thrift::Types::STRING is a binary string (string without encoding).
289
+ #
290
+ # Returns the value read; object type varies based on field_info[:type].
291
+ def read_type(field_info)
292
+ # if field_info is a Fixnum, assume it is a Thrift::Types constant
293
+ # convert it into a field_info Hash for backwards compatibility
294
+ if field_info.is_a? Fixnum
295
+ field_info = {:type => field_info}
296
+ end
297
+
298
+ case field_info[:type]
216
299
  when Types::BOOL
217
300
  read_bool
218
301
  when Types::BYTE
@@ -226,7 +309,11 @@ module Thrift
226
309
  when Types::I64
227
310
  read_i64
228
311
  when Types::STRING
229
- read_string
312
+ if field_info[:binary]
313
+ read_binary
314
+ else
315
+ read_string
316
+ end
230
317
  else
231
318
  raise NotImplementedError
232
319
  end
@@ -32,8 +32,7 @@ module Thrift
32
32
 
33
33
  # Pre-allocated read buffer for fixed-size read methods. Needs to be at least 8 bytes long for
34
34
  # read_i64() and read_double().
35
- @rbuf = "\0" * 8
36
- @rbuf.force_encoding("BINARY") if @rbuf.respond_to?(:force_encoding)
35
+ @rbuf = Bytes.empty_byte_buffer(8)
37
36
  end
38
37
 
39
38
  def write_message_begin(name, type, seqid)
@@ -108,8 +107,13 @@ module Thrift
108
107
  end
109
108
 
110
109
  def write_string(str)
111
- write_i32(str.length)
112
- trans.write(str)
110
+ buf = Bytes.convert_to_utf8_byte_buffer(str)
111
+ write_binary(buf)
112
+ end
113
+
114
+ def write_binary(buf)
115
+ write_i32(buf.bytesize)
116
+ trans.write(buf)
113
117
  end
114
118
 
115
119
  def read_message_begin
@@ -214,9 +218,13 @@ module Thrift
214
218
  end
215
219
 
216
220
  def read_string
217
- sz = read_i32
218
- dat = trans.read_all(sz)
219
- dat
221
+ buffer = read_binary
222
+ Bytes.convert_to_string(buffer)
223
+ end
224
+
225
+ def read_binary
226
+ size = read_i32
227
+ trans.read_all(size)
220
228
  end
221
229
 
222
230
  end