thrift 0.23.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 +203 -40
  3. data/ext/binary_protocol_accelerated.c +130 -40
  4. data/ext/bytes.c +14 -0
  5. data/ext/compact_protocol.c +184 -91
  6. data/ext/constants.h +3 -0
  7. data/ext/extconf.rb +12 -4
  8. data/ext/macros.h +11 -0
  9. data/ext/memory_buffer.c +67 -12
  10. data/ext/struct.c +192 -71
  11. data/ext/thrift_native.c +7 -0
  12. data/lib/thrift/bytes.rb +6 -3
  13. data/lib/thrift/client.rb +31 -33
  14. data/lib/thrift/exceptions.rb +11 -8
  15. data/lib/thrift/multiplexed_processor.rb +17 -8
  16. data/lib/thrift/processor.rb +25 -3
  17. data/lib/thrift/protocol/base_protocol.rb +66 -31
  18. data/lib/thrift/protocol/binary_protocol.rb +80 -37
  19. data/lib/thrift/protocol/binary_protocol_accelerated.rb +7 -2
  20. data/lib/thrift/protocol/compact_protocol.rb +204 -88
  21. data/lib/thrift/protocol/header_protocol.rb +15 -3
  22. data/lib/thrift/protocol/json_protocol.rb +158 -109
  23. data/lib/thrift/protocol/multiplexed_protocol.rb +3 -3
  24. data/lib/thrift/protocol/protocol_decorator.rb +6 -2
  25. data/lib/thrift/serializer/deserializer.rb +1 -0
  26. data/lib/thrift/serializer/serializer.rb +7 -0
  27. data/lib/thrift/server/base_server.rb +11 -2
  28. data/lib/thrift/server/nonblocking_server.rb +69 -20
  29. data/lib/thrift/server/rack_application.rb +69 -0
  30. data/lib/thrift/server/simple_server.rb +27 -15
  31. data/lib/thrift/server/thin_http_server.rb +21 -44
  32. data/lib/thrift/server/thread_pool_server.rb +21 -17
  33. data/lib/thrift/server/threaded_server.rb +22 -18
  34. data/lib/thrift/struct.rb +34 -18
  35. data/lib/thrift/struct_union.rb +37 -36
  36. data/lib/thrift/thrift_native.rb +2 -1
  37. data/lib/thrift/transport/base_server_transport.rb +3 -0
  38. data/lib/thrift/transport/base_transport.rb +26 -4
  39. data/lib/thrift/transport/buffered_transport.rb +5 -4
  40. data/lib/thrift/transport/framed_transport.rb +33 -7
  41. data/lib/thrift/transport/header_transport.rb +159 -33
  42. data/lib/thrift/transport/http_client_transport.rb +28 -14
  43. data/lib/thrift/transport/io_stream_transport.rb +3 -1
  44. data/lib/thrift/transport/memory_buffer_transport.rb +14 -9
  45. data/lib/thrift/transport/server_socket.rb +10 -8
  46. data/lib/thrift/transport/socket.rb +85 -48
  47. data/lib/thrift/transport/ssl_server_socket.rb +67 -6
  48. data/lib/thrift/transport/ssl_socket.rb +73 -14
  49. data/lib/thrift/transport/unix_server_socket.rb +6 -2
  50. data/lib/thrift/transport/unix_socket.rb +5 -6
  51. data/lib/thrift/types.rb +23 -22
  52. data/lib/thrift/union.rb +21 -11
  53. data/lib/thrift/uuid.rb +9 -8
  54. data/lib/thrift.rb +40 -39
  55. metadata +7 -266
  56. data/benchmark/Benchmark.thrift +0 -24
  57. data/benchmark/benchmark.rb +0 -285
  58. data/benchmark/client.rb +0 -117
  59. data/benchmark/server.rb +0 -120
  60. data/benchmark/thin_server.rb +0 -45
  61. data/lib/thrift/server/mongrel_http_server.rb +0 -60
  62. data/spec/BaseService.thrift +0 -27
  63. data/spec/ExtendedService.thrift +0 -25
  64. data/spec/Referenced.thrift +0 -44
  65. data/spec/ThriftNamespacedSpec.thrift +0 -53
  66. data/spec/ThriftSpec.thrift +0 -187
  67. data/spec/base_protocol_spec.rb +0 -224
  68. data/spec/base_transport_spec.rb +0 -387
  69. data/spec/binary_protocol_accelerated_spec.rb +0 -46
  70. data/spec/binary_protocol_spec.rb +0 -72
  71. data/spec/binary_protocol_spec_shared.rb +0 -445
  72. data/spec/bytes_spec.rb +0 -99
  73. data/spec/client_spec.rb +0 -166
  74. data/spec/compact_protocol_spec.rb +0 -196
  75. data/spec/constants_demo_spec.rb +0 -101
  76. data/spec/exception_spec.rb +0 -140
  77. data/spec/flat_spec.rb +0 -62
  78. data/spec/header_protocol_spec.rb +0 -475
  79. data/spec/header_transport_spec.rb +0 -386
  80. data/spec/http_client_spec.rb +0 -159
  81. data/spec/json_protocol_spec.rb +0 -552
  82. data/spec/namespaced_spec.rb +0 -66
  83. data/spec/nonblocking_server_spec.rb +0 -361
  84. data/spec/processor_spec.rb +0 -79
  85. data/spec/serializer_spec.rb +0 -66
  86. data/spec/server_socket_spec.rb +0 -84
  87. data/spec/server_spec.rb +0 -186
  88. data/spec/socket_spec.rb +0 -67
  89. data/spec/socket_spec_shared.rb +0 -167
  90. data/spec/spec_helper.rb +0 -69
  91. data/spec/ssl_server_socket_spec.rb +0 -45
  92. data/spec/ssl_socket_spec.rb +0 -87
  93. data/spec/struct_nested_containers_spec.rb +0 -190
  94. data/spec/struct_spec.rb +0 -397
  95. data/spec/support/header_protocol_helper.rb +0 -54
  96. data/spec/thin_http_server_spec.rb +0 -126
  97. data/spec/types_spec.rb +0 -117
  98. data/spec/union_spec.rb +0 -272
  99. data/spec/unix_socket_spec.rb +0 -115
  100. data/spec/uuid_validation_spec.rb +0 -238
  101. data/test/fuzz/Makefile.am +0 -173
  102. data/test/fuzz/README.md +0 -149
  103. data/test/fuzz/fuzz_common.rb +0 -95
  104. data/test/fuzz/fuzz_parse_binary_protocol.rb +0 -22
  105. data/test/fuzz/fuzz_parse_binary_protocol_accelerated.rb +0 -22
  106. data/test/fuzz/fuzz_parse_binary_protocol_accelerated_harness.rb +0 -22
  107. data/test/fuzz/fuzz_parse_binary_protocol_harness.rb +0 -22
  108. data/test/fuzz/fuzz_parse_compact_protocol.rb +0 -22
  109. data/test/fuzz/fuzz_parse_compact_protocol_harness.rb +0 -22
  110. data/test/fuzz/fuzz_parse_json_protocol.rb +0 -22
  111. data/test/fuzz/fuzz_parse_json_protocol_harness.rb +0 -22
  112. data/test/fuzz/fuzz_roundtrip_binary_protocol.rb +0 -22
  113. data/test/fuzz/fuzz_roundtrip_binary_protocol_accelerated.rb +0 -22
  114. data/test/fuzz/fuzz_roundtrip_binary_protocol_accelerated_harness.rb +0 -22
  115. data/test/fuzz/fuzz_roundtrip_binary_protocol_harness.rb +0 -22
  116. data/test/fuzz/fuzz_roundtrip_compact_protocol.rb +0 -22
  117. data/test/fuzz/fuzz_roundtrip_compact_protocol_harness.rb +0 -22
  118. data/test/fuzz/fuzz_roundtrip_json_protocol.rb +0 -22
  119. data/test/fuzz/fuzz_roundtrip_json_protocol_harness.rb +0 -22
  120. data/test/fuzz/fuzz_tracer.rb +0 -28
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  #
2
3
  # Licensed to the Apache Software Foundation (ASF) under one
