thrift 0.22.0 → 0.24.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 (119) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +235 -17
  3. data/benchmark/benchmark.rb +23 -8
  4. data/benchmark/client.rb +50 -6
  5. data/benchmark/server.rb +46 -7
  6. data/benchmark/thin_server.rb +2 -0
  7. data/ext/binary_protocol_accelerated.c +154 -42
  8. data/ext/bytes.c +14 -0
  9. data/ext/compact_protocol.c +138 -45
  10. data/ext/constants.h +12 -0
  11. data/ext/extconf.rb +17 -8
  12. data/ext/memory_buffer.c +44 -7
  13. data/ext/protocol.c +29 -0
  14. data/ext/protocol.h +35 -0
  15. data/ext/struct.c +48 -17
  16. data/ext/thrift_native.c +28 -3
  17. data/lib/thrift/bytes.rb +70 -100
  18. data/lib/thrift/client.rb +54 -13
  19. data/lib/thrift/exceptions.rb +6 -5
  20. data/lib/thrift/multiplexed_processor.rb +20 -10
  21. data/lib/thrift/processor.rb +7 -6
  22. data/lib/thrift/protocol/base_protocol.rb +52 -21
  23. data/lib/thrift/protocol/binary_protocol.rb +65 -20
  24. data/lib/thrift/protocol/binary_protocol_accelerated.rb +6 -5
  25. data/lib/thrift/protocol/compact_protocol.rb +76 -41
  26. data/lib/thrift/protocol/header_protocol.rb +321 -0
  27. data/lib/thrift/protocol/json_protocol.rb +44 -27
  28. data/lib/thrift/protocol/multiplexed_protocol.rb +6 -5
  29. data/lib/thrift/protocol/protocol_decorator.rb +13 -4
  30. data/lib/thrift/serializer/deserializer.rb +6 -5
  31. data/lib/thrift/serializer/serializer.rb +5 -5
  32. data/lib/thrift/server/base_server.rb +5 -4
  33. data/lib/thrift/server/mongrel_http_server.rb +7 -6
  34. data/lib/thrift/server/nonblocking_server.rb +35 -9
  35. data/lib/thrift/server/simple_server.rb +13 -5
  36. data/lib/thrift/server/thin_http_server.rb +4 -3
  37. data/lib/thrift/server/thread_pool_server.rb +7 -6
  38. data/lib/thrift/server/threaded_server.rb +13 -5
  39. data/lib/thrift/struct.rb +12 -11
  40. data/lib/thrift/struct_union.rb +14 -9
  41. data/lib/thrift/thrift_native.rb +3 -2
  42. data/lib/thrift/transport/base_server_transport.rb +8 -5
  43. data/lib/thrift/transport/base_transport.rb +18 -14
  44. data/lib/thrift/transport/buffered_transport.rb +7 -6
  45. data/lib/thrift/transport/framed_transport.rb +8 -7
  46. data/lib/thrift/transport/header_transport.rb +562 -0
  47. data/lib/thrift/transport/http_client_transport.rb +2 -1
  48. data/lib/thrift/transport/io_stream_transport.rb +4 -3
  49. data/lib/thrift/transport/memory_buffer_transport.rb +13 -6
  50. data/lib/thrift/transport/server_socket.rb +14 -8
  51. data/lib/thrift/transport/socket.rb +126 -60
  52. data/lib/thrift/transport/ssl_server_socket.rb +4 -3
  53. data/lib/thrift/transport/ssl_socket.rb +45 -13
  54. data/lib/thrift/transport/unix_server_socket.rb +9 -5
  55. data/lib/thrift/transport/unix_socket.rb +7 -6
  56. data/lib/thrift/types.rb +10 -6
  57. data/lib/thrift/union.rb +15 -8
  58. data/lib/thrift/uuid.rb +50 -0
  59. data/lib/thrift.rb +4 -1
  60. data/spec/ThriftSpec.thrift +21 -1
  61. data/spec/base_protocol_spec.rb +21 -2
  62. data/spec/base_transport_spec.rb +48 -8
  63. data/spec/binary_protocol_accelerated_spec.rb +1 -0
  64. data/spec/binary_protocol_spec.rb +1 -2
  65. data/spec/binary_protocol_spec_shared.rb +206 -155
  66. data/spec/bytes_spec.rb +71 -114
  67. data/spec/client_spec.rb +86 -19
  68. data/spec/compact_protocol_spec.rb +153 -16
  69. data/spec/constants_demo_spec.rb +102 -0
  70. data/spec/exception_spec.rb +1 -1
  71. data/spec/flat_spec.rb +1 -0
  72. data/spec/header_protocol_spec.rb +476 -0
  73. data/spec/header_transport_spec.rb +431 -0
  74. data/spec/http_client_spec.rb +5 -6
  75. data/spec/json_protocol_spec.rb +69 -47
  76. data/spec/multiplexed_processor_spec.rb +75 -0
  77. data/spec/namespaced_spec.rb +1 -1
  78. data/spec/nonblocking_server_spec.rb +174 -8
  79. data/spec/processor_spec.rb +1 -1
  80. data/spec/recursion_depth_spec.rb +223 -0
  81. data/spec/serializer_spec.rb +1 -1
  82. data/spec/server_socket_spec.rb +38 -1
  83. data/spec/server_spec.rb +60 -9
  84. data/spec/socket_spec.rb +119 -13
  85. data/spec/socket_spec_shared.rb +73 -9
  86. data/spec/spec_helper.rb +2 -1
  87. data/spec/ssl_server_socket_spec.rb +52 -1
  88. data/spec/ssl_socket_spec.rb +181 -11
  89. data/spec/struct_nested_containers_spec.rb +2 -2
  90. data/spec/struct_spec.rb +114 -9
  91. data/spec/support/header_protocol_helper.rb +55 -0
  92. data/spec/thin_http_server_spec.rb +4 -18
  93. data/spec/types_spec.rb +26 -26
  94. data/spec/union_spec.rb +70 -11
  95. data/spec/unix_socket_spec.rb +17 -2
  96. data/spec/uuid_validation_spec.rb +239 -0
  97. data/test/fuzz/Makefile +779 -0
  98. data/test/fuzz/Makefile.am +173 -0
  99. data/test/fuzz/Makefile.in +775 -0
  100. data/test/fuzz/README.md +149 -0
  101. data/test/fuzz/fuzz_common.rb +96 -0
  102. data/{lib/thrift/core_ext.rb → test/fuzz/fuzz_parse_binary_protocol.rb} +4 -4
  103. data/{lib/thrift/core_ext/fixnum.rb → test/fuzz/fuzz_parse_binary_protocol_accelerated.rb} +7 -13
  104. data/test/fuzz/fuzz_parse_binary_protocol_accelerated_harness.rb +23 -0
  105. data/test/fuzz/fuzz_parse_binary_protocol_harness.rb +23 -0
  106. data/test/fuzz/fuzz_parse_compact_protocol.rb +23 -0
  107. data/test/fuzz/fuzz_parse_compact_protocol_harness.rb +23 -0
  108. data/test/fuzz/fuzz_parse_json_protocol.rb +23 -0
  109. data/test/fuzz/fuzz_parse_json_protocol_harness.rb +23 -0
  110. data/test/fuzz/fuzz_roundtrip_binary_protocol.rb +23 -0
  111. data/test/fuzz/fuzz_roundtrip_binary_protocol_accelerated.rb +23 -0
  112. data/test/fuzz/fuzz_roundtrip_binary_protocol_accelerated_harness.rb +23 -0
  113. data/test/fuzz/fuzz_roundtrip_binary_protocol_harness.rb +23 -0
  114. data/test/fuzz/fuzz_roundtrip_compact_protocol.rb +23 -0
  115. data/test/fuzz/fuzz_roundtrip_compact_protocol_harness.rb +23 -0
  116. data/test/fuzz/fuzz_roundtrip_json_protocol.rb +23 -0
  117. data/test/fuzz/fuzz_roundtrip_json_protocol_harness.rb +23 -0
  118. data/test/fuzz/fuzz_tracer.rb +29 -0
  119. metadata +105 -70
