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
@@ -20,15 +20,24 @@
20
20
 
21
21
  module Thrift
22
22
  class CompactProtocol < BaseProtocol
23
-
24
- PROTOCOL_ID = [0x82].pack('c').unpack('c').first
23
+ PROTOCOL_ID = [0x82].pack("c").unpack1("c")
25
24
  VERSION = 1
26
25
  VERSION_MASK = 0x1f
27
26
  TYPE_MASK = 0xE0
28
27
  TYPE_BITS = 0x07
29
28
  TYPE_SHIFT_AMOUNT = 5
30
29
  MAX_VARINT32_BYTES = 5 # ceil(32/7); matches protobuf wire format
30
+ VARINT32_PREFIX_BYTES = MAX_VARINT32_BYTES - 1
31
+ MAX_VARINT32_LAST_BYTE = 0x0f
31
32
  MAX_VARINT_BYTES = 10 # ceil(64/7); matches protobuf wire format
33
+ BYTE_MIN = -(2**7)
34
+ BYTE_MAX = (2**7) - 1
35
+ I16_MIN = -(2**15)
36
+ I16_MAX = (2**15) - 1
37
+ I32_MIN = -(2**31)
38
+ I32_MAX = (2**31) - 1
39
+ I64_MIN = -(2**63)
40
+ I64_MAX = (2**63) - 1
32
41
 
33
42
  TSTOP = [nil, Types::STOP, 0]
34
43
 
@@ -68,40 +77,53 @@ module Thrift
68
77
  SET => Types::SET,
69
78
  MAP => Types::MAP,
70
79
  STRUCT => Types::STRUCT,
71
- UUID => Types::UUID
80
+ UUID => Types::UUID,
72
81
  }
73
82
 
74
83
  TTYPE_TO_COMPACT = {
75
- Types::STOP => Types::STOP,
76
- Types::BOOL => BOOLEAN_TRUE,
77
- Types::BYTE => BYTE,
78
- Types::I16 => I16,
79
- Types::I32 => I32,
80
- Types::I64 => I64,
81
- Types::DOUBLE => DOUBLE,
82
- Types::STRING => BINARY,
83
- Types::LIST => LIST,
84
- Types::SET => SET,
85
- Types::MAP => MAP,
86
- Types::STRUCT => STRUCT,
87
- Types::UUID => UUID
84
+ Types::STOP => Types::STOP,
85
+ Types::BOOL => BOOLEAN_TRUE,
86
+ Types::BYTE => BYTE,
87
+ Types::I16 => I16,
88
+ Types::I32 => I32,
89
+ Types::I64 => I64,
90
+ Types::DOUBLE => DOUBLE,
91
+ Types::STRING => BINARY,
92
+ Types::LIST => LIST,
93
+ Types::SET => SET,
94
+ Types::MAP => MAP,
95
+ Types::STRUCT => STRUCT,
96
+ Types::UUID => UUID,
88
97
  }
89
98
 
90
99
  def self.get_ttype(compact_type)
91
100
  val = COMPACT_TO_TTYPE[compact_type & 0x0f]
92
- raise "don't know what type: #{compact_type & 0x0f}" unless val
93
- val
101
+ return val if val
102
+
103
+ raise ProtocolException.new(
104
+ ProtocolException::INVALID_DATA,
105
+ "Unknown compact type: #{compact_type & 0x0f}",
106
+ )
94
107
  end
95
108
 
96
109
  def self.get_compact_type(ttype)
97
110
  val = TTYPE_TO_COMPACT[ttype]
98
- raise "don't know what type: #{ttype & 0x0f}" unless val
99
- val
111
+ return val if val
112
+
113
+ raise ProtocolException.new(
114
+ ProtocolException::INVALID_DATA,
115
+ "Unknown compact type: #{ttype}",
116
+ )
100
117
  end
101
118
  end
102
119
 