3
4
  # or more contributor license agreements. See the NOTICE file
@@ -19,13 +20,24 @@
19
20
 
20
21
  module Thrift
21
22
  class CompactProtocol < BaseProtocol
22
-
23
- PROTOCOL_ID = [0x82].pack('c').unpack('c').first
23
+ PROTOCOL_ID = [0x82].pack("c").unpack1("c")
24
24
  VERSION = 1
25
25
  VERSION_MASK = 0x1f
26
26
  TYPE_MASK = 0xE0
27
27
  TYPE_BITS = 0x07
28
28
  TYPE_SHIFT_AMOUNT = 5
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
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
29
41
 
30
42
  TSTOP = [nil, Types::STOP, 0]
31
43
 
@@ -65,40 +77,53 @@ module Thrift
65
77
  SET => Types::SET,
66
78
  MAP => Types::MAP,
67
79
  STRUCT => Types::STRUCT,
68
- UUID => Types::UUID
80
+ UUID => Types::UUID,
69
81
  }
70
82
 
71
83
  TTYPE_TO_COMPACT = {
72
- Types::STOP => Types::STOP,
73
- Types::BOOL => BOOLEAN_TRUE,
74
- Types::BYTE => BYTE,
75
- Types::I16 => I16,
76
- Types::I32 => I32,
77
- Types::I64 => I64,
78
- Types::DOUBLE => DOUBLE,
79
- Types::STRING => BINARY,
80
- Types::LIST => LIST,
81
- Types::SET => SET,
82
- Types::MAP => MAP,
83
- Types::STRUCT => STRUCT,
84
- 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,
85
97
  }