@@ -1,4 +1,5 @@
1
- #
1
+ # frozen_string_literal: true
2
+ #
2
3
  # Licensed to the Apache Software Foundation (ASF) under one
3
4
  # or more contributor license agreements. See the NOTICE file
4
5
  # distributed with this work for additional information
@@ -6,16 +7,16 @@
6
7
  # to you under the Apache License, Version 2.0 (the
7
8
  # "License"); you may not use this file except in compliance
8
9
  # with the License. You may obtain a copy of the License at
9
- #
10
+ #
10
11
  # http://www.apache.org/licenses/LICENSE-2.0
11
- #
12
+ #
12
13
  # Unless required by applicable law or agreed to in writing,
13
14
  # software distributed under the License is distributed on an
14
15
  # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15
16
  # KIND, either express or implied. See the License for the
16
17
  # specific language governing permissions and limitations
17
18
  # under the License.
18
- #
19
+ #
19
20
 
20
21
  module Thrift
21
22
  class CompactProtocol < BaseProtocol
@@ -26,12 +27,14 @@ module Thrift
26
27
  TYPE_MASK = 0xE0
27
28
  TYPE_BITS = 0x07
28
29
  TYPE_SHIFT_AMOUNT = 5
30
+ MAX_VARINT32_BYTES = 5 # ceil(32/7); matches protobuf wire format
31
+ MAX_VARINT_BYTES = 10 # ceil(64/7); matches protobuf wire format
29
32
 
