blob: 4b58e639da265dac212915ec092cc1b9a6cbf4a8 [file] [log] [blame]
Neil Williams66a44c52018-08-13 16:12:24 -07001#
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
20from thrift.protocol.TBinaryProtocol import TBinaryProtocolAccelerated
21from thrift.protocol.TCompactProtocol import TCompactProtocolAccelerated
James E. King IIIe44f6a92019-02-07 17:11:21 -050022from thrift.protocol.TProtocol import TProtocolBase, TProtocolException, TProtocolFactory
Neil Williams66a44c52018-08-13 16:12:24 -070023from thrift.Thrift import TApplicationException, TMessageType
24from thrift.transport.THeaderTransport import THeaderTransport, THeaderSubprotocolID, THeaderClientType
25
26
27PROTOCOLS_BY_ID = {
28 THeaderSubprotocolID.BINARY: TBinaryProtocolAccelerated,
29 THeaderSubprotocolID.COMPACT: TCompactProtocolAccelerated,
30}
31
32
33class THeaderProtocol(TProtocolBase):
34 """A framed protocol with headers and payload transforms.
35
36 THeaderProtocol frames other Thrift protocols and adds support for optional
37 out-of-band headers. The currently supported subprotocols are
Neil Williams1c35d6b2021-01-04 11:27:01 -080038 TBinaryProtocol and TCompactProtocol. When used as a client, the
39 subprotocol to frame can be chosen with the `default_protocol` parameter to
40 the constructor.
Neil Williams66a44c52018-08-13 16:12:24 -070041
42 It's also possible to apply transforms to the encoded message payload. The
43 only transform currently supported is to gzip.
44
45 When used in a server, THeaderProtocol can accept messages from
46 non-THeaderProtocol clients if allowed (see `allowed_client_types`). This
47 includes framed and unframed transports and both TBinaryProtocol and
48 TCompactProtocol. The server will respond in the appropriate dialect for
49 the connected client. HTTP clients are not currently supported.
50
51 THeaderProtocol does not currently support THTTPServer, TNonblockingServer,
52 or TProcessPoolServer.
53
54 See doc/specs/HeaderFormat.md for details of the wire format.
55
56 """
57
Neil Williams1c35d6b2021-01-04 11:27:01 -080058 def __init__(self, transport, allowed_client_types, default_protocol=THeaderSubprotocolID.BINARY):
Neil Williams66a44c52018-08-13 16:12:24 -070059 # much of the actual work for THeaderProtocol happens down in
60 # THeaderTransport since we need to do low-level shenanigans to detect
61 # if the client is sending us headers or one of the headerless formats
62 # we support. this wraps the real transport with the one that does all
63 # the magic.
64 if not isinstance(transport, THeaderTransport):
Neil Williams1c35d6b2021-01-04 11:27:01 -080065 transport = THeaderTransport(transport, allowed_client_types, default_protocol)
Neil Williams66a44c52018-08-13 16:12:24 -070066 super(THeaderProtocol, self).__init__(transport)
67 self._set_protocol()
68
69 def get_headers(self):
70 return self.trans.get_headers()
71
72 def set_header(self, key, value):
73 self.trans.set_header(key, value)
74
75 def clear_headers(self):
76 self.trans.clear_headers()
77
78 def add_transform(self, transform_id):
79 self.trans.add_transform(transform_id)
80
81 def writeMessageBegin(self, name, ttype, seqid):
82 self.trans.sequence_id = seqid
83 return self._protocol.writeMessageBegin(name, ttype, seqid)
84
85 def writeMessageEnd(self):
86 return self._protocol.writeMessageEnd()
87
88 def writeStructBegin(self, name):
89 return self._protocol.writeStructBegin(name)
90
91 def writeStructEnd(self):
92 return self._protocol.writeStructEnd()
93
94 def writeFieldBegin(self, name, ttype, fid):
95 return self._protocol.writeFieldBegin(name, ttype, fid)
96
97 def writeFieldEnd(self):
98 return self._protocol.writeFieldEnd()
99
100 def writeFieldStop(self):
101 return self._protocol.writeFieldStop()
102
103 def writeMapBegin(self, ktype, vtype, size):
104 return self._protocol.writeMapBegin(ktype, vtype, size)
105
106 def writeMapEnd(self):
107 return self._protocol.writeMapEnd()
108
109 def writeListBegin(self, etype, size):
110 return self._protocol.writeListBegin(etype, size)
111
112 def writeListEnd(self):
113 return self._protocol.writeListEnd()
114
115 def writeSetBegin(self, etype, size):
116 return self._protocol.writeSetBegin(etype, size)
117
118 def writeSetEnd(self):
119 return self._protocol.writeSetEnd()
120
121 def writeBool(self, bool_val):
122 return self._protocol.writeBool(bool_val)
123
124 def writeByte(self, byte):
125 return self._protocol.writeByte(byte)
126
127 def writeI16(self, i16):
128 return self._protocol.writeI16(i16)
129
130 def writeI32(self, i32):
131 return self._protocol.writeI32(i32)
132
133 def writeI64(self, i64):
134 return self._protocol.writeI64(i64)
135
136 def writeDouble(self, dub):
137 return self._protocol.writeDouble(dub)
138
139 def writeBinary(self, str_val):
140 return self._protocol.writeBinary(str_val)
141
142 def _set_protocol(self):
143 try:
144 protocol_cls = PROTOCOLS_BY_ID[self.trans.protocol_id]
145 except KeyError:
146 raise TApplicationException(
147 TProtocolException.INVALID_PROTOCOL,
148 "Unknown protocol requested.",
149 )
150
151 self._protocol = protocol_cls(self.trans)
152 self._fast_encode = self._protocol._fast_encode
153 self._fast_decode = self._protocol._fast_decode
154
155 def readMessageBegin(self):
156 try:
157 self.trans.readFrame(0)
158 self._set_protocol()
159 except TApplicationException as exc:
160 self._protocol.writeMessageBegin(b"", TMessageType.EXCEPTION, 0)
161 exc.write(self._protocol)
162 self._protocol.writeMessageEnd()
163 self.trans.flush()
164
165 return self._protocol.readMessageBegin()
166
167 def readMessageEnd(self):
168 return self._protocol.readMessageEnd()
169
170 def readStructBegin(self):
171 return self._protocol.readStructBegin()
172
173 def readStructEnd(self):
174 return self._protocol.readStructEnd()
175
176 def readFieldBegin(self):
177 return self._protocol.readFieldBegin()
178
179 def readFieldEnd(self):
180 return self._protocol.readFieldEnd()
181
182 def readMapBegin(self):
183 return self._protocol.readMapBegin()
184
185 def readMapEnd(self):
186 return self._protocol.readMapEnd()
187
188 def readListBegin(self):
189 return self._protocol.readListBegin()
190
191 def readListEnd(self):
192 return self._protocol.readListEnd()
193
194 def readSetBegin(self):
195 return self._protocol.readSetBegin()
196
197 def readSetEnd(self):
198 return self._protocol.readSetEnd()
199
200 def readBool(self):
201 return self._protocol.readBool()
202
203 def readByte(self):
204 return self._protocol.readByte()
205
206 def readI16(self):
207 return self._protocol.readI16()
208
209 def readI32(self):
210 return self._protocol.readI32()
211
212 def readI64(self):
213 return self._protocol.readI64()
214
215 def readDouble(self):
216 return self._protocol.readDouble()
217
218 def readBinary(self):
219 return self._protocol.readBinary()
220
221
James E. King IIIe44f6a92019-02-07 17:11:21 -0500222class THeaderProtocolFactory(TProtocolFactory):
Neil Williams1c35d6b2021-01-04 11:27:01 -0800223 def __init__(
224 self,
225 allowed_client_types=(THeaderClientType.HEADERS,),
226 default_protocol=THeaderSubprotocolID.BINARY,
227 ):
Neil Williams66a44c52018-08-13 16:12:24 -0700228 self.allowed_client_types = allowed_client_types
Neil Williams1c35d6b2021-01-04 11:27:01 -0800229 self.default_protocol = default_protocol
Neil Williams66a44c52018-08-13 16:12:24 -0700230
231 def getProtocol(self, trans):
Neil Williams1c35d6b2021-01-04 11:27:01 -0800232 return THeaderProtocol(trans, self.allowed_client_types, self.default_protocol)