86
98
 
87
99
  def self.get_ttype(compact_type)
88
100
  val = COMPACT_TO_TTYPE[compact_type & 0x0f]
89
- raise "don't know what type: #{compact_type & 0x0f}" unless val
90
- val
101
+ return val if val
102
+
103
+ raise ProtocolException.new(
104
+ ProtocolException::INVALID_DATA,
105
+ "Unknown compact type: #{compact_type & 0x0f}",
106
+ )
91
107
  end
92
108
 
93
109
  def self.get_compact_type(ttype)
94
110
  val = TTYPE_TO_COMPACT[ttype]
95
- raise "don't know what type: #{ttype & 0x0f}" unless val
96
- val
111
+ return val if val
112
+
113
+ raise ProtocolException.new(
114
+ ProtocolException::INVALID_DATA,
115
+ "Unknown compact type: #{ttype}",
116
+ )
97
117
  end
98
118
  end
99
119
 
100
- 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)
101
124
  super(transport)
125
+ @max_string_size = max_string_size
126
+ @reset_message_size = transport.message_boundaries?
102
127
 
103
128
  @last_field = [0]
104
129
  @boolean_value = nil
@@ -108,8 +133,14 @@ module Thrift
108
133
  end
109
134
 
110
135
  def write_message_begin(name, type, seqid)
111
- write_byte(PROTOCOL_ID)
112
- 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))
113
144
  write_varint32(message_seqid_to_varint32(seqid))
114
145
  write_string(name)
115
146
  nil
@@ -126,6 +157,12 @@ module Thrift
126
157
  end
127
158
 
128
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
+
129
166
  if type == Types::BOOL
130
167
  # we want to possibly include the value, so we'll wait.
131
168
  @boolean_field = [type, id]
@@ -144,16 +181,16 @@ module Thrift
144
181
  last_id = @last_field.pop
145
182
 
146
183
  # if there's a type override, use that.
147
- typeToWrite = type_override || CompactTypes.get_compact_type(type)
184
+ type_to_write = type_override || CompactTypes.get_compact_type(type)
148
185
 
149
186
  # check if we can use delta encoding for the field id
150
187
  if id > last_id && id - last_id <= 15
151
188
  # write them together
152
- write_byte((id - last_id) << 4 | typeToWrite)
189
+ write_byte_direct(((id - last_id) << 4) | type_to_write)
153
190
  else
154
191
  # write them separate
155
- write_byte(typeToWrite)
156
- write_i16(id)
192
+ write_byte_direct(type_to_write)
193
+ write_varint32(int_to_zig_zag(id))
157
194
  end