30
- TSTOP = ["", Types::STOP, 0]
33
+ TSTOP = [nil, Types::STOP, 0]
31
34
 
32
- #
35
+ #
33
36
  # All of the on-wire type codes.
34
- #
37
+ #
35
38
  class CompactTypes
36
39
  BOOLEAN_TRUE = 0x01
37
40
  BOOLEAN_FALSE = 0x02
@@ -45,11 +48,12 @@ module Thrift
45
48
  SET = 0x0A
46
49
  MAP = 0x0B
47
50
  STRUCT = 0x0C
48
-
51
+ UUID = 0x0D
52
+
49
53
  def self.is_bool_type?(b)
50
54
  (b & 0x0f) == BOOLEAN_TRUE || (b & 0x0f) == BOOLEAN_FALSE
51
55
  end
52
-
56
+
53
57
  COMPACT_TO_TTYPE = {
54
58
  Types::STOP => Types::STOP,
55
59
  BOOLEAN_FALSE => Types::BOOL,
@@ -63,7 +67,8 @@ module Thrift
63
67
  LIST => Types::LIST,
64
68
  SET => Types::SET,
65
69
  MAP => Types::MAP,
66
- STRUCT => Types::STRUCT
70
+ STRUCT => Types::STRUCT,
71
+ UUID => Types::UUID
67
72
  }
68
73
 
69
74
  TTYPE_TO_COMPACT = {
@@ -78,15 +83,16 @@ module Thrift
78
83
  Types::LIST => LIST,
79
84
  Types::SET => SET,
80
85
  Types::MAP => MAP,
81
- Types::STRUCT => STRUCT
86
+ Types::STRUCT => STRUCT,
87
+ Types::UUID => UUID
82
88
  }
83
-
89
+
84
90
  def self.get_ttype(compact_type)
85
91
  val = COMPACT_TO_TTYPE[compact_type & 0x0f]
86
92
  raise "don't know what type: #{compact_type & 0x0f}" unless val
87
93
  val
88
94
  end
89
-
95
+
90
96
  def self.get_compact_type(ttype)
91
97
  val = TTYPE_TO_COMPACT[ttype]
92
98
  raise "don't know what type: #{ttype & 0x0f}" unless val
@@ -107,7 +113,7 @@ module Thrift
107
113
  def write_message_begin(name, type, seqid)
108
114
  write_byte(PROTOCOL_ID)
109
115
  write_byte((VERSION & VERSION_MASK) | ((type << TYPE_SHIFT_AMOUNT) & TYPE_MASK))
110
- write_varint32(seqid)
116
+ write_varint32(message_seqid_to_varint32(seqid))
111
117
  write_string(name)
112
118
  nil
113
119
  end
