blob: ca385d6d3ce4b8e81fe0b821add3365a1d5969f1 [file] [log] [blame]
Chris Simpsona9b6c702018-04-08 07:11:37 -04001/*
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
20import Foundation
21
22public 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
43 func readHeader() throws {
44 let read = try transport.readAll(size: TFramedTransport.headerSize)
45 remainingBytes = Int(decodeFrameSize(data: read))
46 }
47
48 /// Mark: - TTransport
49
50 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 return try transport.readAll(size: toRead)
69 }
70
71 public func flush() throws {
72 // copy buffer and reset
73 let buff = writeBuffer
74 writeBuffer = Data()
75
76 if buff.count - TFramedTransport.headerSize < 0 {
77 throw TTransportError(error: .unknown)
78 }
79
80 let frameSize = encodeFrameSize(size: UInt32(buff.count))
81
82 try transport.write(data: frameSize)
83 try transport.write(data: buff)
84 try transport.flush()
85 }
86
87 public func write(data: Data) throws {
88 writeBuffer.append(data)
89 }
90
91
92
93 private func encodeFrameSize(size: UInt32) -> Data {
94 var data = Data()
95 data.append(Data(bytes: [UInt8(0xff & (size >> 24))]))
96 data.append(Data(bytes: [UInt8(0xff & (size >> 16))]))
97 data.append(Data(bytes: [UInt8(0xff & (size >> 8))]))
98 data.append(Data(bytes: [UInt8(0xff & (size))]))
99
100 return data
101 }
102
103 private func decodeFrameSize(data: Data) -> UInt32 {
104 var size: UInt32
105 size = (UInt32(data[0] & 0xff) << 24)
106 size |= (UInt32(data[1] & 0xff) << 16)
107 size |= (UInt32(data[2] & 0xff) << 8)
108 size |= (UInt32(data[3] & 0xff))
109 return size
110 }
111
112 public func close() throws {
113 try transport.close()
114 }
115
116 public func open() throws {
117 try transport.open()
118 }
119
120 public func isOpen() throws -> Bool {
121 return try transport.isOpen()
122 }
123}