103
- def initialize(transport)
120
+ attr_reader :max_string_size
121
+
122
+ def initialize(transport, max_string_size: DEFAULT_MAX_STRING_SIZE)
123
+ BaseProtocol.validate_max_string_size(max_string_size)
104
124
  super(transport)
125
+ @max_string_size = max_string_size
126
+ @reset_message_size = transport.message_boundaries?
105
127
 
106
128
  @last_field = [0]
107
129
  @boolean_value = nil
@@ -111,8 +133,14 @@ module Thrift
111
133
  end
112
134
 
113
135
  def write_message_begin(name, type, seqid)
114
- write_byte(PROTOCOL_ID)
115
- write_byte((VERSION & VERSION_MASK) | ((type << TYPE_SHIFT_AMOUNT) & TYPE_MASK))
136
+ unless seqid.is_a?(Integer)
137
+ raise "nil argument not allowed!" if seqid.nil?
138
+ raise ::TypeError, "integer argument expected"
139
+ end
140
+ raise RangeError if seqid < I32_MIN || seqid > I32_MAX
141
+
142
+ write_byte_direct(PROTOCOL_ID)
143
+ write_byte_direct((VERSION & VERSION_MASK) | ((type << TYPE_SHIFT_AMOUNT) & TYPE_MASK))
116
144
  write_varint32(message_seqid_to_varint32(seqid))
117
145
  write_string(name)
118
146
  nil
@@ -129,6 +157,12 @@ module Thrift
129
157
  end
130
158
 
131
159
  def write_field_begin(name, type, id)
160
+ unless id.is_a?(Integer)
161
+ raise "nil argument not allowed!" if id.nil?
162
+ raise ::TypeError, "integer argument expected"
163
+ end
164
+ raise RangeError if id < I16_MIN || id > I16_MAX
165
+
132
166
  if type == Types::BOOL
133
167
  # we want to possibly include the value, so we'll wait.
134
168
  @boolean_field = [type, id]
@@ -147,16 +181,16 @@ module Thrift
147
181
  last_id = @last_field.pop
148
182
 
149
183
  # if there's a type override, use that.
150
- typeToWrite = type_override || CompactTypes.get_compact_type(type)
184
+ type_to_write = type_override || CompactTypes.get_compact_type(type)
151
185
 
152
186
  # check if we can use delta encoding for the field id
153
187
  if id > last_id && id - last_id <= 15
154
188
  # write them together
155
- write_byte((id - last_id) << 4 | typeToWrite)
189
+ write_byte_direct(((id - last_id) << 4) | type_to_write)
156
190
  else
157
191
  # write them separate
158
- write_byte(typeToWrite)
159
- write_i16(id)
192
+ write_byte_direct(type_to_write)
193
+ write_varint32(int_to_zig_zag(id))
160
194
  end
161
195
 
162
196
  @last_field.push(id)
@@ -164,15 +198,16 @@ module Thrift
164
198
  end
165
199
 
166
200
  def write_field_stop
167
- write_byte(Types::STOP)
201
+ write_byte_direct(Types::STOP)
168
202
  end
169
203
 
170
204
  def write_map_begin(ktype, vtype, size)
205
+ size = validate_size(size)
171
206
  if (size == 0)
172
- write_byte(0)
207
+ write_byte_direct(0)
173
208
  else
174
209
  write_varint32(size)
175
- write_byte(CompactTypes.get_compact_type(ktype) << 4 | CompactTypes.get_compact_type(vtype))
210
+ write_byte_direct((CompactTypes.get_compact_type(ktype) << 4) | CompactTypes.get_compact_type(vtype))
176
211
  end
177
212
  end
178
213
 
@@ -185,6 +220,7 @@ module Thrift
185
220
  end
186
221
 
187
222
  def write_bool(bool)
223
+ # Preserve Ruby truthiness: only false and nil encode as false.
188
224
  type = bool ? CompactTypes::BOOLEAN_TRUE : CompactTypes::BOOLEAN_FALSE
