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.
- checksums.yaml +4 -4
- data/README.md +235 -17
- data/benchmark/benchmark.rb +23 -8
- data/benchmark/client.rb +50 -6
- data/benchmark/server.rb +46 -7
- data/benchmark/thin_server.rb +2 -0
- data/ext/binary_protocol_accelerated.c +154 -42
- data/ext/bytes.c +14 -0
- data/ext/compact_protocol.c +138 -45
- data/ext/constants.h +12 -0
- data/ext/extconf.rb +17 -8
- data/ext/memory_buffer.c +44 -7
- data/ext/protocol.c +29 -0
- data/ext/protocol.h +35 -0
- data/ext/struct.c +48 -17
- data/ext/thrift_native.c +28 -3
- data/lib/thrift/bytes.rb +70 -100
- data/lib/thrift/client.rb +54 -13
- data/lib/thrift/exceptions.rb +6 -5
- data/lib/thrift/multiplexed_processor.rb +20 -10
- data/lib/thrift/processor.rb +7 -6
- data/lib/thrift/protocol/base_protocol.rb +52 -21
- data/lib/thrift/protocol/binary_protocol.rb +65 -20
- data/lib/thrift/protocol/binary_protocol_accelerated.rb +6 -5
- data/lib/thrift/protocol/compact_protocol.rb +76 -41
- data/lib/thrift/protocol/header_protocol.rb +321 -0
- data/lib/thrift/protocol/json_protocol.rb +44 -27
- data/lib/thrift/protocol/multiplexed_protocol.rb +6 -5
- data/lib/thrift/protocol/protocol_decorator.rb +13 -4
- data/lib/thrift/serializer/deserializer.rb +6 -5
- data/lib/thrift/serializer/serializer.rb +5 -5
- data/lib/thrift/server/base_server.rb +5 -4
- data/lib/thrift/server/mongrel_http_server.rb +7 -6
- data/lib/thrift/server/nonblocking_server.rb +35 -9
- data/lib/thrift/server/simple_server.rb +13 -5
- data/lib/thrift/server/thin_http_server.rb +4 -3
- data/lib/thrift/server/thread_pool_server.rb +7 -6
- data/lib/thrift/server/threaded_server.rb +13 -5
- data/lib/thrift/struct.rb +12 -11
- data/lib/thrift/struct_union.rb +14 -9
- data/lib/thrift/thrift_native.rb +3 -2
- data/lib/thrift/transport/base_server_transport.rb +8 -5
- data/lib/thrift/transport/base_transport.rb +18 -14
- data/lib/thrift/transport/buffered_transport.rb +7 -6
- data/lib/thrift/transport/framed_transport.rb +8 -7
- data/lib/thrift/transport/header_transport.rb +562 -0
- data/lib/thrift/transport/http_client_transport.rb +2 -1
- data/lib/thrift/transport/io_stream_transport.rb +4 -3
- data/lib/thrift/transport/memory_buffer_transport.rb +13 -6
- data/lib/thrift/transport/server_socket.rb +14 -8
- data/lib/thrift/transport/socket.rb +126 -60
- data/lib/thrift/transport/ssl_server_socket.rb +4 -3
- data/lib/thrift/transport/ssl_socket.rb +45 -13
- data/lib/thrift/transport/unix_server_socket.rb +9 -5
- data/lib/thrift/transport/unix_socket.rb +7 -6
- data/lib/thrift/types.rb +10 -6
- data/lib/thrift/union.rb +15 -8
- data/lib/thrift/uuid.rb +50 -0
- data/lib/thrift.rb +4 -1
- data/spec/ThriftSpec.thrift +21 -1
- data/spec/base_protocol_spec.rb +21 -2
- data/spec/base_transport_spec.rb +48 -8
- data/spec/binary_protocol_accelerated_spec.rb +1 -0
- data/spec/binary_protocol_spec.rb +1 -2
- data/spec/binary_protocol_spec_shared.rb +206 -155
- data/spec/bytes_spec.rb +71 -114
- data/spec/client_spec.rb +86 -19
- data/spec/compact_protocol_spec.rb +153 -16
- data/spec/constants_demo_spec.rb +102 -0
- data/spec/exception_spec.rb +1 -1
- data/spec/flat_spec.rb +1 -0
- data/spec/header_protocol_spec.rb +476 -0
- data/spec/header_transport_spec.rb +431 -0
- data/spec/http_client_spec.rb +5 -6
- data/spec/json_protocol_spec.rb +69 -47
- data/spec/multiplexed_processor_spec.rb +75 -0
- data/spec/namespaced_spec.rb +1 -1
- data/spec/nonblocking_server_spec.rb +174 -8
- data/spec/processor_spec.rb +1 -1
- data/spec/recursion_depth_spec.rb +223 -0
- data/spec/serializer_spec.rb +1 -1
- data/spec/server_socket_spec.rb +38 -1
- data/spec/server_spec.rb +60 -9
- data/spec/socket_spec.rb +119 -13
- data/spec/socket_spec_shared.rb +73 -9
- data/spec/spec_helper.rb +2 -1
- data/spec/ssl_server_socket_spec.rb +52 -1
- data/spec/ssl_socket_spec.rb +181 -11
- data/spec/struct_nested_containers_spec.rb +2 -2
- data/spec/struct_spec.rb +114 -9
- data/spec/support/header_protocol_helper.rb +55 -0
- data/spec/thin_http_server_spec.rb +4 -18
- data/spec/types_spec.rb +26 -26
- data/spec/union_spec.rb +70 -11
- data/spec/unix_socket_spec.rb +17 -2
- data/spec/uuid_validation_spec.rb +239 -0
- data/test/fuzz/Makefile +779 -0
- data/test/fuzz/Makefile.am +173 -0
- data/test/fuzz/Makefile.in +775 -0
- data/test/fuzz/README.md +149 -0
- data/test/fuzz/fuzz_common.rb +96 -0
- data/{lib/thrift/core_ext.rb → test/fuzz/fuzz_parse_binary_protocol.rb} +4 -4
- data/{lib/thrift/core_ext/fixnum.rb → test/fuzz/fuzz_parse_binary_protocol_accelerated.rb} +7 -13
- data/test/fuzz/fuzz_parse_binary_protocol_accelerated_harness.rb +23 -0
- data/test/fuzz/fuzz_parse_binary_protocol_harness.rb +23 -0
- data/test/fuzz/fuzz_parse_compact_protocol.rb +23 -0
- data/test/fuzz/fuzz_parse_compact_protocol_harness.rb +23 -0
- data/test/fuzz/fuzz_parse_json_protocol.rb +23 -0
- data/test/fuzz/fuzz_parse_json_protocol_harness.rb +23 -0
- data/test/fuzz/fuzz_roundtrip_binary_protocol.rb +23 -0
- data/test/fuzz/fuzz_roundtrip_binary_protocol_accelerated.rb +23 -0
- data/test/fuzz/fuzz_roundtrip_binary_protocol_accelerated_harness.rb +23 -0
- data/test/fuzz/fuzz_roundtrip_binary_protocol_harness.rb +23 -0
- data/test/fuzz/fuzz_roundtrip_compact_protocol.rb +23 -0
- data/test/fuzz/fuzz_roundtrip_compact_protocol_harness.rb +23 -0
- data/test/fuzz/fuzz_roundtrip_json_protocol.rb +23 -0
- data/test/fuzz/fuzz_roundtrip_json_protocol_harness.rb +23 -0
- data/test/fuzz/fuzz_tracer.rb +29 -0
- 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 = [
|
|
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
|
-
[
|
|
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
|
-
|
|
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
|
-
|
|
430
|
+
MAX_VARINT_BYTES.times do
|
|
408
431
|
b = read_byte()
|
|
409
432
|
result |= (b & 0x7f) << shift
|
|
410
|
-
|
|
433
|
+
return result if (b & 0x80) != 0x80
|
|
411
434
|
shift += 7
|
|
412
435
|
end
|
|
413
|
-
|
|
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
|