@@ -132,14 +138,14 @@ module Thrift
132
138
  nil
133
139
  end
134
140
 
135
- #
136
- # The workhorse of writeFieldBegin. It has the option of doing a
137
- # 'type override' of the type header. This is used specifically in the
141
+ #
142
+ # The workhorse of writeFieldBegin. It has the option of doing a
143
+ # 'type override' of the type header. This is used specifically in the
138
144
  # boolean field case.
139
- #
140
- def write_field_begin_internal(type, id, type_override=nil)
145
+ #
146
+ def write_field_begin_internal(type, id, type_override = nil)
141
147
  last_id = @last_field.pop
142
-
148
+
143
149
  # if there's a type override, use that.
144
150
  typeToWrite = type_override || CompactTypes.get_compact_type(type)
145
151
 
@@ -220,20 +226,25 @@ module Thrift
220
226
  @trans.write(buf)
221
227
  end
222
228
 
229
+ def write_uuid(uuid)
230
+ UUID.validate_uuid!(uuid)
231
+ trans.write(UUID.uuid_bytes(uuid))
232
+ end
233
+
223
234
  def read_message_begin
224
235
  protocol_id = read_byte()
225
236
  if protocol_id != PROTOCOL_ID
226
237
  raise ProtocolException.new("Expected protocol id #{PROTOCOL_ID} but got #{protocol_id}")
227
238
  end
228
-
239
+
229
240
  version_and_type = read_byte()
230
241
  version = version_and_type & VERSION_MASK
231
242
  if (version != VERSION)
232
243
  raise ProtocolException.new("Expected version #{VERSION} but got #{version}");
233
244
  end
234
-
245
+
235
246
  type = (version_and_type >> TYPE_SHIFT_AMOUNT) & TYPE_BITS
236
- seqid = read_varint32()
247
+ seqid = message_seqid_from_varint32(read_varint32())
237
248
  messageName = read_string()
238
249
  [messageName, type, seqid]
239
250
  end
@@ -276,7 +287,7 @@ module Thrift
276
287
 
277
288
  # push the new field onto the field stack so we can keep the deltas going.
278
289
  @last_field.push(field_id)
279
- ["", CompactTypes.get_ttype(type & 0x0f), field_id]
290
+ [nil, CompactTypes.get_ttype(type & 0x0f), field_id]
280
291
  end
281
292
  end
282
293
 
@@ -345,17 +356,21 @@ module Thrift
345
356
  size = read_varint32()
346
357
  trans.read_all(size)
347
358
  end
348
-
359
+
360
+ def read_uuid
361
+ UUID.uuid_from_bytes(trans.read_all(16))
362
+ end
363
+
349
364
  def to_s
350
365
  "compact(#{super.to_s})"
351
366
  end
352
367
 
353
368
  private
354
-
355
- #
356
- # Abstract method for writing the start of lists and sets. List and sets on
369
+
370
+ #
371
+ # Abstract method for writing the start of lists and sets. List and sets on
357
372
  # the wire differ only by the type indicator.
358
- #
373
+ #
359
374
  def write_collection_begin(elem_type, size)
360
375
  if size <= 14
361
376
  write_byte(size << 4 | CompactTypes.get_compact_type(elem_type))
@@ -387,7 +402,7 @@ module Thrift
387
402
 
388
403
  def write_varint64(n)
389
404
  while true
390
- if (n & EVERYTHING_ELSE_MASK) == 0 #TODO need to find a way to make this into a long...
405
+ if (n & EVERYTHING_ELSE_MASK) == 0 # TODO need to find a way to make this into a long...
391
406
  write_byte(n)
392
407
  break
393
408
  else
@@ -396,46 +411,66 @@ module Thrift
396
411
  end
397
412
  end
398
413
  end
399
-
414
+
400
415
  def read_varint32()
401
- read_varint64()
416
+ shift = 0
417
+ result = 0
418
+ MAX_VARINT32_BYTES.times do
419
+ b = read_byte()
420
+ result |= (b & 0x7f) << shift
421
+ return result if (b & 0x80) != 0x80
422
+ shift += 7
423
+ end
424
+ raise ProtocolException.new(ProtocolException::INVALID_DATA, 'Variable-length int over 5 bytes.')
402
425
  end