189
225
  unless @boolean_field.nil?
190
226
  # we haven't written the field header yet
@@ -192,23 +228,47 @@ module Thrift
192
228
  @boolean_field = nil
193
229
  else
194
230
  # we're not part of a field, so just write the value.
195
- write_byte(type)
231
+ write_byte_direct(type)
196
232
  end
197
233
  end
198
234
 
199
235
  def write_byte(byte)
200
- @trans.write([byte].pack('c'))
236
+ unless byte.is_a?(Integer)
237
+ raise "nil argument not allowed!" if byte.nil?
238
+ raise ::TypeError, "integer argument expected"
239
+ end
240
+ raise RangeError if byte < BYTE_MIN || byte > BYTE_MAX
241
+
242
+ write_byte_direct(byte)
201
243
  end
202
244
 
203
245
  def write_i16(i16)
246
+ unless i16.is_a?(Integer)
247
+ raise "nil argument not allowed!" if i16.nil?
248
+ raise ::TypeError, "integer argument expected"
249
+ end
250
+ raise RangeError if i16 < I16_MIN || i16 > I16_MAX
251
+
204
252
  write_varint32(int_to_zig_zag(i16))
205
253
  end
206
254
 
207
255
  def write_i32(i32)
256
+ unless i32.is_a?(Integer)
257
+ raise "nil argument not allowed!" if i32.nil?
258
+ raise ::TypeError, "integer argument expected"
259
+ end
260
+ raise RangeError if i32 < I32_MIN || i32 > I32_MAX
261
+
208
262
  write_varint32(int_to_zig_zag(i32))
209
263
  end
210
264
 
211
265
  def write_i64(i64)
266
+ unless i64.is_a?(Integer)
267
+ raise "nil argument not allowed!" if i64.nil?
268
+ raise ::TypeError, "integer argument expected"
269
+ end
270
+ raise RangeError if i64 < I64_MIN || i64 > I64_MAX
271
+
212
272
  write_varint64(long_to_zig_zag(i64))
213
273
  end
214
274
 
@@ -222,7 +282,8 @@ module Thrift
222
282
  end
223
283
 
224
284
  def write_binary(buf)
225
- write_varint32(buf.bytesize)
285
+ size = validate_size(buf.bytesize)
286
+ write_varint32(size)
226
287
  @trans.write(buf)
227
288
  end
228
289
 
@@ -232,20 +293,28 @@ module Thrift
232
293
  end
233
294
 
234
295
  def read_message_begin
235
- protocol_id = read_byte()
296
+ trans.reset_message_size if @reset_message_size
297
+
298
+ protocol_id = read_byte
236
299
  if protocol_id != PROTOCOL_ID
237
- raise ProtocolException.new("Expected protocol id #{PROTOCOL_ID} but got #{protocol_id}")
300
+ raise ProtocolException.new(
301
+ ProtocolException::BAD_VERSION,
302
+ "Expected protocol id #{PROTOCOL_ID} but got #{protocol_id}",
303
+ )
238
304
  end
239
305
 
240
- version_and_type = read_byte()
306
+ version_and_type = read_byte
241
307
  version = version_and_type & VERSION_MASK
242
308
  if (version != VERSION)
243
- raise ProtocolException.new("Expected version #{VERSION} but got #{version}");
309
+ raise ProtocolException.new(
310
+ ProtocolException::BAD_VERSION,
311
+ "Expected version #{VERSION} but got #{version}",
312
+ )
244
313
  end
245
314
 
246
315
  type = (version_and_type >> TYPE_SHIFT_AMOUNT) & TYPE_BITS
247
- seqid = message_seqid_from_varint32(read_varint32())
248
- messageName = read_string()
316
+ seqid = message_seqid_from_varint32(read_varint32)
317
+ messageName = read_string
249
318
  [messageName, type, seqid]
250
319
  end
251
320
 
@@ -255,12 +324,12 @@ module Thrift
255
324
  end
