]> git.proxmox.com Git - ceph.git/blame - ceph/src/jaegertracing/thrift/lib/d/src/thrift/protocol/binary.d
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / jaegertracing / thrift / lib / d / src / thrift / protocol / binary.d
CommitLineData
f67539c2
TL
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 */
19module thrift.protocol.binary;
20
21import std.array : uninitializedArray;
22import std.typetuple : allSatisfy, TypeTuple;
23import thrift.protocol.base;
24import thrift.transport.base;
25import thrift.internal.endian;
26
27/**
28 * TProtocol implementation of the Binary Thrift protocol.
29 */
30final class TBinaryProtocol(Transport = TTransport) if (
31 isTTransport!Transport
32) : TProtocol {
33
34 /**
35 * Constructs a new instance.
36 *
37 * Params:
38 * trans = The transport to use.
39 * containerSizeLimit = If positive, the container size is limited to the
40 * given number of items.
41 * stringSizeLimit = If positive, the string length is limited to the
42 * given number of bytes.
43 * strictRead = If false, old peers which do not include the protocol
44 * version are tolerated.
45 * strictWrite = Whether to include the protocol version in the header.
46 */
47 this(Transport trans, int containerSizeLimit = 0, int stringSizeLimit = 0,
48 bool strictRead = false, bool strictWrite = true
49 ) {
50 trans_ = trans;
51 this.containerSizeLimit = containerSizeLimit;
52 this.stringSizeLimit = stringSizeLimit;
53 this.strictRead = strictRead;
54 this.strictWrite = strictWrite;
55 }
56
57 Transport transport() @property {
58 return trans_;
59 }
60
61 void reset() {}
62
63 /**
64 * If false, old peers which do not include the protocol version in the
65 * message header are tolerated.
66 *
67 * Defaults to false.
68 */
69 bool strictRead;
70
71 /**
72 * Whether to include the protocol version in the message header (older
73 * versions didn't).
74 *
75 * Defaults to true.
76 */
77 bool strictWrite;
78
79 /**
80 * If positive, limits the number of items of deserialized containers to the
81 * given amount.
82 *
83 * This is useful to avoid allocating excessive amounts of memory when broken
84 * data is received. If the limit is exceeded, a SIZE_LIMIT-type
85 * TProtocolException is thrown.
86 *
87 * Defaults to zero (no limit).
88 */
89 int containerSizeLimit;
90
91 /**
92 * If positive, limits the length of deserialized strings/binary data to the
93 * given number of bytes.
94 *
95 * This is useful to avoid allocating excessive amounts of memory when broken
96 * data is received. If the limit is exceeded, a SIZE_LIMIT-type
97 * TProtocolException is thrown.
98 *
99 * Defaults to zero (no limit).
100 */
101 int stringSizeLimit;
102
103 /*
104 * Writing methods.
105 */
106
107 void writeBool(bool b) {
108 writeByte(b ? 1 : 0);
109 }
110
111 void writeByte(byte b) {
112 trans_.write((cast(ubyte*)&b)[0 .. 1]);
113 }
114
115 void writeI16(short i16) {
116 short net = hostToNet(i16);
117 trans_.write((cast(ubyte*)&net)[0 .. 2]);
118 }
119
120 void writeI32(int i32) {
121 int net = hostToNet(i32);
122 trans_.write((cast(ubyte*)&net)[0 .. 4]);
123 }
124
125 void writeI64(long i64) {
126 long net = hostToNet(i64);
127 trans_.write((cast(ubyte*)&net)[0 .. 8]);
128 }
129
130 void writeDouble(double dub) {
131 static assert(double.sizeof == ulong.sizeof);
132 auto bits = hostToNet(*cast(ulong*)(&dub));
133 trans_.write((cast(ubyte*)&bits)[0 .. 8]);
134 }
135
136 void writeString(string str) {
137 writeBinary(cast(ubyte[])str);
138 }
139
140 void writeBinary(ubyte[] buf) {
141 assert(buf.length <= int.max);
142 writeI32(cast(int)buf.length);
143 trans_.write(buf);
144 }
145
146 void writeMessageBegin(TMessage message) {
147 if (strictWrite) {
148 int versn = VERSION_1 | message.type;
149 writeI32(versn);
150 writeString(message.name);
151 writeI32(message.seqid);
152 } else {
153 writeString(message.name);
154 writeByte(message.type);
155 writeI32(message.seqid);
156 }
157 }
158 void writeMessageEnd() {}
159
160 void writeStructBegin(TStruct tstruct) {}
161 void writeStructEnd() {}
162
163 void writeFieldBegin(TField field) {
164 writeByte(field.type);
165 writeI16(field.id);
166 }
167 void writeFieldEnd() {}
168
169 void writeFieldStop() {
170 writeByte(TType.STOP);
171 }
172
173 void writeListBegin(TList list) {
174 assert(list.size <= int.max);
175 writeByte(list.elemType);
176 writeI32(cast(int)list.size);
177 }
178 void writeListEnd() {}
179
180 void writeMapBegin(TMap map) {
181 assert(map.size <= int.max);
182 writeByte(map.keyType);
183 writeByte(map.valueType);
184 writeI32(cast(int)map.size);
185 }
186 void writeMapEnd() {}
187
188 void writeSetBegin(TSet set) {
189 assert(set.size <= int.max);
190 writeByte(set.elemType);
191 writeI32(cast(int)set.size);
192 }
193 void writeSetEnd() {}
194
195
196 /*
197 * Reading methods.
198 */
199
200 bool readBool() {
201 return readByte() != 0;
202 }
203
204 byte readByte() {
205 ubyte[1] b = void;
206 trans_.readAll(b);
207 return cast(byte)b[0];
208 }
209
210 short readI16() {
211 IntBuf!short b = void;
212 trans_.readAll(b.bytes);
213 return netToHost(b.value);
214 }
215
216 int readI32() {
217 IntBuf!int b = void;
218 trans_.readAll(b.bytes);
219 return netToHost(b.value);
220 }
221
222 long readI64() {
223 IntBuf!long b = void;
224 trans_.readAll(b.bytes);
225 return netToHost(b.value);
226 }
227
228 double readDouble() {
229 IntBuf!long b = void;
230 trans_.readAll(b.bytes);
231 b.value = netToHost(b.value);
232 return *cast(double*)(&b.value);
233 }
234
235 string readString() {
236 return cast(string)readBinary();
237 }
238
239 ubyte[] readBinary() {
240 return readBinaryBody(readSize(stringSizeLimit));
241 }
242
243 TMessage readMessageBegin() {
244 TMessage msg = void;
245
246 int size = readI32();
247 if (size < 0) {
248 int versn = size & VERSION_MASK;
249 if (versn != VERSION_1) {
250 throw new TProtocolException("Bad protocol version.",
251 TProtocolException.Type.BAD_VERSION);
252 }
253
254 msg.type = cast(TMessageType)(size & MESSAGE_TYPE_MASK);
255 msg.name = readString();
256 msg.seqid = readI32();
257 } else {
258 if (strictRead) {
259 throw new TProtocolException(
260 "Protocol version missing, old client?",
261 TProtocolException.Type.BAD_VERSION);
262 } else {
263 if (size < 0) {
264 throw new TProtocolException(TProtocolException.Type.NEGATIVE_SIZE);
265 }
266 msg.name = cast(string)readBinaryBody(size);
267 msg.type = cast(TMessageType)(readByte());
268 msg.seqid = readI32();
269 }
270 }
271
272 return msg;
273 }
274 void readMessageEnd() {}
275
276 TStruct readStructBegin() {
277 return TStruct();
278 }
279 void readStructEnd() {}
280
281 TField readFieldBegin() {
282 TField f = void;
283 f.name = null;
284 f.type = cast(TType)readByte();
285 if (f.type == TType.STOP) return f;
286 f.id = readI16();
287 return f;
288 }
289 void readFieldEnd() {}
290
291 TList readListBegin() {
292 return TList(cast(TType)readByte(), readSize(containerSizeLimit));
293 }
294 void readListEnd() {}
295
296 TMap readMapBegin() {
297 return TMap(cast(TType)readByte(), cast(TType)readByte(),
298 readSize(containerSizeLimit));
299 }
300 void readMapEnd() {}
301
302 TSet readSetBegin() {
303 return TSet(cast(TType)readByte(), readSize(containerSizeLimit));
304 }
305 void readSetEnd() {}
306
307private:
308 ubyte[] readBinaryBody(int size) {
309 if (size == 0) {
310 return null;
311 }
312
313 auto buf = uninitializedArray!(ubyte[])(size);
314 trans_.readAll(buf);
315 return buf;
316 }
317
318 int readSize(int limit) {
319 auto size = readI32();
320 if (size < 0) {
321 throw new TProtocolException(TProtocolException.Type.NEGATIVE_SIZE);
322 } else if (limit > 0 && size > limit) {
323 throw new TProtocolException(TProtocolException.Type.SIZE_LIMIT);
324 }
325 return size;
326 }
327
328 enum MESSAGE_TYPE_MASK = 0x000000ff;
329 enum VERSION_MASK = 0xffff0000;
330 enum VERSION_1 = 0x80010000;
331
332 Transport trans_;
333}
334
335/**
336 * TBinaryProtocol construction helper to avoid having to explicitly specify
337 * the transport type, i.e. to allow the constructor being called using IFTI
338 * (see $(LINK2 http://d.puremagic.com/issues/show_bug.cgi?id=6082, D Bugzilla
339 * enhancement requet 6082)).
340 */
341TBinaryProtocol!Transport tBinaryProtocol(Transport)(Transport trans,
342 int containerSizeLimit = 0, int stringSizeLimit = 0,
343 bool strictRead = false, bool strictWrite = true
344) if (isTTransport!Transport) {
345 return new TBinaryProtocol!Transport(trans, containerSizeLimit,
346 stringSizeLimit, strictRead, strictWrite);
347}
348
349unittest {
350 import std.exception;
351 import thrift.transport.memory;
352
353 // Check the message header format.
354 auto buf = new TMemoryBuffer;
355 auto binary = tBinaryProtocol(buf);
356 binary.writeMessageBegin(TMessage("foo", TMessageType.CALL, 0));
357
358 auto header = new ubyte[15];
359 buf.readAll(header);
360 enforce(header == [
361 128, 1, 0, 1, // Version 1, TMessageType.CALL
362 0, 0, 0, 3, // Method name length
363 102, 111, 111, // Method name ("foo")
364 0, 0, 0, 0, // Sequence id
365 ]);
366}
367
368unittest {
369 import thrift.internal.test.protocol;
370 testContainerSizeLimit!(TBinaryProtocol!())();
371 testStringSizeLimit!(TBinaryProtocol!())();
372}
373
374/**
375 * TProtocolFactory creating a TBinaryProtocol instance for passed in
376 * transports.
377 *
378 * The optional Transports template tuple parameter can be used to specify
379 * one or more TTransport implementations to specifically instantiate
380 * TBinaryProtocol for. If the actual transport types encountered at
381 * runtime match one of the transports in the list, a specialized protocol
382 * instance is created. Otherwise, a generic TTransport version is used.
383 */
384class TBinaryProtocolFactory(Transports...) if (
385 allSatisfy!(isTTransport, Transports)
386) : TProtocolFactory {
387 ///
388 this (int containerSizeLimit = 0, int stringSizeLimit = 0,
389 bool strictRead = false, bool strictWrite = true
390 ) {
391 strictRead_ = strictRead;
392 strictWrite_ = strictWrite;
393 containerSizeLimit_ = containerSizeLimit;
394 stringSizeLimit_ = stringSizeLimit;
395 }
396
397 TProtocol getProtocol(TTransport trans) const {
398 foreach (Transport; TypeTuple!(Transports, TTransport)) {
399 auto concreteTrans = cast(Transport)trans;
400 if (concreteTrans) {
401 return new TBinaryProtocol!Transport(concreteTrans,
402 containerSizeLimit_, stringSizeLimit_, strictRead_, strictWrite_);
403 }
404 }
405 throw new TProtocolException(
406 "Passed null transport to TBinaryProtocolFactoy.");
407 }
408
409protected:
410 bool strictRead_;
411 bool strictWrite_;
412 int containerSizeLimit_;
413 int stringSizeLimit_;
414}