thrift 0.22.0 → 0.23.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 +175 -17
- data/benchmark/benchmark.rb +22 -8
- data/benchmark/client.rb +49 -6
- data/benchmark/server.rb +45 -7
- data/benchmark/thin_server.rb +1 -0
- data/ext/binary_protocol_accelerated.c +76 -19
- data/ext/compact_protocol.c +80 -15
- data/ext/constants.h +12 -0
- data/ext/extconf.rb +10 -9
- data/ext/memory_buffer.c +7 -7
- data/ext/protocol.c +29 -0
- data/ext/protocol.h +35 -0
- data/ext/struct.c +36 -5
- data/ext/thrift_native.c +27 -3
- data/lib/thrift/bytes.rb +68 -101
- data/lib/thrift/client.rb +61 -9
- data/lib/thrift/exceptions.rb +5 -5
- data/lib/thrift/multiplexed_processor.rb +6 -6
- data/lib/thrift/processor.rb +6 -6
- data/lib/thrift/protocol/base_protocol.rb +37 -15
- data/lib/thrift/protocol/binary_protocol.rb +25 -9
- data/lib/thrift/protocol/binary_protocol_accelerated.rb +5 -5
- data/lib/thrift/protocol/compact_protocol.rb +61 -37
- data/lib/thrift/protocol/header_protocol.rb +320 -0
- data/lib/thrift/protocol/json_protocol.rb +26 -16
- data/lib/thrift/protocol/multiplexed_protocol.rb +5 -5
- data/lib/thrift/protocol/protocol_decorator.rb +12 -4
- data/lib/thrift/serializer/deserializer.rb +5 -5
- data/lib/thrift/serializer/serializer.rb +4 -5
- data/lib/thrift/server/base_server.rb +4 -4
- data/lib/thrift/server/mongrel_http_server.rb +6 -6
- data/lib/thrift/server/nonblocking_server.rb +8 -8
- data/lib/thrift/server/simple_server.rb +4 -4
- data/lib/thrift/server/thin_http_server.rb +3 -3
- data/lib/thrift/server/thread_pool_server.rb +6 -6
- data/lib/thrift/server/threaded_server.rb +4 -4
- data/lib/thrift/struct.rb +11 -11
- data/lib/thrift/struct_union.rb +19 -9
- data/lib/thrift/thrift_native.rb +1 -1
- data/lib/thrift/transport/base_server_transport.rb +5 -5
- data/lib/thrift/transport/base_transport.rb +12 -12
- data/lib/thrift/transport/buffered_transport.rb +6 -6
- data/lib/thrift/transport/framed_transport.rb +7 -7
- data/lib/thrift/transport/header_transport.rb +516 -0
- data/lib/thrift/transport/http_client_transport.rb +1 -1
- data/lib/thrift/transport/io_stream_transport.rb +3 -3
- data/lib/thrift/transport/memory_buffer_transport.rb +6 -6
- data/lib/thrift/transport/server_socket.rb +8 -5
- data/lib/thrift/transport/socket.rb +58 -31
- data/lib/thrift/transport/ssl_server_socket.rb +1 -1
- data/lib/thrift/transport/ssl_socket.rb +2 -2
- data/lib/thrift/transport/unix_server_socket.rb +4 -4
- data/lib/thrift/transport/unix_socket.rb +6 -6
- data/lib/thrift/types.rb +9 -6
- data/lib/thrift/union.rb +14 -8
- data/lib/thrift/uuid.rb +49 -0
- data/lib/thrift.rb +3 -1
- data/spec/ThriftSpec.thrift +5 -1
- data/spec/base_protocol_spec.rb +1 -2
- data/spec/base_transport_spec.rb +6 -7
- data/spec/binary_protocol_spec.rb +0 -2
- data/spec/binary_protocol_spec_shared.rb +129 -142
- data/spec/bytes_spec.rb +57 -118
- data/spec/client_spec.rb +85 -19
- data/spec/compact_protocol_spec.rb +54 -16
- data/spec/constants_demo_spec.rb +101 -0
- data/spec/exception_spec.rb +0 -1
- data/spec/header_protocol_spec.rb +475 -0
- data/spec/header_transport_spec.rb +386 -0
- data/spec/http_client_spec.rb +4 -6
- data/spec/json_protocol_spec.rb +47 -47
- data/spec/namespaced_spec.rb +0 -1
- data/spec/nonblocking_server_spec.rb +102 -4
- data/spec/processor_spec.rb +0 -1
- data/spec/serializer_spec.rb +0 -1
- data/spec/server_socket_spec.rb +1 -1
- data/spec/server_spec.rb +8 -9
- data/spec/socket_spec.rb +0 -1
- data/spec/socket_spec_shared.rb +72 -9
- data/spec/spec_helper.rb +1 -1
- data/spec/ssl_server_socket_spec.rb +12 -1
- data/spec/ssl_socket_spec.rb +10 -1
- data/spec/struct_nested_containers_spec.rb +1 -2
- data/spec/struct_spec.rb +113 -9
- data/spec/support/header_protocol_helper.rb +54 -0
- data/spec/thin_http_server_spec.rb +3 -18
- data/spec/types_spec.rb +25 -26
- data/spec/union_spec.rb +69 -11
- data/spec/unix_socket_spec.rb +1 -2
- data/spec/uuid_validation_spec.rb +238 -0
- data/test/fuzz/Makefile.am +173 -0
- data/test/fuzz/README.md +149 -0
- data/test/fuzz/fuzz_common.rb +95 -0
- data/{lib/thrift/core_ext.rb → test/fuzz/fuzz_parse_binary_protocol.rb} +3 -4
- data/{lib/thrift/core_ext/fixnum.rb → test/fuzz/fuzz_parse_binary_protocol_accelerated.rb} +6 -13
- data/test/fuzz/fuzz_parse_binary_protocol_accelerated_harness.rb +22 -0
- data/test/fuzz/fuzz_parse_binary_protocol_harness.rb +22 -0
- data/test/fuzz/fuzz_parse_compact_protocol.rb +22 -0
- data/test/fuzz/fuzz_parse_compact_protocol_harness.rb +22 -0
- data/test/fuzz/fuzz_parse_json_protocol.rb +22 -0
- data/test/fuzz/fuzz_parse_json_protocol_harness.rb +22 -0
- data/test/fuzz/fuzz_roundtrip_binary_protocol.rb +22 -0
- data/test/fuzz/fuzz_roundtrip_binary_protocol_accelerated.rb +22 -0
- data/test/fuzz/fuzz_roundtrip_binary_protocol_accelerated_harness.rb +22 -0
- data/test/fuzz/fuzz_roundtrip_binary_protocol_harness.rb +22 -0
- data/test/fuzz/fuzz_roundtrip_compact_protocol.rb +22 -0
- data/test/fuzz/fuzz_roundtrip_compact_protocol_harness.rb +22 -0
- data/test/fuzz/fuzz_roundtrip_json_protocol.rb +22 -0
- data/test/fuzz/fuzz_roundtrip_json_protocol_harness.rb +22 -0
- data/test/fuzz/fuzz_tracer.rb +28 -0
- metadata +106 -37
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Licensed to the Apache Software Foundation (ASF) under one
|
|
3
|
+
# or more contributor license agreements. See the NOTICE file
|
|
4
|
+
# distributed with this work for additional information
|
|
5
|
+
# regarding copyright ownership. The ASF licenses this file
|
|
6
|
+
# to you under the Apache License, Version 2.0 (the
|
|
7
|
+
# "License"); you may not use this file except in compliance
|
|
8
|
+
# with the License. You may obtain a copy of the License at
|
|
9
|
+
#
|
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
#
|
|
12
|
+
# Unless required by applicable law or agreed to in writing,
|
|
13
|
+
# software distributed under the License is distributed on an
|
|
14
|
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
15
|
+
# KIND, either express or implied. See the License for the
|
|
16
|
+
# specific language governing permissions and limitations
|
|
17
|
+
# under the License.
|
|
18
|
+
#
|
|
19
|
+
|
|
20
|
+
require 'spec_helper'
|
|
21
|
+
require_relative 'support/header_protocol_helper'
|
|
22
|
+
|
|
23
|
+
describe 'HeaderTransport' do
|
|
24
|
+
include HeaderProtocolHelper
|
|
25
|
+
|
|
26
|
+
describe Thrift::HeaderClientType do
|
|
27
|
+
it "should define client type constants" do
|
|
28
|
+
expect(Thrift::HeaderClientType::HEADERS).to eq(0x00)
|
|
29
|
+
expect(Thrift::HeaderClientType::FRAMED_BINARY).to eq(0x01)
|
|
30
|
+
expect(Thrift::HeaderClientType::UNFRAMED_BINARY).to eq(0x02)
|
|
31
|
+
expect(Thrift::HeaderClientType::FRAMED_COMPACT).to eq(0x03)
|
|
32
|
+
expect(Thrift::HeaderClientType::UNFRAMED_COMPACT).to eq(0x04)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
describe Thrift::HeaderSubprotocolID do
|
|
37
|
+
it "should define protocol ID constants" do
|
|
38
|
+
expect(Thrift::HeaderSubprotocolID::BINARY).to eq(0x00)
|
|
39
|
+
expect(Thrift::HeaderSubprotocolID::COMPACT).to eq(0x02)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
describe Thrift::HeaderTransformID do
|
|
44
|
+
it "should define transform ID constants" do
|
|
45
|
+
expect(Thrift::HeaderTransformID::ZLIB).to eq(0x01)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
describe Thrift::HeaderTransport do
|
|
50
|
+
before(:each) do
|
|
51
|
+
@underlying = Thrift::MemoryBufferTransport.new
|
|
52
|
+
@trans = Thrift::HeaderTransport.new(@underlying)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
it "should provide a to_s that describes the encapsulation" do
|
|
56
|
+
expect(@trans.to_s).to eq("header(memory)")
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
it "should pass through open?/open/close" do
|
|
60
|
+
mock_transport = double("Transport")
|
|
61
|
+
expect(mock_transport).to receive(:open?).and_return(true)
|
|
62
|
+
expect(mock_transport).to receive(:open).and_return(nil)
|
|
63
|
+
expect(mock_transport).to receive(:close).and_return(nil)
|
|
64
|
+
|
|
65
|
+
trans = Thrift::HeaderTransport.new(mock_transport)
|
|
66
|
+
expect(trans.open?).to be true
|
|
67
|
+
trans.open
|
|
68
|
+
trans.close
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
describe "header management" do
|
|
72
|
+
it "should allow setting and getting headers" do
|
|
73
|
+
@trans.set_header("key1", "value1")
|
|
74
|
+
@trans.set_header("key2", "value2")
|
|
75
|
+
# Headers aren't read until we receive data, so write and read back
|
|
76
|
+
expect(@trans.get_headers).to eq({})
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
it "should clear headers" do
|
|
80
|
+
@trans.set_header("key1", "value1")
|
|
81
|
+
@trans.clear_headers
|
|
82
|
+
# Write and flush to verify headers were cleared
|
|
83
|
+
@trans.write("test")
|
|
84
|
+
@trans.flush
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
it "should add transforms" do
|
|
88
|
+
expect { @trans.add_transform(Thrift::HeaderTransformID::ZLIB) }.not_to raise_error
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
it "should reject unknown transforms" do
|
|
92
|
+
expect { @trans.add_transform(999) }.to raise_error(Thrift::TransportException)
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
describe "write and flush" do
|
|
97
|
+
it "should buffer writes" do
|
|
98
|
+
@trans.write("hello")
|
|
99
|
+
@trans.write(" world")
|
|
100
|
+
expect(@underlying.available).to eq(0)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
it "should write Header format on flush" do
|
|
104
|
+
@trans.write("test payload")
|
|
105
|
+
@trans.flush
|
|
106
|
+
|
|
107
|
+
# Read back the frame
|
|
108
|
+
data = @underlying.read(@underlying.available)
|
|
109
|
+
|
|
110
|
+
# Should have frame length (4 bytes) + header + payload
|
|
111
|
+
expect(data.bytesize).to be > 16
|
|
112
|
+
|
|
113
|
+
# First 4 bytes are frame length
|
|
114
|
+
frame_size = data[0, 4].unpack('N').first
|
|
115
|
+
expect(frame_size).to eq(data.bytesize - 4)
|
|
116
|
+
|
|
117
|
+
# Next 2 bytes should be header magic
|
|
118
|
+
magic = data[4, 2].unpack('n').first
|
|
119
|
+
expect(magic).to eq(Thrift::HeaderTransport::HEADER_MAGIC)
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
it "should include headers in frame" do
|
|
123
|
+
@trans.set_header("test-key", "test-value")
|
|
124
|
+
@trans.write("payload")
|
|
125
|
+
@trans.flush
|
|
126
|
+
|
|
127
|
+
# Read back and verify it's larger due to headers
|
|
128
|
+
data = @underlying.read(@underlying.available)
|
|
129
|
+
expect(data.bytesize).to be > 30 # Should include header key-value
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
it "should write the configured sequence id into the frame header" do
|
|
133
|
+
@trans.sequence_id = 456
|
|
134
|
+
@trans.write("payload")
|
|
135
|
+
@trans.flush
|
|
136
|
+
|
|
137
|
+
data = @underlying.read(@underlying.available)
|
|
138
|
+
expect(data[8, 4].unpack('N').first).to eq(456)
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
it "should apply ZLIB transform" do
|
|
142
|
+
@trans.add_transform(Thrift::HeaderTransformID::ZLIB)
|
|
143
|
+
original_payload = "a" * 1000 # Compressible data
|
|
144
|
+
@trans.write(original_payload)
|
|
145
|
+
@trans.flush
|
|
146
|
+
|
|
147
|
+
data = @underlying.read(@underlying.available)
|
|
148
|
+
# Compressed frame should be smaller than uncompressed
|
|
149
|
+
expect(data.bytesize).to be < original_payload.bytesize
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
describe "frame size limits" do
|
|
154
|
+
it "should reject payloads larger than max frame size" do
|
|
155
|
+
@trans.set_max_frame_size(4)
|
|
156
|
+
@trans.write("12345")
|
|
157
|
+
expect { @trans.flush }.to raise_error(Thrift::TransportException, /frame that is too large/)
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
describe "read and frame detection" do
|
|
162
|
+
it "should detect Header format" do
|
|
163
|
+
# Write a Header frame
|
|
164
|
+
@trans.write("test data")
|
|
165
|
+
@trans.flush
|
|
166
|
+
|
|
167
|
+
# Reset for reading
|
|
168
|
+
written_data = @underlying.read(@underlying.available)
|
|
169
|
+
read_transport = Thrift::MemoryBufferTransport.new(written_data)
|
|
170
|
+
read_trans = Thrift::HeaderTransport.new(read_transport)
|
|
171
|
+
|
|
172
|
+
result = read_trans.read(9)
|
|
173
|
+
expect(result).to eq("test data")
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
it "should detect framed binary protocol" do
|
|
177
|
+
# Create a framed binary message
|
|
178
|
+
payload = [Thrift::BinaryProtocol::VERSION_1 | Thrift::MessageTypes::CALL].pack('N')
|
|
179
|
+
payload << "test"
|
|
180
|
+
frame = [payload.bytesize].pack('N') + payload
|
|
181
|
+
|
|
182
|
+
read_transport = Thrift::MemoryBufferTransport.new(frame)
|
|
183
|
+
read_trans = Thrift::HeaderTransport.new(read_transport)
|
|
184
|
+
|
|
185
|
+
result = read_trans.read(payload.bytesize)
|
|
186
|
+
expect(result).to eq(payload)
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
it "should detect unframed binary protocol" do
|
|
190
|
+
# Create an unframed binary message (version word first)
|
|
191
|
+
message = [Thrift::BinaryProtocol::VERSION_1 | Thrift::MessageTypes::CALL].pack('N')
|
|
192
|
+
message << "test"
|
|
193
|
+
|
|
194
|
+
read_transport = Thrift::MemoryBufferTransport.new(message)
|
|
195
|
+
read_trans = Thrift::HeaderTransport.new(read_transport)
|
|
196
|
+
|
|
197
|
+
result = read_trans.read(message.bytesize)
|
|
198
|
+
expect(result).to eq(message)
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
it "should read headers from Header frame" do
|
|
202
|
+
# Write with headers
|
|
203
|
+
@trans.set_header("request-id", "12345")
|
|
204
|
+
@trans.write("payload")
|
|
205
|
+
@trans.flush
|
|
206
|
+
|
|
207
|
+
# Read back
|
|
208
|
+
written_data = @underlying.read(@underlying.available)
|
|
209
|
+
read_transport = Thrift::MemoryBufferTransport.new(written_data)
|
|
210
|
+
read_trans = Thrift::HeaderTransport.new(read_transport)
|
|
211
|
+
|
|
212
|
+
read_trans.read(7)
|
|
213
|
+
headers = read_trans.get_headers
|
|
214
|
+
expect(headers["request-id"]).to eq("12345")
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
it "should decode signed sequence ids from Header frames" do
|
|
218
|
+
@trans.sequence_id = -2147483648
|
|
219
|
+
@trans.write("payload")
|
|
220
|
+
@trans.flush
|
|
221
|
+
|
|
222
|
+
written_data = @underlying.read(@underlying.available)
|
|
223
|
+
read_transport = Thrift::MemoryBufferTransport.new(written_data)
|
|
224
|
+
read_trans = Thrift::HeaderTransport.new(read_transport)
|
|
225
|
+
|
|
226
|
+
expect(read_trans.read(7)).to eq("payload")
|
|
227
|
+
expect(read_trans.sequence_id).to eq(-2147483648)
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
it "should decompress ZLIB payload" do
|
|
231
|
+
# Write with ZLIB
|
|
232
|
+
@trans.add_transform(Thrift::HeaderTransformID::ZLIB)
|
|
233
|
+
original = "hello world this is a test"
|
|
234
|
+
@trans.write(original)
|
|
235
|
+
@trans.flush
|
|
236
|
+
|
|
237
|
+
# Read back
|
|
238
|
+
written_data = @underlying.read(@underlying.available)
|
|
239
|
+
read_transport = Thrift::MemoryBufferTransport.new(written_data)
|
|
240
|
+
read_trans = Thrift::HeaderTransport.new(read_transport)
|
|
241
|
+
|
|
242
|
+
result = read_trans.read(original.bytesize)
|
|
243
|
+
expect(result).to eq(original)
|
|
244
|
+
end
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
describe "header parsing protections" do
|
|
248
|
+
it "should reject unreasonable header sizes" do
|
|
249
|
+
frame = build_header_frame("", Thrift::Bytes.empty_byte_buffer, header_words: 16_384)
|
|
250
|
+
read_transport = Thrift::MemoryBufferTransport.new(frame)
|
|
251
|
+
read_trans = Thrift::HeaderTransport.new(read_transport)
|
|
252
|
+
|
|
253
|
+
expect { read_trans.read(1) }.to raise_error(Thrift::TransportException, /Header size is unreasonable/)
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
it "should reject header frames that are too small" do
|
|
257
|
+
frame = Thrift::Bytes.empty_byte_buffer
|
|
258
|
+
frame << [9].pack('N')
|
|
259
|
+
frame << [Thrift::HeaderTransport::HEADER_MAGIC].pack('n')
|
|
260
|
+
frame << [0].pack('n')
|
|
261
|
+
frame << [0].pack('N')
|
|
262
|
+
frame << [0].pack('n')
|
|
263
|
+
read_transport = Thrift::MemoryBufferTransport.new(frame)
|
|
264
|
+
read_trans = Thrift::HeaderTransport.new(read_transport)
|
|
265
|
+
|
|
266
|
+
expect { read_trans.read(1) }.to raise_error(Thrift::TransportException, /frame is too small/)
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
it "should reject varints that cross header boundary" do
|
|
270
|
+
header_data = [0x80, 0x80, 0x80, 0x80].pack('C*')
|
|
271
|
+
frame = build_header_frame(header_data)
|
|
272
|
+
read_transport = Thrift::MemoryBufferTransport.new(frame)
|
|
273
|
+
read_trans = Thrift::HeaderTransport.new(read_transport)
|
|
274
|
+
|
|
275
|
+
expect { read_trans.read(1) }.to raise_error(Thrift::TransportException, /header boundary/)
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
it "should reject strings that exceed header boundary" do
|
|
279
|
+
header_data = +""
|
|
280
|
+
header_data << varint32(Thrift::HeaderSubprotocolID::BINARY)
|
|
281
|
+
header_data << varint32(0)
|
|
282
|
+
header_data << varint32(Thrift::HeaderInfoType::KEY_VALUE)
|
|
283
|
+
header_data << varint32(1)
|
|
284
|
+
header_data << varint32(10)
|
|
285
|
+
header_data << "a"
|
|
286
|
+
|
|
287
|
+
frame = build_header_frame(header_data)
|
|
288
|
+
read_transport = Thrift::MemoryBufferTransport.new(frame)
|
|
289
|
+
read_trans = Thrift::HeaderTransport.new(read_transport)
|
|
290
|
+
|
|
291
|
+
expect { read_trans.read(1) }.to raise_error(Thrift::TransportException, /Info header length exceeds header size/)
|
|
292
|
+
end
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
describe "round-trip" do
|
|
296
|
+
it "should handle complete write-read cycle" do
|
|
297
|
+
# Write
|
|
298
|
+
@trans.set_header("trace-id", "abc123")
|
|
299
|
+
@trans.write("hello world")
|
|
300
|
+
@trans.flush
|
|
301
|
+
|
|
302
|
+
# Read
|
|
303
|
+
written_data = @underlying.read(@underlying.available)
|
|
304
|
+
read_transport = Thrift::MemoryBufferTransport.new(written_data)
|
|
305
|
+
read_trans = Thrift::HeaderTransport.new(read_transport)
|
|
306
|
+
|
|
307
|
+
result = read_trans.read(11)
|
|
308
|
+
expect(result).to eq("hello world")
|
|
309
|
+
expect(read_trans.get_headers["trace-id"]).to eq("abc123")
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
it "should handle multiple headers" do
|
|
313
|
+
@trans.set_header("header1", "value1")
|
|
314
|
+
@trans.set_header("header2", "value2")
|
|
315
|
+
@trans.set_header("header3", "value3")
|
|
316
|
+
@trans.write("data")
|
|
317
|
+
@trans.flush
|
|
318
|
+
|
|
319
|
+
written_data = @underlying.read(@underlying.available)
|
|
320
|
+
read_transport = Thrift::MemoryBufferTransport.new(written_data)
|
|
321
|
+
read_trans = Thrift::HeaderTransport.new(read_transport)
|
|
322
|
+
|
|
323
|
+
read_trans.read(4)
|
|
324
|
+
headers = read_trans.get_headers
|
|
325
|
+
expect(headers["header1"]).to eq("value1")
|
|
326
|
+
expect(headers["header2"]).to eq("value2")
|
|
327
|
+
expect(headers["header3"]).to eq("value3")
|
|
328
|
+
end
|
|
329
|
+
|
|
330
|
+
it "should handle ZLIB compression round-trip" do
|
|
331
|
+
@trans.add_transform(Thrift::HeaderTransformID::ZLIB)
|
|
332
|
+
@trans.set_header("compressed", "true")
|
|
333
|
+
original = "x" * 500
|
|
334
|
+
@trans.write(original)
|
|
335
|
+
@trans.flush
|
|
336
|
+
|
|
337
|
+
written_data = @underlying.read(@underlying.available)
|
|
338
|
+
read_transport = Thrift::MemoryBufferTransport.new(written_data)
|
|
339
|
+
read_trans = Thrift::HeaderTransport.new(read_transport)
|
|
340
|
+
|
|
341
|
+
result = read_trans.read(500)
|
|
342
|
+
expect(result).to eq(original)
|
|
343
|
+
expect(read_trans.get_headers["compressed"]).to eq("true")
|
|
344
|
+
end
|
|
345
|
+
end
|
|
346
|
+
|
|
347
|
+
describe "client type restrictions" do
|
|
348
|
+
it "should reject disallowed client types" do
|
|
349
|
+
# Only allow HEADERS
|
|
350
|
+
allowed = [Thrift::HeaderClientType::HEADERS]
|
|
351
|
+
|
|
352
|
+
# Create framed binary message
|
|
353
|
+
payload = [Thrift::BinaryProtocol::VERSION_1 | Thrift::MessageTypes::CALL].pack('N')
|
|
354
|
+
frame = [payload.bytesize].pack('N') + payload
|
|
355
|
+
|
|
356
|
+
read_transport = Thrift::MemoryBufferTransport.new(frame)
|
|
357
|
+
read_trans = Thrift::HeaderTransport.new(read_transport, allowed)
|
|
358
|
+
|
|
359
|
+
expect { read_trans.read(4) }.to raise_error(Thrift::TransportException)
|
|
360
|
+
end
|
|
361
|
+
end
|
|
362
|
+
end
|
|
363
|
+
|
|
364
|
+
describe Thrift::HeaderTransportFactory do
|
|
365
|
+
it "should wrap transport in HeaderTransport" do
|
|
366
|
+
mock_transport = double("Transport")
|
|
367
|
+
factory = Thrift::HeaderTransportFactory.new
|
|
368
|
+
result = factory.get_transport(mock_transport)
|
|
369
|
+
expect(result).to be_a(Thrift::HeaderTransport)
|
|
370
|
+
end
|
|
371
|
+
|
|
372
|
+
it "should provide a reasonable to_s" do
|
|
373
|
+
expect(Thrift::HeaderTransportFactory.new.to_s).to eq("header")
|
|
374
|
+
end
|
|
375
|
+
|
|
376
|
+
it "should pass allowed_client_types to transport" do
|
|
377
|
+
allowed = [Thrift::HeaderClientType::HEADERS]
|
|
378
|
+
factory = Thrift::HeaderTransportFactory.new(allowed)
|
|
379
|
+
|
|
380
|
+
mock_transport = Thrift::MemoryBufferTransport.new
|
|
381
|
+
result = factory.get_transport(mock_transport)
|
|
382
|
+
|
|
383
|
+
expect(result).to be_a(Thrift::HeaderTransport)
|
|
384
|
+
end
|
|
385
|
+
end
|
|
386
|
+
end
|
data/spec/http_client_spec.rb
CHANGED
|
@@ -20,12 +20,11 @@
|
|
|
20
20
|
require 'spec_helper'
|
|
21
21
|
|
|
22
22
|
describe 'Thrift::HTTPClientTransport' do
|
|
23
|
-
|
|
24
23
|
describe Thrift::HTTPClientTransport do
|
|
25
24
|
before(:each) do
|
|
26
25
|
@client = Thrift::HTTPClientTransport.new("http://my.domain.com/path/to/service?param=value")
|
|
27
26
|
end
|
|
28
|
-
|
|
27
|
+
|
|
29
28
|
it "should provide a reasonable to_s" do
|
|
30
29
|
@client.to_s == "http://my.domain.com/path/to/service?param=value"
|
|
31
30
|
end
|
|
@@ -84,7 +83,7 @@ describe 'Thrift::HTTPClientTransport' do
|
|
|
84
83
|
end
|
|
85
84
|
end
|
|
86
85
|
|
|
87
|
-
@client.flush
|
|
86
|
+
@client.flush rescue
|
|
88
87
|
expect(@client.instance_variable_get(:@outbuf)).to eq(Thrift::Bytes.empty_byte_buffer)
|
|
89
88
|
end
|
|
90
89
|
|
|
@@ -105,7 +104,6 @@ describe 'Thrift::HTTPClientTransport' do
|
|
|
105
104
|
|
|
106
105
|
expect { @client.flush }.to raise_error(Thrift::TransportException)
|
|
107
106
|
end
|
|
108
|
-
|
|
109
107
|
end
|
|
110
108
|
|
|
111
109
|
describe 'ssl enabled' do
|
|
@@ -124,7 +122,7 @@ describe 'Thrift::HTTPClientTransport' do
|
|
|
124
122
|
expect(http).to receive(:use_ssl=).with(true)
|
|
125
123
|
expect(http).to receive(:verify_mode=).with(OpenSSL::SSL::VERIFY_PEER)
|
|
126
124
|
expect(http).to receive(:post).with(@service_path, "test",
|
|
127
|
-
"Content-Type" => "application/x-thrift") do
|
|
125
|
+
{"Content-Type" => "application/x-thrift"}) do
|
|
128
126
|
double("Net::HTTPOK").tap do |response|
|
|
129
127
|
expect(response).to receive(:body).and_return "data"
|
|
130
128
|
expect(response).to receive(:code).and_return "200"
|
|
@@ -146,7 +144,7 @@ describe 'Thrift::HTTPClientTransport' do
|
|
|
146
144
|
expect(http).to receive(:use_ssl=).with(true)
|
|
147
145
|
expect(http).to receive(:verify_mode=).with(OpenSSL::SSL::VERIFY_NONE)
|
|
148
146
|
expect(http).to receive(:post).with(@service_path, "test",
|
|
149
|
-
"Content-Type" => "application/x-thrift") do
|
|
147
|
+
{"Content-Type" => "application/x-thrift"}) do
|
|
150
148
|
double("Net::HTTPOK").tap do |response|
|
|
151
149
|
expect(response).to receive(:body).and_return "data"
|
|
152
150
|
expect(response).to receive(:code).and_return "200"
|
data/spec/json_protocol_spec.rb
CHANGED
|
@@ -21,7 +21,6 @@
|
|
|
21
21
|
require 'spec_helper'
|
|
22
22
|
|
|
23
23
|
describe 'JsonProtocol' do
|
|
24
|
-
|
|
25
24
|
describe Thrift::JsonProtocol do
|
|
26
25
|
before(:each) do
|
|
27
26
|
@trans = Thrift::MemoryBufferTransport.new
|
|
@@ -221,25 +220,18 @@ describe 'JsonProtocol' do
|
|
|
221
220
|
expect(@trans.read(@trans.available)).to eq("\"-Infinity\"")
|
|
222
221
|
end
|
|
223
222
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
end
|
|
223
|
+
it 'should write string' do
|
|
224
|
+
@prot.write_string('this is a test string')
|
|
225
|
+
a = @trans.read(@trans.available)
|
|
226
|
+
expect(a).to eq('"this is a test string"'.force_encoding(Encoding::BINARY))
|
|
227
|
+
expect(a.encoding).to eq(Encoding::BINARY)
|
|
228
|
+
end
|
|
231
229
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
end
|
|
238
|
-
else
|
|
239
|
-
it 'should write string' do
|
|
240
|
-
@prot.write_string('this is a test string')
|
|
241
|
-
expect(@trans.read(@trans.available)).to eq('"this is a test string"')
|
|
242
|
-
end
|
|
230
|
+
it 'should write string with unicode characters' do
|
|
231
|
+
@prot.write_string("this is a test string with unicode characters: \u20AC \u20AD")
|
|
232
|
+
a = @trans.read(@trans.available)
|
|
233
|
+
expect(a).to eq("\"this is a test string with unicode characters: \u20AC \u20AD\"".force_encoding(Encoding::BINARY))
|
|
234
|
+
expect(a.encoding).to eq(Encoding::BINARY)
|
|
243
235
|
end
|
|
244
236
|
|
|
245
237
|
it "should write binary" do
|
|
@@ -252,9 +244,14 @@ describe 'JsonProtocol' do
|
|
|
252
244
|
expect(@trans.read(@trans.available)).to eq("\"AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/w==\"")
|
|
253
245
|
end
|
|
254
246
|
|
|
247
|
+
it "should write a uuid" do
|
|
248
|
+
@prot.write_uuid("00112233-4455-6677-8899-aabbccddeeff")
|
|
249
|
+
expect(@trans.read(@trans.available)).to eq("\"00112233-4455-6677-8899-aabbccddeeff\"")
|
|
250
|
+
end
|
|
251
|
+
|
|
255
252
|
it "should get type name for type id" do
|
|
256
|
-
expect {@prot.get_type_name_for_type_id(Thrift::Types::STOP)}.to raise_error(NotImplementedError)
|
|
257
|
-
expect {@prot.get_type_name_for_type_id(Thrift::Types::VOID)}.to raise_error(NotImplementedError)
|
|
253
|
+
expect { @prot.get_type_name_for_type_id(Thrift::Types::STOP) }.to raise_error(NotImplementedError)
|
|
254
|
+
expect { @prot.get_type_name_for_type_id(Thrift::Types::VOID) }.to raise_error(NotImplementedError)
|
|
258
255
|
expect(@prot.get_type_name_for_type_id(Thrift::Types::BOOL)).to eq("tf")
|
|
259
256
|
expect(@prot.get_type_name_for_type_id(Thrift::Types::BYTE)).to eq("i8")
|
|
260
257
|
expect(@prot.get_type_name_for_type_id(Thrift::Types::DOUBLE)).to eq("dbl")
|
|
@@ -269,7 +266,7 @@ describe 'JsonProtocol' do
|
|
|
269
266
|
end
|
|
270
267
|
|
|
271
268
|
it "should get type id for type name" do
|
|
272
|
-
expect {@prot.get_type_id_for_type_name("pp")}.to raise_error(NotImplementedError)
|
|
269
|
+
expect { @prot.get_type_id_for_type_name("pp") }.to raise_error(NotImplementedError)
|
|
273
270
|
expect(@prot.get_type_id_for_type_name("tf")).to eq(Thrift::Types::BOOL)
|
|
274
271
|
expect(@prot.get_type_id_for_type_name("i8")).to eq(Thrift::Types::BYTE)
|
|
275
272
|
expect(@prot.get_type_id_for_type_name("dbl")).to eq(Thrift::Types::DOUBLE)
|
|
@@ -285,7 +282,7 @@ describe 'JsonProtocol' do
|
|
|
285
282
|
|
|
286
283
|
it "should read json syntax char" do
|
|
287
284
|
@trans.write('F')
|
|
288
|
-
expect {@prot.read_json_syntax_char('G')}.to raise_error(Thrift::ProtocolException)
|
|
285
|
+
expect { @prot.read_json_syntax_char('G') }.to raise_error(Thrift::ProtocolException)
|
|
289
286
|
@trans.write('H')
|
|
290
287
|
@prot.read_json_syntax_char('H')
|
|
291
288
|
end
|
|
@@ -321,7 +318,7 @@ describe 'JsonProtocol' do
|
|
|
321
318
|
|
|
322
319
|
it "should read json string" do
|
|
323
320
|
@trans.write("\"\\P")
|
|
324
|
-
expect {@prot.read_json_string(false)}.to raise_error(Thrift::ProtocolException)
|
|
321
|
+
expect { @prot.read_json_string(false) }.to raise_error(Thrift::ProtocolException)
|
|
325
322
|
|
|
326
323
|
@trans.write("\"this is a test string\"")
|
|
327
324
|
expect(@prot.read_json_string).to eq("this is a test string")
|
|
@@ -358,7 +355,7 @@ describe 'JsonProtocol' do
|
|
|
358
355
|
|
|
359
356
|
it "should read json integer" do
|
|
360
357
|
@trans.write("1.45\"\"")
|
|
361
|
-
expect {@prot.read_json_integer}.to raise_error(Thrift::ProtocolException)
|
|
358
|
+
expect { @prot.read_json_integer }.to raise_error(Thrift::ProtocolException)
|
|
362
359
|
@prot.read_string
|
|
363
360
|
|
|
364
361
|
@trans.write("1453T")
|
|
@@ -367,11 +364,11 @@ describe 'JsonProtocol' do
|
|
|
367
364
|
|
|
368
365
|
it "should read json double" do
|
|
369
366
|
@trans.write("1.45e3e01\"\"")
|
|
370
|
-
expect {@prot.read_json_double}.to raise_error(Thrift::ProtocolException)
|
|
367
|
+
expect { @prot.read_json_double }.to raise_error(Thrift::ProtocolException)
|
|
371
368
|
@prot.read_string
|
|
372
369
|
|
|
373
370
|
@trans.write("\"1.453e01\"")
|
|
374
|
-
expect {@prot.read_json_double}.to raise_error(Thrift::ProtocolException)
|
|
371
|
+
expect { @prot.read_json_double }.to raise_error(Thrift::ProtocolException)
|
|
375
372
|
|
|
376
373
|
@trans.write("1.453e01\"\"")
|
|
377
374
|
expect(@prot.read_json_double).to eq(14.53)
|
|
@@ -409,7 +406,7 @@ describe 'JsonProtocol' do
|
|
|
409
406
|
|
|
410
407
|
it "should read_message_begin" do
|
|
411
408
|
@trans.write("[2,")
|
|
412
|
-
expect {@prot.read_message_begin}.to raise_error(Thrift::ProtocolException)
|
|
409
|
+
expect { @prot.read_message_begin }.to raise_error(Thrift::ProtocolException)
|
|
413
410
|
|
|
414
411
|
@trans.write("[1,\"name\",12,32\"\"")
|
|
415
412
|
expect(@prot.read_message_begin).to eq(["name", 12, 32])
|
|
@@ -504,25 +501,18 @@ describe 'JsonProtocol' do
|
|
|
504
501
|
expect(@prot.read_double).to eq(12.23)
|
|
505
502
|
end
|
|
506
503
|
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
end
|
|
504
|
+
it 'should read string' do
|
|
505
|
+
@trans.write('"this is a test string"'.force_encoding(Encoding::BINARY))
|
|
506
|
+
a = @prot.read_string
|
|
507
|
+
expect(a).to eq('this is a test string')
|
|
508
|
+
expect(a.encoding).to eq(Encoding::UTF_8)
|
|
509
|
+
end
|
|
514
510
|
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
end
|
|
521
|
-
else
|
|
522
|
-
it 'should read string' do
|
|
523
|
-
@trans.write('"this is a test string"')
|
|
524
|
-
expect(@prot.read_string).to eq('this is a test string')
|
|
525
|
-
end
|
|
511
|
+
it 'should read string with unicode characters' do
|
|
512
|
+
@trans.write('"this is a test string with unicode characters: \u20AC \u20AD"'.force_encoding(Encoding::BINARY))
|
|
513
|
+
a = @prot.read_string
|
|
514
|
+
expect(a).to eq("this is a test string with unicode characters: \u20AC \u20AD")
|
|
515
|
+
expect(a.encoding).to eq(Encoding::UTF_8)
|
|
526
516
|
end
|
|
527
517
|
|
|
528
518
|
it "should read binary" do
|
|
@@ -534,7 +524,17 @@ describe 'JsonProtocol' do
|
|
|
534
524
|
@trans.write("\"AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/w==\"")
|
|
535
525
|
expect(@prot.read_binary.bytes.to_a).to eq((0...256).to_a)
|
|
536
526
|
end
|
|
537
|
-
|
|
527
|
+
|
|
528
|
+
it "should read a uuid" do
|
|
529
|
+
@trans.write("\"00112233-4455-6677-8899-aabbccddeeff\"")
|
|
530
|
+
expect(@prot.read_uuid).to eq("00112233-4455-6677-8899-aabbccddeeff")
|
|
531
|
+
end
|
|
532
|
+
|
|
533
|
+
it "should normalize uppercase uuid on read" do
|
|
534
|
+
@trans.write("\"00112233-4455-6677-8899-AABBCCDDEEFF\"")
|
|
535
|
+
expect(@prot.read_uuid).to eq("00112233-4455-6677-8899-aabbccddeeff")
|
|
536
|
+
end
|
|
537
|
+
|
|
538
538
|
it "should provide a reasonable to_s" do
|
|
539
539
|
expect(@prot.to_s).to eq("json(memory)")
|
|
540
540
|
end
|