256
325
 
257
326
  def read_struct_end
258
- @last_field.pop()
327
+ @last_field.pop
259
328
  nil
260
329
  end
261
330
 
262
331
  def read_field_begin
263
- type = read_byte()
332
+ type = read_byte
264
333
 
265
334
  # if it's a stop, then we can return immediately, as the struct is over.
266
335
  if (type & 0x0f) == Types::STOP
@@ -273,7 +342,7 @@ module Thrift
273
342
  if modifier == 0
274
343
  # not a delta. look ahead for the zigzag varint field id.
275
344
  @last_field.pop
276
- field_id = read_i16()
345
+ field_id = read_i16
277
346
  else
278
347
  # has a delta. add the delta to the last read field id.
279
348
  field_id = @last_field.pop + modifier
@@ -292,17 +361,19 @@ module Thrift
292
361
  end
293
362
 
294
363
  def read_map_begin
295
- size = read_varint32()
296
- key_and_value_type = size == 0 ? 0 : read_byte()
364
+ size = read_varint32
365
+ validate_container_size(size)
366
+ key_and_value_type = size == 0 ? 0 : read_byte
297
367
  [CompactTypes.get_ttype(key_and_value_type >> 4), CompactTypes.get_ttype(key_and_value_type & 0xf), size]
298
368
  end
299
369
 
300
370
  def read_list_begin
301
- size_and_type = read_byte()
371
+ size_and_type = read_byte
302
372
  size = (size_and_type >> 4) & 0x0f
303
373
  if size == 15
304
- size = read_varint32()
374
+ size = read_varint32
305
375
  end
376
+ validate_container_size(size)
306
377
  type = CompactTypes.get_ttype(size_and_type)
307
378
  [type, size]
308
379
  end
@@ -317,7 +388,7 @@ module Thrift
317
388
  @bool_value = nil
318
389
  bv
319
390
  else
320
- read_byte() == CompactTypes::BOOLEAN_TRUE
391
+ read_byte == CompactTypes::BOOLEAN_TRUE
321
392
  end
322
393
  end
323
394
 
@@ -330,21 +401,21 @@ module Thrift
330
401
  end
331
402
 
332
403
  def read_i16
333
- zig_zag_to_int(read_varint32())
404
+ value = zig_zag_to_int(read_varint32) & 0xffff
405
+ value > I16_MAX ? value - 0x10000 : value
334
406
  end
335
407
 
336
408
  def read_i32
337
- zig_zag_to_int(read_varint32())
409
+ zig_zag_to_int(read_varint32)
338
410
  end
339
411
 
340
412
  def read_i64
341
- zig_zag_to_long(read_varint64())
413
+ zig_zag_to_long(read_varint64 & 0xffffffffffffffff)
342
414
  end
343
415
 
344
416
  def read_double
345
417
  trans.read_into_buffer(@rbuf, 8)
346
- val = @rbuf.reverse.unpack('G').first
347
- val
418
+ @rbuf.reverse.unpack1("G")
348
419
  end
349
420
 
350
421
  def read_string
@@ -353,16 +424,24 @@ module Thrift
353
424
  end
354
425
 
355
426
  def read_binary
356
- size = read_varint32()
427
+ size = read_varint32
428
+ if size > I32_MAX
429
+ raise ProtocolException.new(ProtocolException::SIZE_LIMIT, "Binary size limit exceeded")
430
+ end
431
+ check_string_size(size)
357
432
  trans.read_all(size)
358
433
  end
359
434
 
435
+ def skip_string
436
+ read_binary
437
+ end
438
+
360
439
  def read_uuid
361
440
  UUID.uuid_from_bytes(trans.read_all(16))
362
441
  end
363
442
 
364
443
  def to_s
365
- "compact(#{super.to_s})"
444
+ "compact(#{super})"
366
445
  end
367
446
 
368
447
  private
@@ -372,68 +451,84 @@ module Thrift
372
451
  # the wire differ only by the type indicator.
