diff --git a/Sources/KituraNet/ServerResponse.swift b/Sources/KituraNet/ServerResponse.swift index f7d0f70..4326f7e 100644 --- a/Sources/KituraNet/ServerResponse.swift +++ b/Sources/KituraNet/ServerResponse.swift @@ -14,6 +14,7 @@ * limitations under the License. **/ +import KituraSys import Socket import Foundation @@ -26,27 +27,37 @@ public class ServerResponse : SocketWriter { /// Socket for the ServerResponse /// private var socket: Socket? - + /// - /// TODO: ??? + /// Size of buffer + /// + private let BUFFER_SIZE = 2000 + + /// + /// Buffer for HTTP response line, headers, and short bodies + /// + private var buffer: NSMutableData + + /// + /// Whether or not the HTTP response line and headers have been flushed. /// private var startFlushed = false - + /// /// TODO: ??? /// private var singleHeaders: [String: String] = [:] - + /// /// TODO: ??? /// private var multiHeaders: [String: [String]] = [:] - + /// /// Status code /// private var status = HttpStatusCode.OK.rawValue - + /// /// Status code /// @@ -60,28 +71,29 @@ public class ServerResponse : SocketWriter { } } } - + /// /// Initializes a ServerResponse instance /// init(socket: Socket) { - + self.socket = socket + buffer = NSMutableData(capacity: BUFFER_SIZE)! setHeader("Date", value: SpiUtils.httpDate()) - + } - + /// /// Get a specific headers for the response by key /// /// - Parameter key: the header key /// public func getHeader(_ key: String) -> String? { - + return singleHeaders[key] - + } - + /// /// Get all values on a specific key /// @@ -166,23 +178,23 @@ public class ServerResponse : SocketWriter { singleHeaders.removeValue(forKey: key) multiHeaders.removeValue(forKey: key) } - + /// - /// Write a string as a response + /// Write a string as a response /// /// - Parameter string: String data to be written. /// /// - Throws: ??? /// public func write(from string: String) throws { - - if let socket = socket { + + if socket != nil { try flushStart() - try socket.write(from: string) + try writeToSocketThroughBuffer(text: string) } - + } - + /// /// Write data as a response /// @@ -193,14 +205,23 @@ public class ServerResponse : SocketWriter { /// - Throws: ??? /// public func write(from data: NSData) throws { - + if let socket = socket { try flushStart() - try socket.write(from: data) + if buffer.length + data.length > BUFFER_SIZE && buffer.length != 0 { + try socket.write(from: buffer) + buffer.length = 0 + } + if data.length > BUFFER_SIZE { + try socket.write(from: data) + } + else { + buffer.append(data) + } } - + } - + /// /// End the response /// @@ -221,11 +242,14 @@ public class ServerResponse : SocketWriter { public func end() throws { if let socket = socket { try flushStart() + if buffer.length > 0 { + try socket.write(from: buffer) + } socket.close() } socket = nil } - + /// /// Begin flushing the buffer /// @@ -233,39 +257,60 @@ public class ServerResponse : SocketWriter { /// private func flushStart() throws { - guard let socket = socket where !startFlushed else { + if socket == nil || startFlushed { return } - try socket.write(from: "HTTP/1.1 ") - try socket.write(from: String(status)) - try socket.write(from: " ") + try writeToSocketThroughBuffer(text: "HTTP/1.1 ") + try writeToSocketThroughBuffer(text: String(status)) + try writeToSocketThroughBuffer(text: " ") var statusText = Http.statusCodes[status] if statusText == nil { statusText = "" } - try socket.write(from: statusText!) - try socket.write(from: "\r\n") + try writeToSocketThroughBuffer(text: statusText!) + try writeToSocketThroughBuffer(text: "\r\n") for (key, value) in singleHeaders { - try socket.write(from: key) - try socket.write(from: ": ") - try socket.write(from: value) - try socket.write(from: "\r\n") + try writeToSocketThroughBuffer(text: key) + try writeToSocketThroughBuffer(text: ": ") + try writeToSocketThroughBuffer(text: value) + try writeToSocketThroughBuffer(text: "\r\n") } for (key, valueSet) in multiHeaders { for value in valueSet { - try socket.write(from: key) - try socket.write(from: ": ") - try socket.write(from: value) - try socket.write(from: "\r\n") + try writeToSocketThroughBuffer(text: key) + try writeToSocketThroughBuffer(text: ": ") + try writeToSocketThroughBuffer(text: value) + try writeToSocketThroughBuffer(text: "\r\n") } } - try socket.write(from: "\r\n") + try writeToSocketThroughBuffer(text: "\r\n") startFlushed = true } + + /// + /// Function to write Strings to the socket through the buffer + /// + private func writeToSocketThroughBuffer(text: String) throws { + guard let socket = socket, + let utf8Data = StringUtils.toUtf8String(text) else { + return + } + + if buffer.length + utf8Data.length > BUFFER_SIZE && buffer.length != 0 { + try socket.write(from: buffer) + buffer.length = 0 + } + if utf8Data.length > BUFFER_SIZE { + try socket.write(from: utf8Data) + } + else { + buffer.append(utf8Data) + } + } }