158
195
 
159
196
  @last_field.push(id)
@@ -161,15 +198,16 @@ module Thrift
161
198
  end
162
199
 
163
200
  def write_field_stop
164
- write_byte(Types::STOP)
201
+ write_byte_direct(Types::STOP)
165
202
  end
166
203
 
167
204
  def write_map_begin(ktype, vtype, size)
205
+ size = validate_size(size)
168
206
  if (size == 0)
169
- write_byte(0)
207
+ write_byte_direct(0)
170
208
  else
171
209
  write_varint32(size)
172
- 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))
173
211
  end
174
212
  end
175
213
 
@@ -182,6 +220,7 @@ module Thrift
182
220
  end
183
221
 
184
222
  def write_bool(bool)
223
+ # Preserve Ruby truthiness: only false and nil encode as false.
185
224
  type = bool ? CompactTypes::BOOLEAN_TRUE : CompactTypes::BOOLEAN_FALSE
186
225
  unless @boolean_field.nil?
187
226
  # we haven't written the field header yet
@@ -189,23 +228,47 @@ module Thrift
189
228
  @boolean_field = nil
190
229
  else
191
230
  # we're not part of a field, so just write the value.
192
- write_byte(type)
231
+ write_byte_direct(type)
193
232
  end
194
233
  end
195
234
 
196
235
  def write_byte(byte)
197
- @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)
198
243
  end
199
244
 
200
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
+
201
252
  write_varint32(int_to_zig_zag(i16))
202
253
  end
203
254
 
204
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
+
205
262
  write_varint32(int_to_zig_zag(i32))
206
263
  end
207
264
 
208
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
+
209
272
  write_varint64(long_to_zig_zag(i64))
210
273
  end
211
274
 
@@ -219,7 +282,8 @@ module Thrift
219
282
  end
220
283
 
221
284
  def write_binary(buf)
222
- write_varint32(buf.bytesize)
285
+ size = validate_size(buf.bytesize)
286
+ write_varint32(size)
223
287
  @trans.write(buf)
224
288
  end
225
289
 
@@ -229,20 +293,28 @@ module Thrift
229
293
  end
230
294
 
231
295
  def read_message_begin
232
- protocol_id = read_byte()
296
+ trans.reset_message_size if @reset_message_size
297
+
298
+ protocol_id = read_byte
233
299
  if protocol_id != PROTOCOL_ID
234
- 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
+ )
235
304
  end
236
305
 
237
- version_and_type = read_byte()
306
+ version_and_type = read_byte
238
307
  version = version_and_type & VERSION_MASK
239
308
  if (version != VERSION)
240
- 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
+ )
241
313
  end
242
314
 
243
315
  type = (version_and_type >> TYPE_SHIFT_AMOUNT) & TYPE_BITS
244
- seqid = message_seqid_from_varint32(read_varint32())
245
- messageName = read_string()
316
+ seqid = message_seqid_from_varint32(read_varint32)
317
+ messageName = read_string
246
318
  [messageName, type, seqid]
247
319
  end
248
320
 
@@ -252,12 +324,12 @@ module Thrift
252
324
  end
253
325
 
254
326
  def read_struct_end
255
- @last_field.pop()
327
+ @last_field.pop
256
328
  nil
257
329
  end
258
330
 
259
331
  def read_field_begin
260
- type = read_byte()
332
+ type = read_byte
261
333
 
262
334
  # if it's a stop, then we can return immediately, as the struct is over.
263
335
  if (type & 0x0f) == Types::STOP
@@ -270,7 +342,7 @@ module Thrift
270
342
  if modifier == 0
271
343
  # not a delta. look ahead for the zigzag varint field id.
272
344
  @last_field.pop
273
- field_id = read_i16()
345
+ field_id = read_i16
274
346
  else
275
347
  # has a delta. add the delta to the last read field id.
276
348
  field_id = @last_field.pop + modifier
@@ -289,17 +361,19 @@ module Thrift
289
361
  end
290
362
 
291
363
  def read_map_begin
292
- size = read_varint32()
293
- 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
294
367
  [CompactTypes.get_ttype(key_and_value_type >> 4), CompactTypes.get_ttype(key_and_value_type & 0xf), size]
