Skip to content

Commit

Permalink
Kitura/Kitura#430 Write small strings to the socket through a buffer
Browse files Browse the repository at this point in the history
  • Loading branch information
shmuelk committed May 3, 2016
1 parent e1f449f commit d69cab1
Showing 1 changed file with 85 additions and 40 deletions.
125 changes: 85 additions & 40 deletions Sources/KituraNet/ServerResponse.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
* limitations under the License.
**/

import KituraSys
import Socket

import Foundation
Expand All @@ -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
///
Expand All @@ -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
///
Expand Down Expand Up @@ -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
///
Expand All @@ -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
///
Expand All @@ -221,51 +242,75 @@ 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
///
/// - Throws: ???
///
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)
}
}
}

0 comments on commit d69cab1

Please sign in to comment.