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 class TFramedTransport: TTransport { 23 public static let headerSize = 4 24 public static let initFrameSize = 1024 25 private static let defaultMaxLength = 16384000 26 27 public var transport: TTransport 28 private var writeBuffer = Data() 29 30 private var maxSize = TFramedTransport.defaultMaxLength 31 private var remainingBytes = 0 32 33 34 public init(transport: TTransport, maxSize: Int) { 35 self.transport = transport 36 self.maxSize = maxSize 37 } 38 39 public convenience init(transport: TTransport) { 40 self.init(transport: transport, maxSize: TFramedTransport.defaultMaxLength) 41 } 42 readHeadernull43 func readHeader() throws { 44 let read = try transport.readAll(size: TFramedTransport.headerSize) 45 remainingBytes = Int(decodeFrameSize(data: read)) 46 } 47 48 /// Mark: - TTransport 49 readnull50 public func read(size: Int) throws -> Data { 51 while (remainingBytes <= 0) { 52 try readHeader() 53 } 54 55 let toRead = min(size, remainingBytes) 56 57 if toRead < 0 { 58 try close() 59 throw TTransportError(error: .negativeSize, 60 message: "Read a negative frame size (\(toRead))!") 61 } 62 63 if toRead > maxSize { 64 try close() 65 throw TTransportError(error: .sizeLimit(limit: maxSize, got: toRead)) 66 } 67 68 let data = try transport.readAll(size: toRead) 69 remainingBytes -= data.count 70 return data 71 } 72 flushnull73 public func flush() throws { 74 // copy buffer and reset 75 let buff = writeBuffer 76 writeBuffer = Data() 77 78 let frameSize = encodeFrameSize(size: UInt32(buff.count)) 79 80 try transport.write(data: frameSize) 81 try transport.write(data: buff) 82 try transport.flush() 83 } 84 writenull85 public func write(data: Data) throws { 86 writeBuffer.append(data) 87 } 88 89 90 encodeFrameSizenull91 private func encodeFrameSize(size: UInt32) -> Data { 92 var data = Data() 93 data.append(Data([UInt8(0xff & (size >> 24))])) 94 data.append(Data([UInt8(0xff & (size >> 16))])) 95 data.append(Data([UInt8(0xff & (size >> 8))])) 96 data.append(Data([UInt8(0xff & (size))])) 97 98 return data 99 } 100 decodeFrameSizenull101 private func decodeFrameSize(data: Data) -> UInt32 { 102 var size: UInt32 103 size = (UInt32(data[0] & 0xff) << 24) 104 size |= (UInt32(data[1] & 0xff) << 16) 105 size |= (UInt32(data[2] & 0xff) << 8) 106 size |= (UInt32(data[3] & 0xff)) 107 return size 108 } 109 closenull110 public func close() throws { 111 try transport.close() 112 } 113 opennull114 public func open() throws { 115 try transport.open() 116 } 117 isOpennull118 public func isOpen() throws -> Bool { 119 return try transport.isOpen() 120 } 121 } 122