295
368
  end
296
369
 
297
370
  def read_list_begin
298
- size_and_type = read_byte()
371
+ size_and_type = read_byte
299
372
  size = (size_and_type >> 4) & 0x0f
300
373
  if size == 15
301
- size = read_varint32()
374
+ size = read_varint32
302
375
  end
376
+ validate_container_size(size)
303
377
  type = CompactTypes.get_ttype(size_and_type)
304
378
  [type, size]
305
379
  end
@@ -314,7 +388,7 @@ module Thrift
314
388
  @bool_value = nil
315
389
  bv
316
390
  else
317
- read_byte() == CompactTypes::BOOLEAN_TRUE
391
+ read_byte == CompactTypes::BOOLEAN_TRUE
318
392
  end
319
393
  end
320
394
 
@@ -327,21 +401,21 @@ module Thrift
327
401
  end
328
402
 
329
403
  def read_i16
330
- zig_zag_to_int(read_varint32())
404
+ value = zig_zag_to_int(read_varint32) & 0xffff
405
+ value > I16_MAX ? value - 0x10000 : value
331
406
  end
332
407
 
333
408
  def read_i32
334
- zig_zag_to_int(read_varint32())
409
+ zig_zag_to_int(read_varint32)
335
410
  end
336
411
 
337
412
  def read_i64
338
- zig_zag_to_long(read_varint64())
413
+ zig_zag_to_long(read_varint64 & 0xffffffffffffffff)
339
414
  end
340
415
 
341
416
  def read_double
342
417
  trans.read_into_buffer(@rbuf, 8)
343
- val = @rbuf.reverse.unpack('G').first
344
- val
418
+ @rbuf.reverse.unpack1("G")
345
419
  end
346
420
 
347
421
  def read_string
@@ -350,16 +424,24 @@ module Thrift
350
424
  end
351
425
 
352
426
  def read_binary
353
- 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)
354
432
  trans.read_all(size)
355
433
  end
356
434
 
435
+ def skip_string
436
+ read_binary
437
+ end
438
+
357
439
  def read_uuid
358
440
  UUID.uuid_from_bytes(trans.read_all(16))
359
441
  end
360
442
 
361
443
  def to_s
362
- "compact(#{super.to_s})"
444
+ "compact(#{super})"
363
445
  end
364
446
 
365
447
  private
@@ -369,60 +451,84 @@ module Thrift
369
451
  # the wire differ only by the type indicator.
370
452
  #
371
453
  def write_collection_begin(elem_type, size)
454
+ size = validate_size(size)
455
+ compact_type = CompactTypes.get_compact_type(elem_type)
372
456
  if size <= 14
373
- write_byte(size << 4 | CompactTypes.get_compact_type(elem_type))
457
+ write_byte_direct((size << 4) | compact_type)
374
458
  else
375
- write_byte(0xf0 | CompactTypes.get_compact_type(elem_type))
459
+ write_byte_direct(0xf0 | compact_type)
376
460
  write_varint32(size)
377
461
  end
378
462
  end
379
463
 
464
+ def write_byte_direct(byte)
465
+ @trans.write([byte].pack("C"))
466
+ end
467
+
380
468
  def write_varint32(n)
381
- # int idx = 0;
382
- while true
383
- if (n & ~0x7F) == 0
384
- # i32buf[idx++] = (byte)n;
385
- write_byte(n)
386
- break
387
- # return;
388
- else
389
- # i32buf[idx++] = (byte)((n & 0x7F) | 0x80);
390
- write_byte((n & 0x7F) | 0x80)
391
- n = n >> 7
392
- end
469
+ if (n & ~0x7F) == 0
470
+ write_byte_direct(n)
471
+ return
393
472
  end
394
- # 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)
395
481
  end
396
482
 
397
483
  SEVEN_BIT_MASK = 0x7F
398
484
  EVERYTHING_ELSE_MASK = ~SEVEN_BIT_MASK
399
485
 
400
486
  def write_varint64(n)