373
452
  #
374
453
  def write_collection_begin(elem_type, size)
454
+ size = validate_size(size)
455
+ compact_type = CompactTypes.get_compact_type(elem_type)
375
456
  if size <= 14
376
- write_byte(size << 4 | CompactTypes.get_compact_type(elem_type))
457
+ write_byte_direct((size << 4) | compact_type)
377
458
  else
378
- write_byte(0xf0 | CompactTypes.get_compact_type(elem_type))
459
+ write_byte_direct(0xf0 | compact_type)
379
460
  write_varint32(size)
380
461
  end
381
462
  end
382
463
 
464
+ def write_byte_direct(byte)
465
+ @trans.write([byte].pack("C"))
466
+ end
467
+
383
468
  def write_varint32(n)
384
- # int idx = 0;
385
- while true
386
- if (n & ~0x7F) == 0
387
- # i32buf[idx++] = (byte)n;
388
- write_byte(n)
389
- break
390
- # return;
391
- else
392
- # i32buf[idx++] = (byte)((n & 0x7F) | 0x80);
393
- write_byte((n & 0x7F) | 0x80)
394
- n = n >> 7
395
- end
469
+ if (n & ~0x7F) == 0
470
+ write_byte_direct(n)
471
+ return
396
472
  end
397
- # trans_.write(i32buf, 0, idx);
473
+
474
+ buffer = String.new(capacity: MAX_VARINT32_BYTES, encoding: Encoding::BINARY)
475
+ while (n & ~0x7F) != 0
476
+ buffer << ((n & 0x7F) | 0x80)
477
+ n >>= 7
478
+ end
479
+ buffer << n
480
+ @trans.write(buffer)
398
481
  end
399
482
 
400
483
  SEVEN_BIT_MASK = 0x7F
401
484
  EVERYTHING_ELSE_MASK = ~SEVEN_BIT_MASK
402
485
 
403
486
  def write_varint64(n)
404
- while true
405
- if (n & EVERYTHING_ELSE_MASK) == 0 # TODO need to find a way to make this into a long...
406
- write_byte(n)
407
- break
408
- else
409
- write_byte((n & SEVEN_BIT_MASK) | 0x80)
410
- n >>= 7
411
- end
487
+ if (n & EVERYTHING_ELSE_MASK) == 0
488
+ write_byte_direct(n)
489
+ return
490
+ end
491
+
492
+ buffer = String.new(capacity: MAX_VARINT_BYTES, encoding: Encoding::BINARY)
493
+ while (n & EVERYTHING_ELSE_MASK) != 0
494
+ buffer << ((n & SEVEN_BIT_MASK) | 0x80)
495
+ n >>= 7
412
496
  end
497
+ buffer << n
498
+ @trans.write(buffer)
413
499
  end
414
500
 
415
- def read_varint32()
501
+ def read_varint32
416
502
  shift = 0
417
503
  result = 0
418
- MAX_VARINT32_BYTES.times do
419
- b = read_byte()
504
+ VARINT32_PREFIX_BYTES.times do
505
+ b = read_byte
420
506
  result |= (b & 0x7f) << shift
421
507
  return result if (b & 0x80) != 0x80
422
508
  shift += 7
423
509
  end
424
- raise ProtocolException.new(ProtocolException::INVALID_DATA, 'Variable-length int over 5 bytes.')
510
+
511
+ b = read_byte
512
+ if (b & 0x80) != 0
513
+ raise ProtocolException.new(ProtocolException::INVALID_DATA, "Variable-length int over 5 bytes.")
514
+ end
515
+ if (b & ~MAX_VARINT32_LAST_BYTE) != 0
516
+ raise ProtocolException.new(ProtocolException::INVALID_DATA, "Variable-length int overflows uint32.")
517
+ end
518
+
519
+ result | (b << shift)
425
520
  end
426
521
 
427
- def read_varint64()
522
+ def read_varint64
428
523
  shift = 0
