blob: e485cffb1451ab45f907543e23a4371c00b621e0 [file] [log] [blame]
Roger Meierf4eec7a2011-09-11 18:16:21 +00001#
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
Nobuaki Sukegawa760511f2015-11-06 21:24:16 +090020from .TProtocol import TType, TProtocolBase, TProtocolException, checkIntegerLimits
David Reissabafd792010-09-27 17:28:15 +000021from struct import pack, unpack
22
Nobuaki Sukegawa760511f2015-11-06 21:24:16 +090023from ..compat import binary_to_str, str_to_binary
24
David Reissabafd792010-09-27 17:28:15 +000025__all__ = ['TCompactProtocol', 'TCompactProtocolFactory']
26
27CLEAR = 0
28FIELD_WRITE = 1
29VALUE_WRITE = 2
30CONTAINER_WRITE = 3
31BOOL_WRITE = 4
32FIELD_READ = 5
33CONTAINER_READ = 6
34VALUE_READ = 7
35BOOL_READ = 8
36
Bryan Duxbury69720412012-01-03 17:32:30 +000037
David Reissabafd792010-09-27 17:28:15 +000038def make_helper(v_from, container):
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +090039 def helper(func):
40 def nested(self, *args, **kwargs):
41 assert self.state in (v_from, container), (self.state, v_from, container)
42 return func(self, *args, **kwargs)
43 return nested
44 return helper
James E. King, III0ad20bd2017-09-30 15:44:16 -070045
46
David Reissabafd792010-09-27 17:28:15 +000047writer = make_helper(VALUE_WRITE, CONTAINER_WRITE)
48reader = make_helper(VALUE_READ, CONTAINER_READ)
49
Bryan Duxbury69720412012-01-03 17:32:30 +000050
David Reissabafd792010-09-27 17:28:15 +000051def makeZigZag(n, bits):
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +090052 checkIntegerLimits(n, bits)
53 return (n << 1) ^ (n >> (bits - 1))
David Reissabafd792010-09-27 17:28:15 +000054
Bryan Duxbury69720412012-01-03 17:32:30 +000055
David Reissabafd792010-09-27 17:28:15 +000056def fromZigZag(n):
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +090057 return (n >> 1) ^ -(n & 1)
David Reissabafd792010-09-27 17:28:15 +000058
Bryan Duxbury69720412012-01-03 17:32:30 +000059
David Reissabafd792010-09-27 17:28:15 +000060def writeVarint(trans, n):
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +090061 out = bytearray()
62 while True:
63 if n & ~0x7f == 0:
64 out.append(n)
65 break
66 else:
67 out.append((n & 0xff) | 0x80)
68 n = n >> 7
69 trans.write(bytes(out))
David Reissabafd792010-09-27 17:28:15 +000070
Bryan Duxbury69720412012-01-03 17:32:30 +000071
David Reissabafd792010-09-27 17:28:15 +000072def readVarint(trans):
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +090073 result = 0
74 shift = 0
75 while True:
76 x = trans.readAll(1)
77 byte = ord(x)
78 result |= (byte & 0x7f) << shift
79 if byte >> 7 == 0:
80 return result
81 shift += 7
David Reissabafd792010-09-27 17:28:15 +000082
Bryan Duxbury69720412012-01-03 17:32:30 +000083
Nobuaki Sukegawab9c859a2015-12-21 01:10:25 +090084class CompactType(object):
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +090085 STOP = 0x00
86 TRUE = 0x01
87 FALSE = 0x02
88 BYTE = 0x03
89 I16 = 0x04
90 I32 = 0x05
91 I64 = 0x06
92 DOUBLE = 0x07
93 BINARY = 0x08
94 LIST = 0x09
95 SET = 0x0A
96 MAP = 0x0B
97 STRUCT = 0x0C
David Reissabafd792010-09-27 17:28:15 +000098
James E. King, III0ad20bd2017-09-30 15:44:16 -070099
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900100CTYPES = {
101 TType.STOP: CompactType.STOP,
102 TType.BOOL: CompactType.TRUE, # used for collection
103 TType.BYTE: CompactType.BYTE,
104 TType.I16: CompactType.I16,
105 TType.I32: CompactType.I32,
106 TType.I64: CompactType.I64,
107 TType.DOUBLE: CompactType.DOUBLE,
108 TType.STRING: CompactType.BINARY,
109 TType.STRUCT: CompactType.STRUCT,
110 TType.LIST: CompactType.LIST,
111 TType.SET: CompactType.SET,
112 TType.MAP: CompactType.MAP,
113}
David Reissabafd792010-09-27 17:28:15 +0000114
115TTYPES = {}
116for k, v in CTYPES.items():
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900117 TTYPES[v] = k
David Reissabafd792010-09-27 17:28:15 +0000118TTYPES[CompactType.FALSE] = TType.BOOL
119del k
120del v
121
Bryan Duxbury69720412012-01-03 17:32:30 +0000122
David Reissabafd792010-09-27 17:28:15 +0000123class TCompactProtocol(TProtocolBase):
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900124 """Compact implementation of the Thrift protocol driver."""
David Reissabafd792010-09-27 17:28:15 +0000125
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900126 PROTOCOL_ID = 0x82
127 VERSION = 1
128 VERSION_MASK = 0x1f
129 TYPE_MASK = 0xe0
130 TYPE_BITS = 0x07
131 TYPE_SHIFT_AMOUNT = 5
David Reissabafd792010-09-27 17:28:15 +0000132
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900133 def __init__(self, trans,
134 string_length_limit=None,
135 container_length_limit=None):
136 TProtocolBase.__init__(self, trans)
137 self.state = CLEAR
138 self.__last_fid = 0
139 self.__bool_fid = None
140 self.__bool_value = None
141 self.__structs = []
142 self.__containers = []
143 self.string_length_limit = string_length_limit
144 self.container_length_limit = container_length_limit
Nobuaki Sukegawa7b545b52016-01-11 13:46:04 +0900145
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900146 def _check_string_length(self, length):
147 self._check_length(self.string_length_limit, length)
Nobuaki Sukegawa7b545b52016-01-11 13:46:04 +0900148
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900149 def _check_container_length(self, length):
150 self._check_length(self.container_length_limit, length)
David Reissabafd792010-09-27 17:28:15 +0000151
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900152 def __writeVarint(self, n):
153 writeVarint(self.trans, n)
David Reissabafd792010-09-27 17:28:15 +0000154
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900155 def writeMessageBegin(self, name, type, seqid):
156 assert self.state == CLEAR
157 self.__writeUByte(self.PROTOCOL_ID)
158 self.__writeUByte(self.VERSION | (type << self.TYPE_SHIFT_AMOUNT))
159 self.__writeVarint(seqid)
160 self.__writeBinary(str_to_binary(name))
161 self.state = VALUE_WRITE
David Reissabafd792010-09-27 17:28:15 +0000162
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900163 def writeMessageEnd(self):
164 assert self.state == VALUE_WRITE
165 self.state = CLEAR
David Reissabafd792010-09-27 17:28:15 +0000166
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900167 def writeStructBegin(self, name):
168 assert self.state in (CLEAR, CONTAINER_WRITE, VALUE_WRITE), self.state
169 self.__structs.append((self.state, self.__last_fid))
170 self.state = FIELD_WRITE
171 self.__last_fid = 0
David Reissabafd792010-09-27 17:28:15 +0000172
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900173 def writeStructEnd(self):
174 assert self.state == FIELD_WRITE
175 self.state, self.__last_fid = self.__structs.pop()
David Reissabafd792010-09-27 17:28:15 +0000176
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900177 def writeFieldStop(self):
178 self.__writeByte(0)
David Reissabafd792010-09-27 17:28:15 +0000179
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900180 def __writeFieldHeader(self, type, fid):
181 delta = fid - self.__last_fid
182 if 0 < delta <= 15:
183 self.__writeUByte(delta << 4 | type)
184 else:
185 self.__writeByte(type)
186 self.__writeI16(fid)
187 self.__last_fid = fid
David Reissabafd792010-09-27 17:28:15 +0000188
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900189 def writeFieldBegin(self, name, type, fid):
190 assert self.state == FIELD_WRITE, self.state
191 if type == TType.BOOL:
192 self.state = BOOL_WRITE
193 self.__bool_fid = fid
194 else:
195 self.state = VALUE_WRITE
196 self.__writeFieldHeader(CTYPES[type], fid)
David Reissabafd792010-09-27 17:28:15 +0000197
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900198 def writeFieldEnd(self):
199 assert self.state in (VALUE_WRITE, BOOL_WRITE), self.state
200 self.state = FIELD_WRITE
David Reissabafd792010-09-27 17:28:15 +0000201
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900202 def __writeUByte(self, byte):
203 self.trans.write(pack('!B', byte))
David Reissabafd792010-09-27 17:28:15 +0000204
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900205 def __writeByte(self, byte):
206 self.trans.write(pack('!b', byte))
David Reissabafd792010-09-27 17:28:15 +0000207
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900208 def __writeI16(self, i16):
209 self.__writeVarint(makeZigZag(i16, 16))
David Reissabafd792010-09-27 17:28:15 +0000210
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900211 def __writeSize(self, i32):
212 self.__writeVarint(i32)
David Reissabafd792010-09-27 17:28:15 +0000213
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900214 def writeCollectionBegin(self, etype, size):
215 assert self.state in (VALUE_WRITE, CONTAINER_WRITE), self.state
216 if size <= 14:
217 self.__writeUByte(size << 4 | CTYPES[etype])
218 else:
219 self.__writeUByte(0xf0 | CTYPES[etype])
220 self.__writeSize(size)
221 self.__containers.append(self.state)
222 self.state = CONTAINER_WRITE
223 writeSetBegin = writeCollectionBegin
224 writeListBegin = writeCollectionBegin
David Reissabafd792010-09-27 17:28:15 +0000225
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900226 def writeMapBegin(self, ktype, vtype, size):
227 assert self.state in (VALUE_WRITE, CONTAINER_WRITE), self.state
228 if size == 0:
229 self.__writeByte(0)
230 else:
231 self.__writeSize(size)
232 self.__writeUByte(CTYPES[ktype] << 4 | CTYPES[vtype])
233 self.__containers.append(self.state)
234 self.state = CONTAINER_WRITE
David Reissabafd792010-09-27 17:28:15 +0000235
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900236 def writeCollectionEnd(self):
237 assert self.state == CONTAINER_WRITE, self.state
238 self.state = self.__containers.pop()
239 writeMapEnd = writeCollectionEnd
240 writeSetEnd = writeCollectionEnd
241 writeListEnd = writeCollectionEnd
David Reissabafd792010-09-27 17:28:15 +0000242
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900243 def writeBool(self, bool):
244 if self.state == BOOL_WRITE:
245 if bool:
246 ctype = CompactType.TRUE
247 else:
248 ctype = CompactType.FALSE
249 self.__writeFieldHeader(ctype, self.__bool_fid)
250 elif self.state == CONTAINER_WRITE:
251 if bool:
252 self.__writeByte(CompactType.TRUE)
253 else:
254 self.__writeByte(CompactType.FALSE)
255 else:
256 raise AssertionError("Invalid state in compact protocol")
David Reissabafd792010-09-27 17:28:15 +0000257
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900258 writeByte = writer(__writeByte)
259 writeI16 = writer(__writeI16)
David Reissabafd792010-09-27 17:28:15 +0000260
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900261 @writer
262 def writeI32(self, i32):
263 self.__writeVarint(makeZigZag(i32, 32))
David Reissabafd792010-09-27 17:28:15 +0000264
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900265 @writer
266 def writeI64(self, i64):
267 self.__writeVarint(makeZigZag(i64, 64))
David Reissabafd792010-09-27 17:28:15 +0000268
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900269 @writer
270 def writeDouble(self, dub):
271 self.trans.write(pack('<d', dub))
David Reissabafd792010-09-27 17:28:15 +0000272
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900273 def __writeBinary(self, s):
274 self.__writeSize(len(s))
275 self.trans.write(s)
276 writeBinary = writer(__writeBinary)
David Reissabafd792010-09-27 17:28:15 +0000277
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900278 def readFieldBegin(self):
279 assert self.state == FIELD_READ, self.state
280 type = self.__readUByte()
281 if type & 0x0f == TType.STOP:
282 return (None, 0, 0)
283 delta = type >> 4
284 if delta == 0:
285 fid = self.__readI16()
286 else:
287 fid = self.__last_fid + delta
288 self.__last_fid = fid
289 type = type & 0x0f
290 if type == CompactType.TRUE:
291 self.state = BOOL_READ
292 self.__bool_value = True
293 elif type == CompactType.FALSE:
294 self.state = BOOL_READ
295 self.__bool_value = False
296 else:
297 self.state = VALUE_READ
298 return (None, self.__getTType(type), fid)
David Reissabafd792010-09-27 17:28:15 +0000299
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900300 def readFieldEnd(self):
301 assert self.state in (VALUE_READ, BOOL_READ), self.state
302 self.state = FIELD_READ
David Reissabafd792010-09-27 17:28:15 +0000303
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900304 def __readUByte(self):
305 result, = unpack('!B', self.trans.readAll(1))
306 return result
David Reissabafd792010-09-27 17:28:15 +0000307
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900308 def __readByte(self):
309 result, = unpack('!b', self.trans.readAll(1))
310 return result
David Reissabafd792010-09-27 17:28:15 +0000311
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900312 def __readVarint(self):
313 return readVarint(self.trans)
David Reissabafd792010-09-27 17:28:15 +0000314
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900315 def __readZigZag(self):
316 return fromZigZag(self.__readVarint())
David Reissabafd792010-09-27 17:28:15 +0000317
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900318 def __readSize(self):
319 result = self.__readVarint()
320 if result < 0:
321 raise TProtocolException("Length < 0")
322 return result
David Reissabafd792010-09-27 17:28:15 +0000323
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900324 def readMessageBegin(self):
325 assert self.state == CLEAR
326 proto_id = self.__readUByte()
327 if proto_id != self.PROTOCOL_ID:
328 raise TProtocolException(TProtocolException.BAD_VERSION,
329 'Bad protocol id in the message: %d' % proto_id)
330 ver_type = self.__readUByte()
331 type = (ver_type >> self.TYPE_SHIFT_AMOUNT) & self.TYPE_BITS
332 version = ver_type & self.VERSION_MASK
333 if version != self.VERSION:
334 raise TProtocolException(TProtocolException.BAD_VERSION,
335 'Bad version: %d (expect %d)' % (version, self.VERSION))
336 seqid = self.__readVarint()
337 name = binary_to_str(self.__readBinary())
338 return (name, type, seqid)
David Reissabafd792010-09-27 17:28:15 +0000339
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900340 def readMessageEnd(self):
341 assert self.state == CLEAR
342 assert len(self.__structs) == 0
David Reissabafd792010-09-27 17:28:15 +0000343
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900344 def readStructBegin(self):
345 assert self.state in (CLEAR, CONTAINER_READ, VALUE_READ), self.state
346 self.__structs.append((self.state, self.__last_fid))
347 self.state = FIELD_READ
348 self.__last_fid = 0
David Reissabafd792010-09-27 17:28:15 +0000349
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900350 def readStructEnd(self):
351 assert self.state == FIELD_READ
352 self.state, self.__last_fid = self.__structs.pop()
David Reissabafd792010-09-27 17:28:15 +0000353
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900354 def readCollectionBegin(self):
355 assert self.state in (VALUE_READ, CONTAINER_READ), self.state
356 size_type = self.__readUByte()
357 size = size_type >> 4
358 type = self.__getTType(size_type)
359 if size == 15:
360 size = self.__readSize()
361 self._check_container_length(size)
362 self.__containers.append(self.state)
363 self.state = CONTAINER_READ
364 return type, size
365 readSetBegin = readCollectionBegin
366 readListBegin = readCollectionBegin
David Reissabafd792010-09-27 17:28:15 +0000367
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900368 def readMapBegin(self):
369 assert self.state in (VALUE_READ, CONTAINER_READ), self.state
370 size = self.__readSize()
371 self._check_container_length(size)
372 types = 0
373 if size > 0:
374 types = self.__readUByte()
375 vtype = self.__getTType(types)
376 ktype = self.__getTType(types >> 4)
377 self.__containers.append(self.state)
378 self.state = CONTAINER_READ
379 return (ktype, vtype, size)
David Reissabafd792010-09-27 17:28:15 +0000380
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900381 def readCollectionEnd(self):
382 assert self.state == CONTAINER_READ, self.state
383 self.state = self.__containers.pop()
384 readSetEnd = readCollectionEnd
385 readListEnd = readCollectionEnd
386 readMapEnd = readCollectionEnd
David Reissabafd792010-09-27 17:28:15 +0000387
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900388 def readBool(self):
389 if self.state == BOOL_READ:
390 return self.__bool_value == CompactType.TRUE
391 elif self.state == CONTAINER_READ:
392 return self.__readByte() == CompactType.TRUE
393 else:
394 raise AssertionError("Invalid state in compact protocol: %d" %
395 self.state)
David Reissabafd792010-09-27 17:28:15 +0000396
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900397 readByte = reader(__readByte)
398 __readI16 = __readZigZag
399 readI16 = reader(__readZigZag)
400 readI32 = reader(__readZigZag)
401 readI64 = reader(__readZigZag)
David Reissabafd792010-09-27 17:28:15 +0000402
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900403 @reader
404 def readDouble(self):
405 buff = self.trans.readAll(8)
406 val, = unpack('<d', buff)
407 return val
David Reissabafd792010-09-27 17:28:15 +0000408
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900409 def __readBinary(self):
410 size = self.__readSize()
411 self._check_string_length(size)
412 return self.trans.readAll(size)
413 readBinary = reader(__readBinary)
David Reissabafd792010-09-27 17:28:15 +0000414
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900415 def __getTType(self, byte):
416 return TTYPES[byte & 0x0f]
David Reissabafd792010-09-27 17:28:15 +0000417
418
Nobuaki Sukegawab9c859a2015-12-21 01:10:25 +0900419class TCompactProtocolFactory(object):
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900420 def __init__(self,
421 string_length_limit=None,
422 container_length_limit=None):
423 self.string_length_limit = string_length_limit
424 self.container_length_limit = container_length_limit
David Reissabafd792010-09-27 17:28:15 +0000425
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900426 def getProtocol(self, trans):
427 return TCompactProtocol(trans,
428 self.string_length_limit,
429 self.container_length_limit)
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900430
431
432class TCompactProtocolAccelerated(TCompactProtocol):
433 """C-Accelerated version of TCompactProtocol.
434
435 This class does not override any of TCompactProtocol's methods,
436 but the generated code recognizes it directly and will call into
437 our C module to do the encoding, bypassing this object entirely.
438 We inherit from TCompactProtocol so that the normal TCompactProtocol
439 encoding can happen if the fastbinary module doesn't work for some
440 reason.
441 To disable this behavior, pass fallback=False constructor argument.
442
443 In order to take advantage of the C module, just use
444 TCompactProtocolAccelerated instead of TCompactProtocol.
445 """
446 pass
447
448 def __init__(self, *args, **kwargs):
449 fallback = kwargs.pop('fallback', True)
450 super(TCompactProtocolAccelerated, self).__init__(*args, **kwargs)
451 try:
452 from thrift.protocol import fastbinary
453 except ImportError:
454 if not fallback:
455 raise
456 else:
457 self._fast_decode = fastbinary.decode_compact
458 self._fast_encode = fastbinary.encode_compact
459
460
461class TCompactProtocolAcceleratedFactory(object):
462 def __init__(self,
463 string_length_limit=None,
464 container_length_limit=None,
465 fallback=True):
466 self.string_length_limit = string_length_limit
467 self.container_length_limit = container_length_limit
468 self._fallback = fallback
469
470 def getProtocol(self, trans):
471 return TCompactProtocolAccelerated(
472 trans,
473 string_length_limit=self.string_length_limit,
474 container_length_limit=self.container_length_limit,
475 fallback=self._fallback)