403
-
426
+
404
427
  def read_varint64()
405
428
  shift = 0
406
429
  result = 0
407
- while true
430
+ MAX_VARINT_BYTES.times do
408
431
  b = read_byte()
409
432
  result |= (b & 0x7f) << shift
410
- break if (b & 0x80) != 0x80
433
+ return result if (b & 0x80) != 0x80
411
434
  shift += 7
412
435
  end
413
- result
436
+ raise ProtocolException.new(ProtocolException::INVALID_DATA, 'Variable-length int over 10 bytes.')
414
437
  end
415
-
438
+
416
439
  def int_to_zig_zag(n)
417
440
  (n << 1) ^ (n >> 31)
418
441
  end
419
-
442
+
420
443
  def long_to_zig_zag(l)
421
444
  # puts "zz encoded #{l} to #{(l << 1) ^ (l >> 63)}"
422
445
  (l << 1) ^ (l >> 63)
423
446
  end
424
-
447
+
425
448
  def zig_zag_to_int(n)
426
449
  (n >> 1) ^ -(n & 1)
427
450
  end
428
-
451
+
429
452
  def zig_zag_to_long(n)
430
453
  (n >> 1) ^ -(n & 1)
431
454
  end
455
+
456
+ def message_seqid_to_varint32(seqid)
457
+ if seqid < -(2**31) || seqid > (2**31) - 1
458
+ raise RangeError, "seqid must be a signed int32"
459
+ end
460
+
461
+ seqid < 0 ? seqid + (2**32) : seqid
462
+ end
463
+
464
+ def message_seqid_from_varint32(seqid)
465
+ seqid > 0x7fffffff ? seqid - (2**32) : seqid
466
+ end
432
467
  end
433
468
 
434
469
  class CompactProtocolFactory < BaseProtocolFactory
435
470
  def get_protocol(trans)
436
471
  CompactProtocol.new(trans)
437
472
  end
438
-
473
+
439
474
  def to_s
440
475
  "compact"
441
476
  end
