blob: 9f75b5efc8a81ddf39530c59d07982eb7459ac6a [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
Jano Svitoka0825922020-03-06 08:44:10 +010068 let data = try transport.readAll(size: toRead)
69 remainingBytes -= data.count
70 return data
Chris Simpsona9b6c702018-04-08 07:11:37 -040071 }
72
73 public func flush() throws {
74 // copy buffer and reset
75 let buff = writeBuffer
76 writeBuffer = Data()
77
Chris Simpsona9b6c702018-04-08 07:11:37 -040078 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
85 public func write(data: Data) throws {
86 writeBuffer.append(data)
87 }
88
89
90
91 private func encodeFrameSize(size: UInt32) -> Data {
92 var data = Data()
Antoine Cœur08a6eb62019-07-08 18:42:09 +080093 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))]))
Chris Simpsona9b6c702018-04-08 07:11:37 -040097
98 return data
99 }
100
101 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
110 public func close() throws {
111 try transport.close()
112 }
113
114 public func open() throws {
115 try transport.open()
116 }
117
118 public func isOpen() throws -> Bool {
119 return try transport.isOpen()
120 }
121}