]>
Commit | Line | Data |
---|---|---|
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 | */ | |
19 | ||
20 | import Foundation | |
21 | ||
22 | public struct TBinaryProtocolVersion { | |
23 | static let version1 = Int32(bitPattern: 0x80010000) | |
24 | static let versionMask = Int32(bitPattern: 0xffff0000) | |
25 | } | |
26 | ||
27 | public class TBinaryProtocol: TProtocol { | |
28 | public var messageSizeLimit: UInt32 = 0 | |
29 | ||
30 | public var transport: TTransport | |
31 | ||
32 | // class level properties for setting global config (useful for server in lieu of Factory design) | |
33 | public static var strictRead: Bool = false | |
34 | public static var strictWrite: Bool = true | |
35 | ||
36 | private var strictRead: Bool | |
37 | private var strictWrite: Bool | |
38 | ||
39 | var currentMessageName: String? | |
40 | var currentFieldName: String? | |
41 | ||
42 | ||
43 | public convenience init(transport: TTransport, strictRead: Bool, strictWrite: Bool) { | |
44 | self.init(on: transport) | |
45 | self.strictRead = strictRead | |
46 | self.strictWrite = strictWrite | |
47 | } | |
48 | ||
49 | public required init(on transport: TTransport) { | |
50 | self.transport = transport | |
51 | self.strictWrite = TBinaryProtocol.strictWrite | |
52 | self.strictRead = TBinaryProtocol.strictRead | |
53 | } | |
54 | ||
55 | func readStringBody(_ size: Int) throws -> String { | |
56 | ||
57 | var data = Data() | |
58 | try ProtocolTransportTry(error: TProtocolError(message: "Transport read failed")) { | |
59 | data = try self.transport.readAll(size: size) | |
60 | } | |
61 | ||
62 | return String(data: data, encoding: String.Encoding.utf8) ?? "" | |
63 | } | |
64 | ||
65 | /// Mark: - TProtocol | |
66 | ||
67 | public func readMessageBegin() throws -> (String, TMessageType, Int32) { | |
68 | let size: Int32 = try read() | |
69 | var messageName = "" | |
70 | var type = TMessageType.exception | |
71 | ||
72 | if size < 0 { | |
73 | let version = size & TBinaryProtocolVersion.versionMask | |
74 | if version != TBinaryProtocolVersion.version1 { | |
75 | throw TProtocolError(error: .badVersion(expected: "\(TBinaryProtocolVersion.version1)", | |
76 | got: "\(version)")) | |
77 | } | |
78 | type = TMessageType(rawValue: Int32(size) & 0x00FF) ?? type | |
79 | messageName = try read() | |
80 | } else { | |
81 | if strictRead { | |
82 | let errorMessage = "Missing message version, old client? Message Name: \(currentMessageName ?? "")" | |
83 | throw TProtocolError(error: .invalidData, | |
84 | message: errorMessage) | |
85 | } | |
86 | if messageSizeLimit > 0 && size > Int32(messageSizeLimit) { | |
87 | throw TProtocolError(error: .sizeLimit(limit: Int(messageSizeLimit), got: Int(size))) | |
88 | } | |
89 | ||
90 | messageName = try readStringBody(Int(size)) | |
91 | type = TMessageType(rawValue: Int32(try read() as UInt8)) ?? type | |
92 | } | |
93 | ||
94 | let seqID: Int32 = try read() | |
95 | return (messageName, type, seqID) | |
96 | } | |
97 | ||
98 | public func readMessageEnd() throws { | |
99 | return | |
100 | } | |
101 | ||
102 | public func readStructBegin() throws -> String { | |
103 | return "" | |
104 | } | |
105 | ||
106 | public func readStructEnd() throws { | |
107 | return | |
108 | } | |
109 | ||
110 | public func readFieldBegin() throws -> (String, TType, Int32) { | |
111 | ||
112 | let fieldType = TType(rawValue: Int32(try read() as UInt8)) ?? TType.stop | |
113 | var fieldID: Int32 = 0 | |
114 | ||
115 | if fieldType != .stop { | |
116 | fieldID = Int32(try read() as Int16) | |
117 | } | |
118 | ||
119 | return ("", fieldType, fieldID) | |
120 | } | |
121 | ||
122 | public func readFieldEnd() throws { | |
123 | return | |
124 | } | |
125 | ||
126 | public func readMapBegin() throws -> (TType, TType, Int32) { | |
127 | var raw = Int32(try read() as UInt8) | |
128 | guard let keyType = TType(rawValue: raw) else { | |
129 | throw TProtocolError(message: "Unknown value for keyType TType: \(raw)") | |
130 | } | |
131 | ||
132 | raw = Int32(try read() as UInt8) | |
133 | guard let valueType = TType(rawValue: raw) else { | |
134 | throw TProtocolError(message: "Unknown value for valueType TType: \(raw)") | |
135 | } | |
136 | let size: Int32 = try read() | |
137 | ||
138 | return (keyType, valueType, size) | |
139 | } | |
140 | ||
141 | public func readMapEnd() throws { | |
142 | return | |
143 | } | |
144 | ||
145 | public func readSetBegin() throws -> (TType, Int32) { | |
146 | let raw = Int32(try read() as UInt8) | |
147 | guard let elementType = TType(rawValue: raw) else { | |
148 | throw TProtocolError(message: "Unknown value for elementType TType: \(raw)") | |
149 | } | |
150 | ||
151 | let size: Int32 = try read() | |
152 | ||
153 | return (elementType, size) | |
154 | } | |
155 | ||
156 | public func readSetEnd() throws { | |
157 | return | |
158 | } | |
159 | ||
160 | public func readListBegin() throws -> (TType, Int32) { | |
161 | let raw = Int32(try read() as UInt8) | |
162 | guard let elementType = TType(rawValue: raw) else { | |
163 | throw TProtocolError(message: "Unknown value for elementType TType: \(raw)") | |
164 | } | |
165 | let size: Int32 = try read() | |
166 | ||
167 | return (elementType, size) | |
168 | } | |
169 | ||
170 | public func readListEnd() throws { | |
171 | return | |
172 | } | |
173 | ||
174 | public func read() throws -> String { | |
175 | let data: Data = try read() | |
176 | guard let str = String.init(data: data, encoding: .utf8) else { | |
177 | throw TProtocolError(error: .invalidData, message: "Couldn't encode UTF-8 from data read") | |
178 | } | |
179 | return str | |
180 | } | |
181 | ||
182 | public func read() throws -> Bool { | |
183 | return (try read() as UInt8) == 1 | |
184 | } | |
185 | ||
186 | public func read() throws -> UInt8 { | |
187 | var buff = Data() | |
188 | try ProtocolTransportTry(error: TProtocolError(message: "Transport Read Failed")) { | |
189 | buff = try self.transport.readAll(size: 1) | |
190 | } | |
191 | return buff[0] | |
192 | } | |
193 | ||
194 | public func read() throws -> Int16 { | |
195 | var buff = Data() | |
196 | try ProtocolTransportTry(error: TProtocolError(message: "Transport Read Failed")) { | |
197 | buff = try self.transport.readAll(size: 2) | |
198 | } | |
199 | var ret = Int16(buff[0] & 0xff) << 8 | |
200 | ret |= Int16(buff[1] & 0xff) | |
201 | return ret | |
202 | } | |
203 | ||
204 | public func read() throws -> Int32 { | |
205 | var buff = Data() | |
206 | try ProtocolTransportTry(error: TProtocolError(message: "Transport Read Failed")) { | |
207 | buff = try self.transport.readAll(size: 4) | |
208 | } | |
209 | var ret = Int32(buff[0] & 0xff) << 24 | |
210 | ret |= Int32(buff[1] & 0xff) << 16 | |
211 | ret |= Int32(buff[2] & 0xff) << 8 | |
212 | ret |= Int32(buff[3] & 0xff) | |
213 | ||
214 | return ret | |
215 | } | |
216 | ||
217 | public func read() throws -> Int64 { | |
218 | var buff = Data() | |
219 | try ProtocolTransportTry(error: TProtocolError(message: "Transport Read Failed")) { | |
220 | buff = try self.transport.readAll(size: 8) | |
221 | } | |
222 | var ret = Int64(buff[0] & 0xff) << 56 | |
223 | ret |= Int64(buff[1] & 0xff) << 48 | |
224 | ret |= Int64(buff[2] & 0xff) << 40 | |
225 | ret |= Int64(buff[3] & 0xff) << 32 | |
226 | ret |= Int64(buff[4] & 0xff) << 24 | |
227 | ret |= Int64(buff[5] & 0xff) << 16 | |
228 | ret |= Int64(buff[6] & 0xff) << 8 | |
229 | ret |= Int64(buff[7] & 0xff) | |
230 | ||
231 | return ret | |
232 | } | |
233 | ||
234 | public func read() throws -> Double { | |
235 | let val = try read() as Int64 | |
236 | return Double(bitPattern: UInt64(bitPattern: val)) | |
237 | } | |
238 | ||
239 | public func read() throws -> Data { | |
240 | let size = Int(try read() as Int32) | |
241 | var data = Data() | |
242 | try ProtocolTransportTry(error: TProtocolError(message: "Transport Read Failed")) { | |
243 | data = try self.transport.readAll(size: size) | |
244 | } | |
245 | ||
246 | return data | |
247 | } | |
248 | ||
249 | // Write methods | |
250 | ||
251 | public func writeMessageBegin(name: String, type messageType: TMessageType, sequenceID: Int32) throws { | |
252 | if strictWrite { | |
253 | let version = TBinaryProtocolVersion.version1 | Int32(messageType.rawValue) | |
254 | try write(version) | |
255 | try write(name) | |
256 | try write(sequenceID) | |
257 | } else { | |
258 | try write(name) | |
259 | try write(UInt8(messageType.rawValue)) | |
260 | try write(sequenceID) | |
261 | } | |
262 | currentMessageName = name | |
263 | } | |
264 | ||
265 | public func writeMessageEnd() throws { | |
266 | currentMessageName = nil | |
267 | } | |
268 | ||
269 | public func writeStructBegin(name: String) throws { | |
270 | return | |
271 | } | |
272 | ||
273 | public func writeStructEnd() throws { | |
274 | return | |
275 | } | |
276 | ||
277 | public func writeFieldBegin(name: String, type fieldType: TType, fieldID: Int32) throws { | |
278 | try write(UInt8(fieldType.rawValue)) | |
279 | try write(Int16(fieldID)) | |
280 | } | |
281 | ||
282 | public func writeFieldStop() throws { | |
283 | try write(UInt8(TType.stop.rawValue)) | |
284 | } | |
285 | ||
286 | public func writeFieldEnd() throws { | |
287 | return | |
288 | } | |
289 | ||
290 | public func writeMapBegin(keyType: TType, valueType: TType, size: Int32) throws { | |
291 | try write(UInt8(keyType.rawValue)) | |
292 | try write(UInt8(valueType.rawValue)) | |
293 | try write(size) | |
294 | } | |
295 | ||
296 | public func writeMapEnd() throws { | |
297 | return | |
298 | } | |
299 | ||
300 | public func writeSetBegin(elementType: TType, size: Int32) throws { | |
301 | try write(UInt8(elementType.rawValue)) | |
302 | try write(size) | |
303 | } | |
304 | ||
305 | public func writeSetEnd() throws { | |
306 | return | |
307 | } | |
308 | ||
309 | public func writeListBegin(elementType: TType, size: Int32) throws { | |
310 | try write(UInt8(elementType.rawValue)) | |
311 | try write(size) | |
312 | } | |
313 | ||
314 | public func writeListEnd() throws { | |
315 | return | |
316 | } | |
317 | ||
318 | public func write(_ value: String) throws { | |
319 | try write(value.data(using: .utf8)!) | |
320 | } | |
321 | ||
322 | public func write(_ value: Bool) throws { | |
323 | let byteVal: UInt8 = value ? 1 : 0 | |
324 | try write(byteVal) | |
325 | } | |
326 | ||
327 | public func write(_ value: UInt8) throws { | |
328 | let buff = Data([value]) | |
329 | ||
330 | try ProtocolTransportTry(error: TProtocolError(message: "Transport write failed")) { | |
331 | try self.transport.write(data: buff) | |
332 | } | |
333 | } | |
334 | ||
335 | public func write(_ value: Int16) throws { | |
336 | var buff = Data() | |
337 | buff.append(Data([UInt8(0xff & (value >> 8))])) | |
338 | buff.append(Data([UInt8(0xff & (value))])) | |
339 | try ProtocolTransportTry(error: TProtocolError(message: "Transport write failed")) { | |
340 | try self.transport.write(data: buff) | |
341 | } | |
342 | } | |
343 | ||
344 | public func write(_ value: Int32) throws { | |
345 | var buff = Data() | |
346 | buff.append(Data([UInt8(0xff & (value >> 24))])) | |
347 | buff.append(Data([UInt8(0xff & (value >> 16))])) | |
348 | buff.append(Data([UInt8(0xff & (value >> 8))])) | |
349 | buff.append(Data([UInt8(0xff & (value))])) | |
350 | ||
351 | try ProtocolTransportTry(error: TProtocolError(message: "Transport write failed")) { | |
352 | try self.transport.write(data: buff) | |
353 | } | |
354 | } | |
355 | ||
356 | public func write(_ value: Int64) throws { | |
357 | var buff = Data() | |
358 | buff.append(Data([UInt8(0xff & (value >> 56))])) | |
359 | buff.append(Data([UInt8(0xff & (value >> 48))])) | |
360 | buff.append(Data([UInt8(0xff & (value >> 40))])) | |
361 | buff.append(Data([UInt8(0xff & (value >> 32))])) | |
362 | buff.append(Data([UInt8(0xff & (value >> 24))])) | |
363 | buff.append(Data([UInt8(0xff & (value >> 16))])) | |
364 | buff.append(Data([UInt8(0xff & (value >> 8))])) | |
365 | buff.append(Data([UInt8(0xff & (value))])) | |
366 | ||
367 | try ProtocolTransportTry(error: TProtocolError(message: "Transport write failed")) { | |
368 | try self.transport.write(data: buff) | |
369 | } | |
370 | } | |
371 | ||
372 | public func write(_ value: Double) throws { | |
373 | // Notably unsafe, since Double and Int64 are the same size, this should work fine | |
374 | try self.write(Int64(bitPattern: value.bitPattern)) | |
375 | } | |
376 | ||
377 | public func write(_ data: Data) throws { | |
378 | try write(Int32(data.count)) | |
379 | ||
380 | try ProtocolTransportTry(error: TProtocolError(message: "Transport write failed")) { | |
381 | try self.transport.write(data: data) | |
382 | } | |
383 | } | |
384 | } |