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 readStringBodynull55 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 readMessageBeginnull67 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 readMessageEndnull98 public func readMessageEnd() throws { 99 return 100 } 101 readStructBeginnull102 public func readStructBegin() throws -> String { 103 return "" 104 } 105 readStructEndnull106 public func readStructEnd() throws { 107 return 108 } 109 readFieldBeginnull110 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 readFieldEndnull122 public func readFieldEnd() throws { 123 return 124 } 125 readMapBeginnull126 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 readMapEndnull141 public func readMapEnd() throws { 142 return 143 } 144 readSetBeginnull145 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 readSetEndnull156 public func readSetEnd() throws { 157 return 158 } 159 readListBeginnull160 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 readListEndnull170 public func readListEnd() throws { 171 return 172 } 173 readnull174 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 readnull182 public func read() throws -> Bool { 183 return (try read() as UInt8) == 1 184 } 185 readnull186 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 readnull194 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 readnull204 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 readnull217 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 readnull234 public func read() throws -> Double { 235 let val = try read() as Int64 236 return Double(bitPattern: UInt64(bitPattern: val)) 237 } 238 readnull239 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 writeMessageBeginnull251 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 writeMessageEndnull265 public func writeMessageEnd() throws { 266 currentMessageName = nil 267 } 268 writeStructBeginnull269 public func writeStructBegin(name: String) throws { 270 return 271 } 272 writeStructEndnull273 public func writeStructEnd() throws { 274 return 275 } 276 writeFieldBeginnull277 public func writeFieldBegin(name: String, type fieldType: TType, fieldID: Int32) throws { 278 try write(UInt8(fieldType.rawValue)) 279 try write(Int16(fieldID)) 280 } 281 writeFieldStopnull282 public func writeFieldStop() throws { 283 try write(UInt8(TType.stop.rawValue)) 284 } 285 writeFieldEndnull286 public func writeFieldEnd() throws { 287 return 288 } 289 writeMapBeginnull290 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 writeMapEndnull296 public func writeMapEnd() throws { 297 return 298 } 299 writeSetBeginnull300 public func writeSetBegin(elementType: TType, size: Int32) throws { 301 try write(UInt8(elementType.rawValue)) 302 try write(size) 303 } 304 writeSetEndnull305 public func writeSetEnd() throws { 306 return 307 } 308 writeListBeginnull309 public func writeListBegin(elementType: TType, size: Int32) throws { 310 try write(UInt8(elementType.rawValue)) 311 try write(size) 312 } 313 writeListEndnull314 public func writeListEnd() throws { 315 return 316 } 317 writenull318 public func write(_ value: String) throws { 319 try write(value.data(using: .utf8)!) 320 } 321 writenull322 public func write(_ value: Bool) throws { 323 let byteVal: UInt8 = value ? 1 : 0 324 try write(byteVal) 325 } 326 writenull327 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 writenull335 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 writenull344 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 writenull356 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 writenull372 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 writenull377 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 } 385