401
- while true
402
- if (n & EVERYTHING_ELSE_MASK) == 0 # TODO need to find a way to make this into a long...
403
- write_byte(n)
404
- break
405
- else
406
- write_byte((n & SEVEN_BIT_MASK) | 0x80)
407
- n >>= 7
408
- 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
409
496
  end
497
+ buffer << n
498
+ @trans.write(buffer)
410
499
  end
411
500
 
412
- def read_varint32()
413
- read_varint64()
501
+ def read_varint32
502
+ shift = 0
503
+ result = 0
504
+ VARINT32_PREFIX_BYTES.times do
505
+ b = read_byte
506
+ result |= (b & 0x7f) << shift
507
+ return result if (b & 0x80) != 0x80
508
+ shift += 7
509
+ end
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)
414
520
  end
415
521
 
416
- def read_varint64()
522
+ def read_varint64
417
523
  shift = 0
418
524
  result = 0
419
- while true
420
- b = read_byte()
525
+ MAX_VARINT_BYTES.times do
526
+ b = read_byte
421
527
  result |= (b & 0x7f) << shift
422
- break if (b & 0x80) != 0x80
528
+ return result if (b & 0x80) != 0x80
423
529
  shift += 7
424
530
  end
425
- result
531
+ raise ProtocolException.new(ProtocolException::INVALID_DATA, "Variable-length int over 10 bytes.")
426
532
  end
427
533
 
428
534
  def int_to_zig_zag(n)
@@ -443,11 +549,17 @@ module Thrift
443
549
  end
444
550
 
445
551
  def message_seqid_to_varint32(seqid)
446
- if seqid < -(2**31) || seqid > (2**31) - 1
447
- 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"
448
559
  end
560
+ raise RangeError if size < 0 || size > I32_MAX
449
561
 
450
- seqid < 0 ? seqid + (2**32) : seqid
562
+ size
451
563
  end
452
564
 
453
565
  def message_seqid_from_varint32(seqid)
@@ -456,8 +568,12 @@ module Thrift
456
568
  end
457
569
 
458
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
+
459
575
  def get_protocol(trans)
460
- CompactProtocol.new(trans)
576
+ CompactProtocol.new(trans, max_string_size: @max_string_size)
461
577
  end
462
578
 
463
579
  def to_s
@@ -1,4 +1,5 @@
1
1
  # encoding: ascii-8bit
2
+ # frozen_string_literal: true
2
3
  #
3
4
  # Licensed to the Apache Software Foundation (ASF) under one
4
5
  # or more contributor license agreements. See the NOTICE file
@@ -177,8 +178,9 @@ module Thrift
177
178
  @header_transport.reset_protocol
178
179
  reset_protocol_if_needed
179
180
  rescue ProtocolException => ex
181
+ use_default_protocol
180
182
  app_ex = ApplicationException.new(ApplicationException::INVALID_PROTOCOL, ex.message)
181
- write_message_begin("", MessageTypes::EXCEPTION, 0)
183
+ write_message_begin("", MessageTypes::EXCEPTION, @header_transport.sequence_id)
182
184
  app_ex.write(self)
183
185
  write_message_end
184
186
  @header_transport.flush
@@ -263,12 +265,16 @@ module Thrift
263
265
  @protocol.read_binary
264
266
  end
265
267
 
268
+ def skip_string
269
+ @protocol.skip_string
270
+ end
271
+
266
272
  def read_uuid
267
273
  @protocol.read_uuid
268
274
  end
269
275
 
270
276
  def to_s
271
- "header(#{@protocol.to_s})"
277
+ "header(#{@protocol})"
272
278
  end
273
279
 
274
280
  private
@@ -282,6 +288,12 @@ module Thrift
282
288
  end
283
289
  end
284
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
+
285
297
  # Creates a protocol instance based on protocol ID
286
298
  def create_protocol(protocol_id)
287
299
  case protocol_id
@@ -292,7 +304,7 @@ module Thrift
292
304
  else
293
305
  raise ProtocolException.new(
294
306
  ProtocolException::INVALID_DATA,
295
- "Unknown protocol ID: #{protocol_id}"
307
+ "Unknown protocol ID: #{protocol_id}",
296
308
  )
297
309
  end
298
310
  end