@@ -0,0 +1,321 @@
1
+ # encoding: ascii-8bit
2
+ # frozen_string_literal: true
3
+ #
4
+ # Licensed to the Apache Software Foundation (ASF) under one
5
+ # or more contributor license agreements. See the NOTICE file
6
+ # distributed with this work for additional information
7
+ # regarding copyright ownership. The ASF licenses this file
8
+ # to you under the Apache License, Version 2.0 (the
9
+ # "License"); you may not use this file except in compliance
10
+ # with the License. You may obtain a copy of the License at
11
+ #
12
+ # http://www.apache.org/licenses/LICENSE-2.0
13
+ #
14
+ # Unless required by applicable law or agreed to in writing,
15
+ # software distributed under the License is distributed on an
16
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17
+ # KIND, either express or implied. See the License for the
18
+ # specific language governing permissions and limitations
19
+ # under the License.
20
+ #
21
+
22
+ module Thrift
23
+ # HeaderProtocol is a protocol that wraps HeaderTransport and delegates
24
+ # to either BinaryProtocol or CompactProtocol based on auto-detection.
25
+ #
26
+ # It provides access to header management (get_headers, set_header, etc.)
27
+ # through the underlying HeaderTransport.
28
+ #
29
+ # Example usage:
30
+ # socket = Thrift::Socket.new('localhost', 9090)
31
+ # protocol = Thrift::HeaderProtocol.new(socket)
32
+ # client = MyService::Client.new(protocol)
33
+ # protocol.trans.open
34
+ # client.some_method()
35
+ # protocol.trans.close
36
+ #
37
+ class HeaderProtocol < BaseProtocol
38
+ # Creates a new HeaderProtocol.
39
+ #
40
+ # @param transport [BaseTransport, HeaderTransport] The transport to wrap.
41
+ # If not already a HeaderTransport, it will be wrapped in one.
42
+ # @param allowed_client_types [Array<Integer>] Allowed client types for auto-detection
43
+ # @param default_protocol [Integer] Default protocol ID (BINARY or COMPACT)
44
+ def initialize(transport, allowed_client_types = nil, default_protocol = HeaderSubprotocolID::COMPACT)
45
+ # Wrap transport in HeaderTransport if not already wrapped
46
+ if transport.is_a?(HeaderTransport)
47
+ @header_transport = transport
48
+ else
49
+ @header_transport = HeaderTransport.new(transport, allowed_client_types, default_protocol)
50
+ end
51
+
52
+ @default_protocol = default_protocol
53
+ @current_protocol_id = default_protocol
54
+
55
+ # Create initial protocol
56
+ @protocol = create_protocol(@current_protocol_id)
57
+ end
58
+
59
+ # Returns the HeaderTransport
60
+ def trans
61
+ @header_transport
62
+ end
63
+
64
+ # Returns headers read from the last message
65
+ def get_headers
66
+ @header_transport.get_headers
67
+ end
68
+
69
+ # Sets a header to be sent with the next message
70
+ def set_header(key, value)
71
+ @header_transport.set_header(key, value)
72
+ end
73
+
74
+ # Clears all write headers
75
+ def clear_headers
76
+ @header_transport.clear_headers
77
+ end
78
+
79
+ # Adds a transform (e.g., ZLIB compression)
80
+ def add_transform(transform_id)
81
+ @header_transport.add_transform(transform_id)
82
+ end
83
+
84
+ # Write methods - delegate to underlying protocol
85
+ def write_message_begin(name, type, seqid)
86
+ @header_transport.sequence_id = seqid
87
+ @protocol.write_message_begin(name, type, seqid)
88
+ end
89
+
90
+ def write_message_end
91
+ @protocol.write_message_end
92
+ end
93
+
94
+ def write_struct_begin(name)
95
+ @protocol.write_struct_begin(name)
96
+ end
97
+
98
+ def write_struct_end
99
+ @protocol.write_struct_end
100
+ end
101
+
102
+ def write_field_begin(name, type, id)
103
+ @protocol.write_field_begin(name, type, id)
104
+ end
105
+
106
+ def write_field_end
107
+ @protocol.write_field_end
108
+ end
109
+
110
+ def write_field_stop
111
+ @protocol.write_field_stop
112
+ end
113
+
114
+ def write_map_begin(ktype, vtype, size)
115
+ @protocol.write_map_begin(ktype, vtype, size)
116
+ end
117
+
118
+ def write_map_end
119
+ @protocol.write_map_end
120
+ end
121
+
122
+ def write_list_begin(etype, size)
123
+ @protocol.write_list_begin(etype, size)
124
+ end
125
+
126
+ def write_list_end
127
+ @protocol.write_list_end
128
+ end
129
+
130
+ def write_set_begin(etype, size)
131
+ @protocol.write_set_begin(etype, size)
132
+ end
133
+
134
+ def write_set_end
135
+ @protocol.write_set_end
136
+ end
137
+
138
+ def write_bool(bool)
139
+ @protocol.write_bool(bool)
140
+ end
141
+
142
+ def write_byte(byte)
143
+ @protocol.write_byte(byte)
144
+ end
145
+
146
+ def write_i16(i16)
147
+ @protocol.write_i16(i16)
148
+ end
149
+
150
+ def write_i32(i32)
151
+ @protocol.write_i32(i32)
152
+ end
153
+
154
+ def write_i64(i64)
155
+ @protocol.write_i64(i64)
156
+ end
157
+
158
+ def write_double(dub)
159
+ @protocol.write_double(dub)
160
+ end
161
+
162
+ def write_string(str)
163
+ @protocol.write_string(str)
164
+ end
165
+
166
+ def write_binary(buf)
167
+ @protocol.write_binary(buf)
168
+ end
169
+
170
+ def write_uuid(uuid)
171
+ @protocol.write_uuid(uuid)
172
+ end
173
+
174
+ # Read methods - delegate to underlying protocol
175
+ # read_message_begin handles protocol switching after detection
176
+ def read_message_begin
177
+ begin
178
+ @header_transport.reset_protocol
179
+ reset_protocol_if_needed
180
+ rescue ProtocolException => ex
181
+ app_ex = ApplicationException.new(ApplicationException::INVALID_PROTOCOL, ex.message)
182
+ write_message_begin("", MessageTypes::EXCEPTION, 0)
183
+ app_ex.write(self)
184
+ write_message_end
185
+ @header_transport.flush
186
+ raise ex
187
+ end
188
+ @protocol.read_message_begin
189
+ end
190
+
191
+ def read_message_end
192
+ @protocol.read_message_end
193
+ end
194
+
195
+ def read_struct_begin
196
+ @protocol.read_struct_begin
197
+ end
198
+
199
+ def read_struct_end
200
+ @protocol.read_struct_end
201
+ end
202
+
203
+ def read_field_begin
204
+ @protocol.read_field_begin
205
+ end
206
+
207
+ def read_field_end
208
+ @protocol.read_field_end
209
+ end
210
+
211
+ def read_map_begin
212
+ @protocol.read_map_begin
213
+ end
214
+
215
+ def read_map_end
216
+ @protocol.read_map_end
217
+ end
218
+
219
+ def read_list_begin
220
+ @protocol.read_list_begin
221
+ end
222
+
223
+ def read_list_end
224
+ @protocol.read_list_end
225
+ end
226
+
227
+ def read_set_begin
228
+ @protocol.read_set_begin
229
+ end
230
+
231
+ def read_set_end
232
+ @protocol.read_set_end
233
+ end
234
+
235
+ def read_bool
236
+ @protocol.read_bool
237
+ end
238
+
239
+ def read_byte
240
+ @protocol.read_byte
241
+ end
242
+
243
+ def read_i16
244
+ @protocol.read_i16
245
+ end
246
+
247
+ def read_i32
248
+ @protocol.read_i32
249
+ end
250
+
251
+ def read_i64
252
+ @protocol.read_i64
253
+ end
254
+
255
+ def read_double
256
+ @protocol.read_double
257
+ end
258
+
259
+ def read_string
260
+ @protocol.read_string
261
+ end
262
+
263
+ def read_binary
264
+ @protocol.read_binary
265
+ end
266
+
267
+ def read_uuid
268
+ @protocol.read_uuid
269
+ end
270
+
271
+ def to_s
272
+ "header(#{@protocol.to_s})"
273
+ end
274
+
275
+ private
276
+
277
+ # Checks if the protocol needs to be switched after reading
278
+ def reset_protocol_if_needed
279
+ new_protocol_id = @header_transport.protocol_id
280
+ if new_protocol_id != @current_protocol_id
281
+ @protocol = create_protocol(new_protocol_id)
282
+ @current_protocol_id = new_protocol_id
283
+ end
284
+ end
285
+
286
+ # Creates a protocol instance based on protocol ID
287
+ def create_protocol(protocol_id)
288
+ case protocol_id
289
+ when HeaderSubprotocolID::BINARY
290
+ BinaryProtocol.new(@header_transport)
291
+ when HeaderSubprotocolID::COMPACT
292
+ CompactProtocol.new(@header_transport)
293
+ else
294
+ raise ProtocolException.new(
295
+ ProtocolException::INVALID_DATA,
296
+ "Unknown protocol ID: #{protocol_id}"
297
+ )
298
+ end
299
+ end
300
+ end
301
+
302
+ # Factory for creating HeaderProtocol instances
303
+ class HeaderProtocolFactory < BaseProtocolFactory
304
+ # Creates a new HeaderProtocolFactory.
305
+ #
306
+ # @param allowed_client_types [Array<Integer>] Allowed client types for auto-detection
307
+ # @param default_protocol [Integer] Default protocol ID (BINARY or COMPACT)
308
+ def initialize(allowed_client_types = nil, default_protocol = HeaderSubprotocolID::BINARY)
309
+ @allowed_client_types = allowed_client_types
310
+ @default_protocol = default_protocol
311
+ end
312
+
313
+ def get_protocol(trans)
314
+ HeaderProtocol.new(trans, @allowed_client_types, @default_protocol)
315
+ end
316
+
317
+ def to_s
318
+ "header"
319
+ end
320
+ end
321
+ end