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
|
@@ -0,0 +1,431 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
#
|
|
3
|
+
# Licensed to the Apache Software Foundation (ASF) under one
|
|
4
|
+
# or more contributor license agreements. See the NOTICE file
|
|
5
|
+
# distributed with this work for additional information
|
|
6
|
+
# regarding copyright ownership. The ASF licenses this file
|
|
7
|
+
# to you under the Apache License, Version 2.0 (the
|
|
8
|
+
# "License"); you may not use this file except in compliance
|
|
9
|
+
# with the License. You may obtain a copy of the License at
|
|
10
|
+
#
|
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
#
|
|
13
|
+
# Unless required by applicable law or agreed to in writing,
|
|
14
|
+
# software distributed under the License is distributed on an
|
|
15
|
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
16
|
+
# KIND, either express or implied. See the License for the
|
|
17
|
+
# specific language governing permissions and limitations
|
|
18
|
+
# under the License.
|
|
19
|
+
#
|
|
20
|
+
|
|
21
|
+
require 'spec_helper'
|
|
22
|
+
require_relative 'support/header_protocol_helper'
|
|
23
|
+
|
|
24
|
+
describe 'HeaderTransport' do
|
|
25
|
+
include HeaderProtocolHelper
|
|
26
|
+
|
|
27
|
+
describe Thrift::HeaderClientType do
|
|
28
|
+
it "should define client type constants" do
|
|
29
|
+
expect(Thrift::HeaderClientType::HEADERS).to eq(0x00)
|
|
30
|
+
expect(Thrift::HeaderClientType::FRAMED_BINARY).to eq(0x01)
|
|
31
|
+
expect(Thrift::HeaderClientType::UNFRAMED_BINARY).to eq(0x02)
|
|
32
|
+
expect(Thrift::HeaderClientType::FRAMED_COMPACT).to eq(0x03)
|
|
33
|
+
expect(Thrift::HeaderClientType::UNFRAMED_COMPACT).to eq(0x04)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
describe Thrift::HeaderSubprotocolID do
|
|
38
|
+
it "should define protocol ID constants" do
|
|
39
|
+
expect(Thrift::HeaderSubprotocolID::BINARY).to eq(0x00)
|
|
40
|
+
expect(Thrift::HeaderSubprotocolID::COMPACT).to eq(0x02)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
describe Thrift::HeaderTransformID do
|
|
45
|
+
it "should define transform ID constants" do
|
|
46
|
+
expect(Thrift::HeaderTransformID::ZLIB).to eq(0x01)
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
describe Thrift::HeaderTransport do
|
|
51
|
+
before(:each) do
|
|
52
|
+
@underlying = Thrift::MemoryBufferTransport.new
|
|
53
|
+
@trans = Thrift::HeaderTransport.new(@underlying)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
it "should provide a to_s that describes the encapsulation" do
|
|
57
|
+
expect(@trans.to_s).to eq("header(memory)")
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
it "should pass through open?/open/close" do
|
|
61
|
+
mock_transport = double("Transport")
|
|
62
|
+
expect(mock_transport).to receive(:open?).and_return(true)
|
|
63
|
+
expect(mock_transport).to receive(:open).and_return(nil)
|
|
64
|
+
expect(mock_transport).to receive(:close).and_return(nil)
|
|
65
|
+
|
|
66
|
+
trans = Thrift::HeaderTransport.new(mock_transport)
|
|
67
|
+
expect(trans.open?).to be true
|
|
68
|
+
trans.open
|
|
69
|
+
trans.close
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
describe "header management" do
|
|
73
|
+
it "should allow setting and getting headers" do
|
|
74
|
+
@trans.set_header("key1", "value1")
|
|
75
|
+
@trans.set_header("key2", "value2")
|
|
76
|
+
# Headers aren't read until we receive data, so write and read back
|
|
77
|
+
expect(@trans.get_headers).to eq({})
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
it "should clear headers" do
|
|
81
|
+
@trans.set_header("key1", "value1")
|
|
82
|
+
@trans.clear_headers
|
|
83
|
+
# Write and flush to verify headers were cleared
|
|
84
|
+
@trans.write("test")
|
|
85
|
+
@trans.flush
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
it "should add transforms" do
|
|
89
|
+
expect { @trans.add_transform(Thrift::HeaderTransformID::ZLIB) }.not_to raise_error
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
it "should reject unknown transforms" do
|
|
93
|
+
expect { @trans.add_transform(999) }.to raise_error(Thrift::TransportException)
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
describe "write and flush" do
|
|
98
|
+
it "should buffer writes" do
|
|
99
|
+
@trans.write("hello")
|
|
100
|
+
@trans.write(" world")
|
|
101
|
+
expect(@underlying.available).to eq(0)
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
it "should write Header format on flush" do
|
|
105
|
+
@trans.write("test payload")
|
|
106
|
+
@trans.flush
|
|
107
|
+
|
|
108
|
+
# Read back the frame
|
|
109
|
+
data = @underlying.read(@underlying.available)
|
|
110
|
+
|
|
111
|
+
# Should have frame length (4 bytes) + header + payload
|
|
112
|
+
expect(data.bytesize).to be > 16
|
|
113
|
+
|
|
114
|
+
# First 4 bytes are frame length
|
|
115
|
+
frame_size = data[0, 4].unpack('N').first
|
|
116
|
+
expect(frame_size).to eq(data.bytesize - 4)
|
|
117
|
+
|
|
118
|
+
# Next 2 bytes should be header magic
|
|
119
|
+
magic = data[4, 2].unpack('n').first
|
|
120
|
+
expect(magic).to eq(Thrift::HeaderTransport::HEADER_MAGIC)
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
it "should include headers in frame" do
|
|
124
|
+
@trans.set_header("test-key", "test-value")
|
|
125
|
+
@trans.write("payload")
|
|
126
|
+
@trans.flush
|
|
127
|
+
|
|
128
|
+
# Read back and verify it's larger due to headers
|
|
129
|
+
data = @underlying.read(@underlying.available)
|
|
130
|
+
expect(data.bytesize).to be > 30 # Should include header key-value
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
it "should write the configured sequence id into the frame header" do
|
|
134
|
+
@trans.sequence_id = 456
|
|
135
|
+
@trans.write("payload")
|
|
136
|
+
@trans.flush
|
|
137
|
+
|
|
138
|
+
data = @underlying.read(@underlying.available)
|
|
139
|
+
expect(data[8, 4].unpack('N').first).to eq(456)
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
it "should apply ZLIB transform" do
|
|
143
|
+
@trans.add_transform(Thrift::HeaderTransformID::ZLIB)
|
|
144
|
+
original_payload = "a" * 1000 # Compressible data
|
|
145
|
+
@trans.write(original_payload)
|
|
146
|
+
@trans.flush
|
|
147
|
+
|
|
148
|
+
data = @underlying.read(@underlying.available)
|
|
149
|
+
# Compressed frame should be smaller than uncompressed
|
|
150
|
+
expect(data.bytesize).to be < original_payload.bytesize
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
describe "frame size limits" do
|
|
155
|
+
it "should reject payloads larger than max frame size" do
|
|
156
|
+
@trans.set_max_frame_size(4)
|
|
157
|
+
@trans.write("12345")
|
|
158
|
+
expect { @trans.flush }.to raise_error(Thrift::TransportException, /frame that is too large/)
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
describe "decompressed size limits" do
|
|
163
|
+
it "should accept a valid max_decompressed_size" do
|
|
164
|
+
expect { @trans.set_max_decompressed_size(1024) }.not_to raise_error
|
|
165
|
+
expect { @trans.set_max_decompressed_size(Thrift::HeaderTransport::MAX_FRAME_SIZE) }.not_to raise_error
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
it "should reject invalid max_decompressed_size" do
|
|
169
|
+
expect { @trans.set_max_decompressed_size(0) }.to raise_error(ArgumentError)
|
|
170
|
+
expect { @trans.set_max_decompressed_size(-1) }.to raise_error(ArgumentError)
|
|
171
|
+
expect { @trans.set_max_decompressed_size(Thrift::HeaderTransport::MAX_FRAME_SIZE + 1) }.to raise_error(ArgumentError)
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
it "should decompress ZLIB payload within the limit" do
|
|
175
|
+
write_buf = Thrift::MemoryBufferTransport.new
|
|
176
|
+
writer = Thrift::HeaderTransport.new(write_buf)
|
|
177
|
+
writer.add_transform(Thrift::HeaderTransformID::ZLIB)
|
|
178
|
+
writer.write("A" * 1_000)
|
|
179
|
+
writer.flush
|
|
180
|
+
|
|
181
|
+
written_data = write_buf.read(write_buf.available)
|
|
182
|
+
read_trans = Thrift::HeaderTransport.new(Thrift::MemoryBufferTransport.new(written_data))
|
|
183
|
+
read_trans.set_max_decompressed_size(2_000)
|
|
184
|
+
|
|
185
|
+
expect(read_trans.read(1_000)).to eq("A" * 1_000)
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
it "should raise SIZE_LIMIT TransportException when decompressed output exceeds the limit" do
|
|
189
|
+
write_buf = Thrift::MemoryBufferTransport.new
|
|
190
|
+
writer = Thrift::HeaderTransport.new(write_buf)
|
|
191
|
+
writer.add_transform(Thrift::HeaderTransformID::ZLIB)
|
|
192
|
+
writer.write("A" * 10_000)
|
|
193
|
+
writer.flush
|
|
194
|
+
|
|
195
|
+
written_data = write_buf.read(write_buf.available)
|
|
196
|
+
read_trans = Thrift::HeaderTransport.new(Thrift::MemoryBufferTransport.new(written_data))
|
|
197
|
+
read_trans.set_max_decompressed_size(100)
|
|
198
|
+
|
|
199
|
+
expect { read_trans.read(1) }.to raise_error(Thrift::TransportException) do |e|
|
|
200
|
+
expect(e.type).to eq(Thrift::TransportException::SIZE_LIMIT)
|
|
201
|
+
expect(e.message).to match(/limit/)
|
|
202
|
+
end
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
describe "read and frame detection" do
|
|
207
|
+
it "should detect Header format" do
|
|
208
|
+
# Write a Header frame
|
|
209
|
+
@trans.write("test data")
|
|
210
|
+
@trans.flush
|
|
211
|
+
|
|
212
|
+
# Reset for reading
|
|
213
|
+
written_data = @underlying.read(@underlying.available)
|
|
214
|
+
read_transport = Thrift::MemoryBufferTransport.new(written_data)
|
|
215
|
+
read_trans = Thrift::HeaderTransport.new(read_transport)
|
|
216
|
+
|
|
217
|
+
result = read_trans.read(9)
|
|
218
|
+
expect(result).to eq("test data")
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
it "should detect framed binary protocol" do
|
|
222
|
+
# Create a framed binary message
|
|
223
|
+
payload = [Thrift::BinaryProtocol::VERSION_1 | Thrift::MessageTypes::CALL].pack('N')
|
|
224
|
+
payload << "test"
|
|
225
|
+
frame = [payload.bytesize].pack('N') + payload
|
|
226
|
+
|
|
227
|
+
read_transport = Thrift::MemoryBufferTransport.new(frame)
|
|
228
|
+
read_trans = Thrift::HeaderTransport.new(read_transport)
|
|
229
|
+
|
|
230
|
+
result = read_trans.read(payload.bytesize)
|
|
231
|
+
expect(result).to eq(payload)
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
it "should detect unframed binary protocol" do
|
|
235
|
+
# Create an unframed binary message (version word first)
|
|
236
|
+
message = [Thrift::BinaryProtocol::VERSION_1 | Thrift::MessageTypes::CALL].pack('N')
|
|
237
|
+
message << "test"
|
|
238
|
+
|
|
239
|
+
read_transport = Thrift::MemoryBufferTransport.new(message)
|
|
240
|
+
read_trans = Thrift::HeaderTransport.new(read_transport)
|
|
241
|
+
|
|
242
|
+
result = read_trans.read(message.bytesize)
|
|
243
|
+
expect(result).to eq(message)
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
it "should read headers from Header frame" do
|
|
247
|
+
# Write with headers
|
|
248
|
+
@trans.set_header("request-id", "12345")
|
|
249
|
+
@trans.write("payload")
|
|
250
|
+
@trans.flush
|
|
251
|
+
|
|
252
|
+
# Read back
|
|
253
|
+
written_data = @underlying.read(@underlying.available)
|
|
254
|
+
read_transport = Thrift::MemoryBufferTransport.new(written_data)
|
|
255
|
+
read_trans = Thrift::HeaderTransport.new(read_transport)
|
|
256
|
+
|
|
257
|
+
read_trans.read(7)
|
|
258
|
+
headers = read_trans.get_headers
|
|
259
|
+
expect(headers["request-id"]).to eq("12345")
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
it "should decode signed sequence ids from Header frames" do
|
|
263
|
+
@trans.sequence_id = -2147483648
|
|
264
|
+
@trans.write("payload")
|
|
265
|
+
@trans.flush
|
|
266
|
+
|
|
267
|
+
written_data = @underlying.read(@underlying.available)
|
|
268
|
+
read_transport = Thrift::MemoryBufferTransport.new(written_data)
|
|
269
|
+
read_trans = Thrift::HeaderTransport.new(read_transport)
|
|
270
|
+
|
|
271
|
+
expect(read_trans.read(7)).to eq("payload")
|
|
272
|
+
expect(read_trans.sequence_id).to eq(-2147483648)
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
it "should decompress ZLIB payload" do
|
|
276
|
+
# Write with ZLIB
|
|
277
|
+
@trans.add_transform(Thrift::HeaderTransformID::ZLIB)
|
|
278
|
+
original = "hello world this is a test"
|
|
279
|
+
@trans.write(original)
|
|
280
|
+
@trans.flush
|
|
281
|
+
|
|
282
|
+
# Read back
|
|
283
|
+
written_data = @underlying.read(@underlying.available)
|
|
284
|
+
read_transport = Thrift::MemoryBufferTransport.new(written_data)
|
|
285
|
+
read_trans = Thrift::HeaderTransport.new(read_transport)
|
|
286
|
+
|
|
287
|
+
result = read_trans.read(original.bytesize)
|
|
288
|
+
expect(result).to eq(original)
|
|
289
|
+
end
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
describe "header parsing protections" do
|
|
293
|
+
it "should reject unreasonable header sizes" do
|
|
294
|
+
frame = build_header_frame("", Thrift::Bytes.empty_byte_buffer, header_words: 16_384)
|
|
295
|
+
read_transport = Thrift::MemoryBufferTransport.new(frame)
|
|
296
|
+
read_trans = Thrift::HeaderTransport.new(read_transport)
|
|
297
|
+
|
|
298
|
+
expect { read_trans.read(1) }.to raise_error(Thrift::TransportException, /Header size is unreasonable/)
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
it "should reject header frames that are too small" do
|
|
302
|
+
frame = Thrift::Bytes.empty_byte_buffer
|
|
303
|
+
frame << [9].pack('N')
|
|
304
|
+
frame << [Thrift::HeaderTransport::HEADER_MAGIC].pack('n')
|
|
305
|
+
frame << [0].pack('n')
|
|
306
|
+
frame << [0].pack('N')
|
|
307
|
+
frame << [0].pack('n')
|
|
308
|
+
read_transport = Thrift::MemoryBufferTransport.new(frame)
|
|
309
|
+
read_trans = Thrift::HeaderTransport.new(read_transport)
|
|
310
|
+
|
|
311
|
+
expect { read_trans.read(1) }.to raise_error(Thrift::TransportException, /frame is too small/)
|
|
312
|
+
end
|
|
313
|
+
|
|
314
|
+
it "should reject varints that cross header boundary" do
|
|
315
|
+
header_data = [0x80, 0x80, 0x80, 0x80].pack('C*')
|
|
316
|
+
frame = build_header_frame(header_data)
|
|
317
|
+
read_transport = Thrift::MemoryBufferTransport.new(frame)
|
|
318
|
+
read_trans = Thrift::HeaderTransport.new(read_transport)
|
|
319
|
+
|
|
320
|
+
expect { read_trans.read(1) }.to raise_error(Thrift::TransportException, /header boundary/)
|
|
321
|
+
end
|
|
322
|
+
|
|
323
|
+
it "should reject strings that exceed header boundary" do
|
|
324
|
+
header_data = +""
|
|
325
|
+
header_data << varint32(Thrift::HeaderSubprotocolID::BINARY)
|
|
326
|
+
header_data << varint32(0)
|
|
327
|
+
header_data << varint32(Thrift::HeaderInfoType::KEY_VALUE)
|
|
328
|
+
header_data << varint32(1)
|
|
329
|
+
header_data << varint32(10)
|
|
330
|
+
header_data << "a"
|
|
331
|
+
|
|
332
|
+
frame = build_header_frame(header_data)
|
|
333
|
+
read_transport = Thrift::MemoryBufferTransport.new(frame)
|
|
334
|
+
read_trans = Thrift::HeaderTransport.new(read_transport)
|
|
335
|
+
|
|
336
|
+
expect { read_trans.read(1) }.to raise_error(Thrift::TransportException, /Info header length exceeds header size/)
|
|
337
|
+
end
|
|
338
|
+
end
|
|
339
|
+
|
|
340
|
+
describe "round-trip" do
|
|
341
|
+
it "should handle complete write-read cycle" do
|
|
342
|
+
# Write
|
|
343
|
+
@trans.set_header("trace-id", "abc123")
|
|
344
|
+
@trans.write("hello world")
|
|
345
|
+
@trans.flush
|
|
346
|
+
|
|
347
|
+
# Read
|
|
348
|
+
written_data = @underlying.read(@underlying.available)
|
|
349
|
+
read_transport = Thrift::MemoryBufferTransport.new(written_data)
|
|
350
|
+
read_trans = Thrift::HeaderTransport.new(read_transport)
|
|
351
|
+
|
|
352
|
+
result = read_trans.read(11)
|
|
353
|
+
expect(result).to eq("hello world")
|
|
354
|
+
expect(read_trans.get_headers["trace-id"]).to eq("abc123")
|
|
355
|
+
end
|
|
356
|
+
|
|
357
|
+
it "should handle multiple headers" do
|
|
358
|
+
@trans.set_header("header1", "value1")
|
|
359
|
+
@trans.set_header("header2", "value2")
|
|
360
|
+
@trans.set_header("header3", "value3")
|
|
361
|
+
@trans.write("data")
|
|
362
|
+
@trans.flush
|
|
363
|
+
|
|
364
|
+
written_data = @underlying.read(@underlying.available)
|
|
365
|
+
read_transport = Thrift::MemoryBufferTransport.new(written_data)
|
|
366
|
+
read_trans = Thrift::HeaderTransport.new(read_transport)
|
|
367
|
+
|
|
368
|
+
read_trans.read(4)
|
|
369
|
+
headers = read_trans.get_headers
|
|
370
|
+
expect(headers["header1"]).to eq("value1")
|
|
371
|
+
expect(headers["header2"]).to eq("value2")
|
|
372
|
+
expect(headers["header3"]).to eq("value3")
|
|
373
|
+
end
|
|
374
|
+
|
|
375
|
+
it "should handle ZLIB compression round-trip" do
|
|
376
|
+
@trans.add_transform(Thrift::HeaderTransformID::ZLIB)
|
|
377
|
+
@trans.set_header("compressed", "true")
|
|
378
|
+
original = "x" * 500
|
|
379
|
+
@trans.write(original)
|
|
380
|
+
@trans.flush
|
|
381
|
+
|
|
382
|
+
written_data = @underlying.read(@underlying.available)
|
|
383
|
+
read_transport = Thrift::MemoryBufferTransport.new(written_data)
|
|
384
|
+
read_trans = Thrift::HeaderTransport.new(read_transport)
|
|
385
|
+
|
|
386
|
+
result = read_trans.read(500)
|
|
387
|
+
expect(result).to eq(original)
|
|
388
|
+
expect(read_trans.get_headers["compressed"]).to eq("true")
|
|
389
|
+
end
|
|
390
|
+
end
|
|
391
|
+
|
|
392
|
+
describe "client type restrictions" do
|
|
393
|
+
it "should reject disallowed client types" do
|
|
394
|
+
# Only allow HEADERS
|
|
395
|
+
allowed = [Thrift::HeaderClientType::HEADERS]
|
|
396
|
+
|
|
397
|
+
# Create framed binary message
|
|
398
|
+
payload = [Thrift::BinaryProtocol::VERSION_1 | Thrift::MessageTypes::CALL].pack('N')
|
|
399
|
+
frame = [payload.bytesize].pack('N') + payload
|
|
400
|
+
|
|
401
|
+
read_transport = Thrift::MemoryBufferTransport.new(frame)
|
|
402
|
+
read_trans = Thrift::HeaderTransport.new(read_transport, allowed)
|
|
403
|
+
|
|
404
|
+
expect { read_trans.read(4) }.to raise_error(Thrift::TransportException)
|
|
405
|
+
end
|
|
406
|
+
end
|
|
407
|
+
end
|
|
408
|
+
|
|
409
|
+
describe Thrift::HeaderTransportFactory do
|
|
410
|
+
it "should wrap transport in HeaderTransport" do
|
|
411
|
+
mock_transport = double("Transport")
|
|
412
|
+
factory = Thrift::HeaderTransportFactory.new
|
|
413
|
+
result = factory.get_transport(mock_transport)
|
|
414
|
+
expect(result).to be_a(Thrift::HeaderTransport)
|
|
415
|
+
end
|
|
416
|
+
|
|
417
|
+
it "should provide a reasonable to_s" do
|
|
418
|
+
expect(Thrift::HeaderTransportFactory.new.to_s).to eq("header")
|
|
419
|
+
end
|
|
420
|
+
|
|
421
|
+
it "should pass allowed_client_types to transport" do
|
|
422
|
+
allowed = [Thrift::HeaderClientType::HEADERS]
|
|
423
|
+
factory = Thrift::HeaderTransportFactory.new(allowed)
|
|
424
|
+
|
|
425
|
+
mock_transport = Thrift::MemoryBufferTransport.new
|
|
426
|
+
result = factory.get_transport(mock_transport)
|
|
427
|
+
|
|
428
|
+
expect(result).to be_a(Thrift::HeaderTransport)
|
|
429
|
+
end
|
|
430
|
+
end
|
|
431
|
+
end
|
data/spec/http_client_spec.rb
CHANGED
|
@@ -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
|
|
@@ -20,12 +21,11 @@
|
|
|
20
21
|
require 'spec_helper'
|
|
21
22
|
|
|
22
23
|
describe 'Thrift::HTTPClientTransport' do
|
|
23
|
-
|
|
24
24
|
describe Thrift::HTTPClientTransport do
|
|
25
25
|
before(:each) do
|
|
26
26
|
@client = Thrift::HTTPClientTransport.new("http://my.domain.com/path/to/service?param=value")
|
|
27
27
|
end
|
|
28
|
-
|
|
28
|
+
|
|
29
29
|
it "should provide a reasonable to_s" do
|
|
30
30
|
@client.to_s == "http://my.domain.com/path/to/service?param=value"
|
|
31
31
|
end
|
|
@@ -84,7 +84,7 @@ describe 'Thrift::HTTPClientTransport' do
|
|
|
84
84
|
end
|
|
85
85
|
end
|
|
86
86
|
|
|
87
|
-
@client.flush
|
|
87
|
+
@client.flush rescue
|
|
88
88
|
expect(@client.instance_variable_get(:@outbuf)).to eq(Thrift::Bytes.empty_byte_buffer)
|
|
89
89
|
end
|
|
90
90
|
|
|
@@ -105,7 +105,6 @@ describe 'Thrift::HTTPClientTransport' do
|
|
|
105
105
|
|
|
106
106
|
expect { @client.flush }.to raise_error(Thrift::TransportException)
|
|
107
107
|
end
|
|
108
|
-
|
|
109
108
|
end
|
|
110
109
|
|
|
111
110
|
describe 'ssl enabled' do
|
|
@@ -124,7 +123,7 @@ describe 'Thrift::HTTPClientTransport' do
|
|
|
124
123
|
expect(http).to receive(:use_ssl=).with(true)
|
|
125
124
|
expect(http).to receive(:verify_mode=).with(OpenSSL::SSL::VERIFY_PEER)
|
|
126
125
|
expect(http).to receive(:post).with(@service_path, "test",
|
|
127
|
-
"Content-Type" => "application/x-thrift") do
|
|
126
|
+
{"Content-Type" => "application/x-thrift"}) do
|
|
128
127
|
double("Net::HTTPOK").tap do |response|
|
|
129
128
|
expect(response).to receive(:body).and_return "data"
|
|
130
129
|
expect(response).to receive(:code).and_return "200"
|
|
@@ -146,7 +145,7 @@ describe 'Thrift::HTTPClientTransport' do
|
|
|
146
145
|
expect(http).to receive(:use_ssl=).with(true)
|
|
147
146
|
expect(http).to receive(:verify_mode=).with(OpenSSL::SSL::VERIFY_NONE)
|
|
148
147
|
expect(http).to receive(:post).with(@service_path, "test",
|
|
149
|
-
"Content-Type" => "application/x-thrift") do
|
|
148
|
+
{"Content-Type" => "application/x-thrift"}) do
|
|
150
149
|
double("Net::HTTPOK").tap do |response|
|
|
151
150
|
expect(response).to receive(:body).and_return "data"
|
|
152
151
|
expect(response).to receive(:code).and_return "200"
|