429
524
  result = 0
430
525
  MAX_VARINT_BYTES.times do
431
- b = read_byte()
526
+ b = read_byte
432
527
  result |= (b & 0x7f) << shift
433
528
  return result if (b & 0x80) != 0x80
434
529
  shift += 7
435
530
  end
436
- raise ProtocolException.new(ProtocolException::INVALID_DATA, 'Variable-length int over 10 bytes.')
531
+ raise ProtocolException.new(ProtocolException::INVALID_DATA, "Variable-length int over 10 bytes.")
437
532
  end
438
533
 
439
534
  def int_to_zig_zag(n)
@@ -454,11 +549,17 @@ module Thrift
454
549
  end
455
550
 
456
551
  def message_seqid_to_varint32(seqid)
457
- if seqid < -(2**31) || seqid > (2**31) - 1
458
- raise RangeError, "seqid must be a signed int32"
552
+ seqid < 0 ? seqid + (2**32) : seqid
553
+ end
554
+
555
+ def validate_size(size)
556
+ unless size.is_a?(Integer)
557
+ raise "nil argument not allowed!" if size.nil?
558
+ raise ::TypeError, "integer argument expected"
459
559
  end
560
+ raise RangeError if size < 0 || size > I32_MAX
460
561
 
461
- seqid < 0 ? seqid + (2**32) : seqid
562
+ size
462
563
  end
463
564
 
464
565
  def message_seqid_from_varint32(seqid)
@@ -467,8 +568,12 @@ module Thrift
467
568
  end
468
569
 
469
570
  class CompactProtocolFactory < BaseProtocolFactory
571
+ def initialize(max_string_size: BaseProtocol::DEFAULT_MAX_STRING_SIZE)
572
+ @max_string_size = max_string_size
573
+ end
574
+
470
575
  def get_protocol(trans)
471
- CompactProtocol.new(trans)
576
+ CompactProtocol.new(trans, max_string_size: @max_string_size)
472
577
  end
473
578
 
474
579
  def to_s
@@ -178,8 +178,9 @@ module Thrift
178
178
  @header_transport.reset_protocol
179
179
  reset_protocol_if_needed
180
180
  rescue ProtocolException => ex
181
+ use_default_protocol
181
182
  app_ex = ApplicationException.new(ApplicationException::INVALID_PROTOCOL, ex.message)
182
- write_message_begin("", MessageTypes::EXCEPTION, 0)
183
+ write_message_begin("", MessageTypes::EXCEPTION, @header_transport.sequence_id)
183
184
  app_ex.write(self)
184
185
  write_message_end
185
186
  @header_transport.flush
@@ -264,12 +265,16 @@ module Thrift
264
265
  @protocol.read_binary
265
266
  end
266
267
 
268
+ def skip_string
269
+ @protocol.skip_string
270
+ end
271
+
267
272
  def read_uuid
268
273
  @protocol.read_uuid
269
274
  end
270
275
 
271
276
  def to_s
272
- "header(#{@protocol.to_s})"
277
+ "header(#{@protocol})"
273
278
  end
274
279
 
275
280
  private
@@ -283,6 +288,12 @@ module Thrift
283
288
  end
284
289
  end
285
290
 
291
+ def use_default_protocol
292
+ @protocol = create_protocol(@default_protocol)
293
+ @current_protocol_id = @default_protocol
294
+ @header_transport.protocol_id = @default_protocol
295
+ end
296
+
286
297
  # Creates a protocol instance based on protocol ID
287
298
  def create_protocol(protocol_id)
288
299
  case protocol_id
@@ -293,7 +304,7 @@ module Thrift
293
304
  else
294
305
  raise ProtocolException.new(
295
306
  ProtocolException::INVALID_DATA,
296
- "Unknown protocol ID: #{protocol_id}"
307
+ "Unknown protocol ID: #{protocol_id}",
297
308
  )
298
309
  end
299
310
  end