├── README.md ├── Sails.xcodeproj ├── project.xcworkspace │ └── contents.xcworkspacedata ├── xcshareddata │ └── xcschemes │ │ └── Sails.xcscheme └── project.pbxproj ├── Sails ├── Methods.swift ├── HTTPMethods.swift ├── Sails.h ├── HTTPResponse.swift ├── Router.swift ├── HTTPRequest.swift ├── Info.plist ├── Sails.swift ├── HTTPParser.swift └── Socket.swift └── SailsTests ├── RouterTests.swift ├── HTTPParserTests.swift ├── SocketTests.swift ├── Info.plist ├── Assertions.swift └── SailsTests.swift /README.md: -------------------------------------------------------------------------------- 1 | # Sails 2 | 3 | Sails is a simple Swift web framework. This is not production ready or overly tested, you should *not* use it yet. 4 | 5 | -------------------------------------------------------------------------------- /Sails.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Sails/Methods.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Methods.swift 3 | // Sails 4 | // 5 | // Created by Danielle Lancashire on 04/10/2015. 6 | // Copyright © 2015 Danielle Lancashire. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | -------------------------------------------------------------------------------- /SailsTests/RouterTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RouterTests.swift 3 | // Sails 4 | // 5 | // Created by Danielle Lancashire on 04/10/2015. 6 | // Copyright © 2015 Danielle Lancashire. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | 11 | class RouterTests: XCTestCase { 12 | } 13 | -------------------------------------------------------------------------------- /SailsTests/HTTPParserTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HTTPParserTests.swift 3 | // Sails 4 | // 5 | // Created by Danielle Lancashire on 04/10/2015. 6 | // Copyright © 2015 Danielle Lancashire. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | 11 | class HTTPParserTests: XCTestCase { 12 | } 13 | -------------------------------------------------------------------------------- /Sails/HTTPMethods.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HTTPMethods.swift 3 | // Sails 4 | // 5 | // Created by Danielle Lancashire on 04/10/2015. 6 | // Copyright © 2015 Danielle Lancashire. All rights reserved. 7 | // 8 | 9 | public enum HTTPMethod: String { 10 | case GET 11 | case POST 12 | case PUT 13 | case DELETE 14 | case HEAD 15 | case OPTIONS 16 | case TRACE 17 | case CONNECT 18 | } 19 | -------------------------------------------------------------------------------- /Sails/Sails.h: -------------------------------------------------------------------------------- 1 | // 2 | // Sails.h 3 | // Sails 4 | // 5 | // Created by Danielle Lancashire on 03/10/2015. 6 | // Copyright © 2015 Danielle Lancashire. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for Sails. 12 | FOUNDATION_EXPORT double SailsVersionNumber; 13 | 14 | //! Project version string for Sails. 15 | FOUNDATION_EXPORT const unsigned char SailsVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /SailsTests/SocketTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SocketTests.swift 3 | // Sails 4 | // 5 | // Created by Danielle Lancashire on 03/10/2015. 6 | // Copyright © 2015 Danielle Lancashire. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import Sails 11 | 12 | class SocketTests: XCTestCase { 13 | func test_can_setup_socket() { 14 | AssertNoThrow { 15 | let socket = try Socket(port: 8080) 16 | XCTAssertNotNil(socket) 17 | } 18 | } 19 | 20 | func test_setting_up_a_socket_on_a_restricted_port_fails() { 21 | AssertThrows { 22 | let socket = try Socket(port: 21) 23 | XCTAssertNotNil(socket) 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /SailsTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /Sails/HTTPResponse.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HTTPResponse.swift 3 | // Sails 4 | // 5 | // Created by Danielle Lancashire on 04/10/2015. 6 | // Copyright © 2015 Danielle Lancashire. All rights reserved. 7 | // 8 | 9 | public protocol HTTPResponse { 10 | var method: HTTPMethod { get } 11 | var headers: [String: String] { get } 12 | var body: NSData? { get } 13 | var statusCode: Int { get } 14 | } 15 | 16 | public struct ConcreteHTTPResponse: HTTPResponse { 17 | public let method: HTTPMethod 18 | public let headers: [String : String] 19 | public let body: NSData? 20 | public let statusCode: Int 21 | 22 | public init(method: HTTPMethod, headers: [String : String], body: NSData?, statusCode: Int) { 23 | self.method = method 24 | self.headers = headers 25 | self.body = body 26 | self.statusCode = statusCode 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Sails/Router.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Router.swift 3 | // Sails 4 | // 5 | // Created by Danielle Lancashire on 04/10/2015. 6 | // Copyright © 2015 Danielle Lancashire. All rights reserved. 7 | // 8 | 9 | public typealias Handler = HTTPRequest -> HTTPResponse 10 | public typealias Matcher = HTTPRequest -> Bool 11 | 12 | public typealias Route = (Matcher, Handler) 13 | 14 | public protocol Router { 15 | var matchers: [Route] { get } 16 | func handlerForRequest(request: HTTPRequest) -> Handler? 17 | } 18 | 19 | public struct ConcreteRouter: Router { 20 | public var matchers: [Route] = [] 21 | 22 | public func handlerForRequest(request: HTTPRequest) -> Handler? { 23 | for (matcher, handler) in matchers where matcher(request) == true { 24 | return handler 25 | } 26 | 27 | return nil 28 | } 29 | 30 | public init(matchers: [Route]) { 31 | self.matchers = matchers 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Sails/HTTPRequest.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HTTPRequest.swift 3 | // Sails 4 | // 5 | // Created by Danielle Lancashire on 04/10/2015. 6 | // Copyright © 2015 Danielle Lancashire. All rights reserved. 7 | // 8 | 9 | public protocol HTTPRequest { 10 | var url: String { get } 11 | var urlParams: [(String, String)] { get } 12 | var method: HTTPMethod { get } 13 | var headers: [String: String] { get } 14 | var body: NSData? { get } 15 | } 16 | 17 | 18 | public struct ConcreteHTTPRequest: HTTPRequest { 19 | public let url: String 20 | public let urlParams: [(String, String)] 21 | public let method: HTTPMethod 22 | public let headers: [String : String] 23 | public let body: NSData? 24 | 25 | public init(url: String, urlParams: [(String, String)], method: HTTPMethod, headers: [String : String], body: NSData?) { 26 | self.url = url 27 | self.urlParams = urlParams 28 | self.method = method 29 | self.headers = headers 30 | self.body = body 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Sails/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSHumanReadableCopyright 24 | Copyright © 2015 Danielle Lancashire. All rights reserved. 25 | NSPrincipalClass 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /SailsTests/Assertions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Assertions.swift 3 | // Sails 4 | // 5 | // Created by Danielle Lancashire on 03/10/2015. 6 | // Copyright © 2015 Danielle Lancashire. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | 11 | /// This allows you to write safe tests for the happy path of failable functions. 12 | /// It helps you to avoid the `try!` operator in tests. 13 | /// 14 | /// If you want to test a function, which may fail in general, you may think of using `try`. 15 | /// But this would mean that you have to declare your test method as throwing, which causes that 16 | /// XCTest doesn't execute the test anymore. 17 | /// 18 | /// So in consequence, you would usually need to write: 19 | /// 20 | /// XCTAssertEqual(try! fib(x), 21) 21 | /// 22 | /// If the expression fails, your whole test suite doesn't execute further and aborts immediately, 23 | /// which is very undesirable, especially on CI, but also for your workflow when you use TDD. 24 | /// 25 | /// Instead you can write now: 26 | /// 27 | /// AssertNoThrow { 28 | /// XCTAssertEqual(try fib(x), 21) 29 | /// } 30 | /// 31 | /// Or alternatively: 32 | /// 33 | /// AssertNoThrow(try fib(x)).map { (y: Int) in 34 | /// XCTAssertEqual(y, 21) 35 | /// } 36 | /// 37 | /// If the expression fails, your test fails. 38 | /// 39 | public func AssertNoThrow(@autoclosure closure: () throws -> R) -> R? { 40 | var result: R? 41 | AssertNoThrow() { 42 | result = try closure() 43 | } 44 | return result 45 | } 46 | 47 | public func AssertNoThrow(@noescape closure: () throws -> ()) { 48 | do { 49 | try closure() 50 | } catch let error { 51 | XCTFail("Caught unexpected error <\(error)>.") 52 | } 53 | } 54 | 55 | public func AssertThrows(@noescape closure: () throws -> ()) { 56 | do { 57 | try closure() 58 | XCTFail("Closure did not throw and error.") 59 | } 60 | catch { 61 | 62 | } 63 | } -------------------------------------------------------------------------------- /SailsTests/SailsTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SailsTests.swift 3 | // Sails 4 | // 5 | // Created by Danielle Lancashire on 04/10/2015. 6 | // Copyright © 2015 Danielle Lancashire. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import Sails 11 | 12 | let port: in_port_t = 8081 13 | 14 | func RegexMatcherMake(regex: NSRegularExpression) -> (HTTPRequest -> Bool) { 15 | return { (request: HTTPRequest) -> Bool in 16 | let range = NSMakeRange(0, request.url.characters.count) 17 | return regex.matchesInString(request.url, options: NSMatchingOptions(rawValue: 0), range: range).count > 0 18 | } 19 | } 20 | 21 | class SailsTests: XCTestCase { 22 | func test_stack_setup() { 23 | AssertNoThrow { 24 | _ = Sails(socket: try Socket(port: port), router: ConcreteRouter(matchers: []), parserType: ConcreteHTTPParser.self) 25 | } 26 | } 27 | 28 | func test_magic() { 29 | let helloRouteMatcher = RegexMatcherMake(try! NSRegularExpression(pattern: "/hello", options: .AnchorsMatchLines)) 30 | let helloRouteResponse: Handler = { request in 31 | return ConcreteHTTPResponse(method: request.method, headers: [:], body: nil, statusCode: 200) 32 | } 33 | 34 | let router = ConcreteRouter(matchers: [(helloRouteMatcher, helloRouteResponse)]) 35 | let sut = Sails(socket: try! Socket(port: 8082), router: router) 36 | sut.start() 37 | 38 | let session = NSURLSession.sharedSession() 39 | let expectation = expectationWithDescription("Request should return") 40 | 41 | let task = session.dataTaskWithURL(NSURL(string: "http://localhost:8082/hello")!) { data, response, error in 42 | XCTAssertEqual(200, (response as! NSHTTPURLResponse).statusCode) 43 | expectation.fulfill() 44 | } 45 | 46 | task.resume() 47 | 48 | waitForExpectationsWithTimeout(10.0, handler: nil) 49 | 50 | sut.stop() 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Sails/Sails.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Sails.swift 3 | // Sails 4 | // 5 | // Created by Danielle Lancashire on 03/10/2015. 6 | // Copyright © 2015 Danielle Lancashire. All rights reserved. 7 | // 8 | 9 | public class Sails { 10 | private let router: Router 11 | private let socket: Socket 12 | private let parserType: HTTPParser.Type 13 | private let clientQueue = dispatch_queue_create("co.rocketapps.Sails.clientQueue", nil) 14 | 15 | public init(socket: Socket = try! Socket(port: 8080), router: Router, parserType: HTTPParser.Type = ConcreteHTTPParser.self) { 16 | self.socket = socket 17 | self.router = router 18 | self.parserType = parserType 19 | } 20 | 21 | public func start() { 22 | dispatch_async(clientQueue) { 23 | while let client = try? self.socket.acceptClient() { 24 | print("New connection from: ", client) 25 | 26 | let parser = self.parserType.init() 27 | while let request = parser.parse(client), let handler = self.router.handlerForRequest(request) { 28 | let response = handler(request) 29 | Sails.respond(client, response: response) 30 | client.close() 31 | } 32 | } 33 | 34 | self.stop() 35 | } 36 | } 37 | 38 | public func stop() { 39 | socket.close() 40 | } 41 | 42 | private static func respond(socket: Socket, response: HTTPResponse) { 43 | do { 44 | try socket.sendUTF8("HTTP/1.1 \(response.statusCode)\r\n") 45 | if let body = response.body { 46 | try socket.sendUTF8("Content-Length: \(body.length)\r\n") 47 | } else { 48 | try socket.sendUTF8("Content-Length: 0\r\n") 49 | } 50 | for (name, value) in response.headers { 51 | try socket.sendUTF8("\(name): \(value)\r\n") 52 | } 53 | try socket.sendUTF8("\r\n") 54 | if let body = response.body where response.method != .HEAD { 55 | try socket.sendData(body) 56 | } 57 | } 58 | catch { 59 | 60 | } 61 | } 62 | } -------------------------------------------------------------------------------- /Sails/HTTPParser.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HTTPParser.swift 3 | // Sails 4 | // 5 | // Created by Danielle Lancashire on 04/10/2015. 6 | // Copyright © 2015 Danielle Lancashire. All rights reserved. 7 | // 8 | 9 | public protocol HTTPParser { 10 | init() 11 | func parse(socket: Socket) -> HTTPRequest? 12 | } 13 | 14 | public struct ConcreteHTTPParser: HTTPParser { 15 | public init() { 16 | 17 | } 18 | 19 | public func parse(socket: Socket) -> HTTPRequest? { 20 | guard let statusLine = try? socket.readNextLine() else { return nil } 21 | let statusTokens = statusLine.componentsSeparatedByString(" ") 22 | 23 | guard statusTokens.count == 3 else { return nil } 24 | 25 | guard let method = HTTPMethod(rawValue: statusTokens[0]) else { return nil } 26 | let path = statusTokens[1] 27 | let urlParams = extractUrlParams(path) 28 | let headers = extractHeaders(socket) 29 | guard let contentLengthString = headers["content-length"], let contentLength = Int(contentLengthString) else { 30 | return ConcreteHTTPRequest(url: path, urlParams: urlParams, method: method, headers: headers, body: nil) 31 | } 32 | let body = extractBody(socket, length: contentLength) 33 | 34 | return ConcreteHTTPRequest(url: path, urlParams: urlParams, method: method, headers: headers, body: body) 35 | } 36 | 37 | private func extractUrlParams(path: String) -> [(String, String)] { 38 | if let query = path.componentsSeparatedByString("?").last { 39 | return query.componentsSeparatedByString("&").map { (param: String) -> (String, String) in 40 | let tokens = param.componentsSeparatedByString("=") 41 | if tokens.count >= 2 { 42 | let key = tokens[0].stringByRemovingPercentEncoding 43 | let value = tokens[1].stringByRemovingPercentEncoding 44 | if key != nil && value != nil { return (key!, value!) } 45 | } 46 | return ("","") 47 | } 48 | } 49 | 50 | return [] 51 | } 52 | 53 | private func extractHeaders(socket: Socket) -> [String : String] { 54 | var headers = [String: String]() 55 | while let headerLine = try? socket.readNextLine() { 56 | if headerLine.isEmpty { 57 | return headers 58 | } 59 | 60 | let headerTokens = headerLine.componentsSeparatedByString(":") 61 | if ( headerTokens.count >= 2 ) { 62 | // RFC 2616 - "Hypertext Transfer Protocol -- HTTP/1.1", paragraph 4.2, "Message Headers": 63 | // "Each header field consists of a name followed by a colon (":") and the field value. Field names are case-insensitive." 64 | // We can keep lower case version. 65 | let headerName = headerTokens[0].lowercaseString 66 | let headerValue = headerTokens[1].stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet()) 67 | if !headerName.isEmpty && !headerValue.isEmpty { 68 | headers.updateValue(headerValue, forKey: headerName) 69 | } 70 | } 71 | } 72 | 73 | return headers 74 | } 75 | 76 | private func extractBody(socket: Socket, length: Int) -> NSData? { 77 | var body = "" 78 | var counter = 0; 79 | while counter < length { 80 | let c = socket.nextInt8() 81 | if c < 0 { 82 | return nil 83 | } 84 | body.append(UnicodeScalar(c)) 85 | counter++; 86 | } 87 | 88 | return body.dataUsingEncoding(NSUTF8StringEncoding) 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /Sails.xcodeproj/xcshareddata/xcschemes/Sails.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 64 | 65 | 71 | 72 | 73 | 74 | 75 | 76 | 82 | 83 | 89 | 90 | 91 | 92 | 94 | 95 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /Sails/Socket.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Socket.swift 3 | // Sails 4 | // 5 | // Created by Danielle Lancashire on 03/10/2015. 6 | // Copyright © 2015 Danielle Lancashire. All rights reserved. 7 | // 8 | 9 | 10 | import Foundation /* currently dependant on Foundation for String -> NSData */ 11 | 12 | 13 | public enum SocketErrors: ErrorType { 14 | case PosixSocketInitializationFailed 15 | case PosixSocketWriteFailed 16 | case PosixSocketReadFailed 17 | case StringDataConversionFailed 18 | case PosixSocketAcceptFailed 19 | } 20 | 21 | public typealias POSIXSocket = CInt 22 | 23 | public class Socket { 24 | private let posixSocket: POSIXSocket 25 | 26 | public init(posixSocket: POSIXSocket) { 27 | self.posixSocket = posixSocket 28 | } 29 | 30 | public init(port: in_port_t = 8080) throws { 31 | posixSocket = socket(AF_INET, SOCK_STREAM, 0) 32 | guard posixSocket != -1 else { 33 | releaseSocket(posixSocket) 34 | throw SocketErrors.PosixSocketInitializationFailed 35 | } 36 | 37 | var value: Int32 = 1; 38 | guard setsockopt(posixSocket, SOL_SOCKET, SO_REUSEADDR, &value, socklen_t(sizeof(Int32))) != -1 else { 39 | releaseSocket(posixSocket) 40 | throw SocketErrors.PosixSocketInitializationFailed 41 | } 42 | 43 | nosigpipe(posixSocket) 44 | 45 | var addr = sockaddr_in(sin_len: __uint8_t(sizeof(sockaddr_in)), sin_family: sa_family_t(AF_INET), sin_port: port_htons(port), sin_addr: in_addr(s_addr: inet_addr("0.0.0.0")), sin_zero: (0, 0, 0, 0, 0, 0, 0, 0)) 46 | var sock_addr = sockaddr(sa_len: 0, sa_family: 0, sa_data: (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)) 47 | 48 | memcpy(&sock_addr, &addr, Int(sizeof(sockaddr_in))) 49 | guard bind(posixSocket, &sock_addr, socklen_t(sizeof(sockaddr_in))) != -1 else { 50 | releaseSocket(posixSocket) 51 | throw SocketErrors.PosixSocketInitializationFailed 52 | } 53 | guard listen(posixSocket, 20 /* max pending connection */ ) != -1 else { 54 | releaseSocket(posixSocket) 55 | throw SocketErrors.PosixSocketInitializationFailed 56 | } 57 | } 58 | } 59 | 60 | public extension Socket { 61 | func sendData(data: NSData) throws { 62 | var totalSent = 0 63 | let unsafePointer = UnsafePointer(data.bytes) 64 | while totalSent < data.length { 65 | let sent = write(posixSocket, unsafePointer + totalSent, Int(data.length - totalSent)) 66 | guard sent != 0 else { 67 | throw SocketErrors.PosixSocketWriteFailed 68 | } 69 | 70 | totalSent += sent 71 | } 72 | } 73 | 74 | func sendUTF8(string: String) throws { 75 | guard let utf8Data = string.dataUsingEncoding(NSUTF8StringEncoding) else { 76 | throw SocketErrors.StringDataConversionFailed 77 | } 78 | 79 | try sendData(utf8Data) 80 | } 81 | } 82 | 83 | public extension Socket { 84 | func peername() -> String? { 85 | var addr = sockaddr(), len: socklen_t = socklen_t(sizeof(sockaddr)) 86 | guard getpeername(posixSocket, &addr, &len) != 0 else { 87 | return nil 88 | } 89 | 90 | var hostBuffer = [CChar](count: Int(NI_MAXHOST), repeatedValue: 0) 91 | guard getnameinfo(&addr, len, &hostBuffer, socklen_t(hostBuffer.count), nil, 0, NI_NUMERICHOST) != 0 else { 92 | return nil 93 | } 94 | 95 | return String.fromCString(hostBuffer) 96 | } 97 | } 98 | 99 | public extension Socket { 100 | func acceptClient() throws -> Socket { 101 | var addr = sockaddr(sa_len: 0, sa_family: 0, sa_data: (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)) 102 | var len: socklen_t = 0 103 | 104 | let clientSocket = accept(posixSocket, &addr, &len) 105 | guard clientSocket != -1 else { 106 | throw SocketErrors.PosixSocketAcceptFailed 107 | } 108 | 109 | nosigpipe(clientSocket) 110 | 111 | return Socket(posixSocket: clientSocket) 112 | } 113 | } 114 | 115 | public extension Socket { 116 | func close() { 117 | releaseSocket(posixSocket) 118 | } 119 | } 120 | 121 | public extension Socket { 122 | func nextInt8() -> Int { 123 | var buffer = [UInt8](count: 1, repeatedValue: 0); 124 | let next = recv(posixSocket, &buffer, Int(buffer.count), 0) 125 | if next <= 0 { return next } 126 | 127 | return Int(buffer[0]) 128 | } 129 | 130 | func readNextLine() throws -> String { 131 | var characters: String = "" 132 | var n = 0 133 | repeat { 134 | n = nextInt8() 135 | if ( n > 13 /* CR */ ) { characters.append(Character(UnicodeScalar(n))) } 136 | } while ( n > 0 && n != 10 /* NL */) 137 | guard n != -1 && !characters.isEmpty else { 138 | throw SocketErrors.PosixSocketReadFailed 139 | } 140 | 141 | return characters 142 | } 143 | } 144 | 145 | private func port_htons(port: in_port_t) -> in_port_t { 146 | let isLittleEndian = Int(OSHostByteOrder()) == OSLittleEndian 147 | return isLittleEndian ? _OSSwapInt16(port) : port 148 | } 149 | 150 | private func nosigpipe(socket: POSIXSocket) { 151 | // prevents crashes when blocking calls are pending and the app is paused. 152 | var no_sig_pipe: Int32 = 1; 153 | setsockopt(socket, SOL_SOCKET, SO_NOSIGPIPE, &no_sig_pipe, socklen_t(sizeof(Int32))); 154 | } 155 | 156 | private func releaseSocket(socket: POSIXSocket) { 157 | shutdown(socket, SHUT_RDWR) 158 | } 159 | -------------------------------------------------------------------------------- /Sails.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 65BC1A491BC02BB700091F45 /* SocketTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65BC1A481BC02BB700091F45 /* SocketTests.swift */; settings = {ASSET_TAGS = (); }; }; 11 | 65BC1A4B1BC0416A00091F45 /* Assertions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65BC1A4A1BC0416900091F45 /* Assertions.swift */; settings = {ASSET_TAGS = (); }; }; 12 | 65BC1A4D1BC0F4FB00091F45 /* HTTPRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65BC1A4C1BC0F4FB00091F45 /* HTTPRequest.swift */; settings = {ASSET_TAGS = (); }; }; 13 | 65BC1A4F1BC0F50200091F45 /* HTTPResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65BC1A4E1BC0F50200091F45 /* HTTPResponse.swift */; settings = {ASSET_TAGS = (); }; }; 14 | 65F49F5F1BC006F000939241 /* Sails.h in Headers */ = {isa = PBXBuildFile; fileRef = 65F49F5E1BC006F000939241 /* Sails.h */; settings = {ATTRIBUTES = (Public, ); }; }; 15 | 65F49F661BC006F000939241 /* Sails.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65F49F5B1BC006F000939241 /* Sails.framework */; settings = {ASSET_TAGS = (); }; }; 16 | 65F49F761BC00E1D00939241 /* Sails.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65F49F751BC00E1D00939241 /* Sails.swift */; settings = {ASSET_TAGS = (); }; }; 17 | 65F49F781BC00E6E00939241 /* Socket.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65F49F771BC00E6E00939241 /* Socket.swift */; settings = {ASSET_TAGS = (); }; }; 18 | 65F70EA71BC0F544002ADFB0 /* HTTPMethods.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65F70EA61BC0F544002ADFB0 /* HTTPMethods.swift */; settings = {ASSET_TAGS = (); }; }; 19 | 65F70EA91BC0F5BB002ADFB0 /* Router.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65F70EA81BC0F5BB002ADFB0 /* Router.swift */; settings = {ASSET_TAGS = (); }; }; 20 | 65F70EAB1BC0F5D6002ADFB0 /* HTTPParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65F70EAA1BC0F5D6002ADFB0 /* HTTPParser.swift */; settings = {ASSET_TAGS = (); }; }; 21 | 65F70EAD1BC0F677002ADFB0 /* HTTPParserTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65F70EAC1BC0F677002ADFB0 /* HTTPParserTests.swift */; settings = {ASSET_TAGS = (); }; }; 22 | 65F70EAF1BC0F67E002ADFB0 /* RouterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65F70EAE1BC0F67E002ADFB0 /* RouterTests.swift */; settings = {ASSET_TAGS = (); }; }; 23 | 65F70EB11BC0F686002ADFB0 /* SailsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65F70EB01BC0F686002ADFB0 /* SailsTests.swift */; settings = {ASSET_TAGS = (); }; }; 24 | /* End PBXBuildFile section */ 25 | 26 | /* Begin PBXContainerItemProxy section */ 27 | 65F49F671BC006F000939241 /* PBXContainerItemProxy */ = { 28 | isa = PBXContainerItemProxy; 29 | containerPortal = 65F49F521BC006F000939241 /* Project object */; 30 | proxyType = 1; 31 | remoteGlobalIDString = 65F49F5A1BC006F000939241; 32 | remoteInfo = Sails; 33 | }; 34 | /* End PBXContainerItemProxy section */ 35 | 36 | /* Begin PBXFileReference section */ 37 | 65BC1A481BC02BB700091F45 /* SocketTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SocketTests.swift; sourceTree = ""; }; 38 | 65BC1A4A1BC0416900091F45 /* Assertions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Assertions.swift; sourceTree = ""; }; 39 | 65BC1A4C1BC0F4FB00091F45 /* HTTPRequest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HTTPRequest.swift; sourceTree = ""; }; 40 | 65BC1A4E1BC0F50200091F45 /* HTTPResponse.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HTTPResponse.swift; sourceTree = ""; }; 41 | 65F49F5B1BC006F000939241 /* Sails.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Sails.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 42 | 65F49F5E1BC006F000939241 /* Sails.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Sails.h; sourceTree = ""; }; 43 | 65F49F601BC006F000939241 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 44 | 65F49F651BC006F000939241 /* SailsTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SailsTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 45 | 65F49F6C1BC006F000939241 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 46 | 65F49F751BC00E1D00939241 /* Sails.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Sails.swift; sourceTree = ""; }; 47 | 65F49F771BC00E6E00939241 /* Socket.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Socket.swift; sourceTree = ""; }; 48 | 65F70EA61BC0F544002ADFB0 /* HTTPMethods.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HTTPMethods.swift; sourceTree = ""; }; 49 | 65F70EA81BC0F5BB002ADFB0 /* Router.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Router.swift; sourceTree = ""; }; 50 | 65F70EAA1BC0F5D6002ADFB0 /* HTTPParser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HTTPParser.swift; sourceTree = ""; }; 51 | 65F70EAC1BC0F677002ADFB0 /* HTTPParserTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HTTPParserTests.swift; sourceTree = ""; }; 52 | 65F70EAE1BC0F67E002ADFB0 /* RouterTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RouterTests.swift; sourceTree = ""; }; 53 | 65F70EB01BC0F686002ADFB0 /* SailsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SailsTests.swift; sourceTree = ""; }; 54 | /* End PBXFileReference section */ 55 | 56 | /* Begin PBXFrameworksBuildPhase section */ 57 | 65F49F571BC006F000939241 /* Frameworks */ = { 58 | isa = PBXFrameworksBuildPhase; 59 | buildActionMask = 2147483647; 60 | files = ( 61 | ); 62 | runOnlyForDeploymentPostprocessing = 0; 63 | }; 64 | 65F49F621BC006F000939241 /* Frameworks */ = { 65 | isa = PBXFrameworksBuildPhase; 66 | buildActionMask = 2147483647; 67 | files = ( 68 | 65F49F661BC006F000939241 /* Sails.framework in Frameworks */, 69 | ); 70 | runOnlyForDeploymentPostprocessing = 0; 71 | }; 72 | /* End PBXFrameworksBuildPhase section */ 73 | 74 | /* Begin PBXGroup section */ 75 | 65F49F511BC006F000939241 = { 76 | isa = PBXGroup; 77 | children = ( 78 | 65F49F5D1BC006F000939241 /* Sails */, 79 | 65F49F691BC006F000939241 /* SailsTests */, 80 | 65F49F5C1BC006F000939241 /* Products */, 81 | ); 82 | sourceTree = ""; 83 | }; 84 | 65F49F5C1BC006F000939241 /* Products */ = { 85 | isa = PBXGroup; 86 | children = ( 87 | 65F49F5B1BC006F000939241 /* Sails.framework */, 88 | 65F49F651BC006F000939241 /* SailsTests.xctest */, 89 | ); 90 | name = Products; 91 | sourceTree = ""; 92 | }; 93 | 65F49F5D1BC006F000939241 /* Sails */ = { 94 | isa = PBXGroup; 95 | children = ( 96 | 65F49F5E1BC006F000939241 /* Sails.h */, 97 | 65F49F751BC00E1D00939241 /* Sails.swift */, 98 | 65F70EA81BC0F5BB002ADFB0 /* Router.swift */, 99 | 65F70EA61BC0F544002ADFB0 /* HTTPMethods.swift */, 100 | 65F70EAA1BC0F5D6002ADFB0 /* HTTPParser.swift */, 101 | 65BC1A4C1BC0F4FB00091F45 /* HTTPRequest.swift */, 102 | 65BC1A4E1BC0F50200091F45 /* HTTPResponse.swift */, 103 | 65F49F771BC00E6E00939241 /* Socket.swift */, 104 | 65F49F601BC006F000939241 /* Info.plist */, 105 | ); 106 | path = Sails; 107 | sourceTree = ""; 108 | }; 109 | 65F49F691BC006F000939241 /* SailsTests */ = { 110 | isa = PBXGroup; 111 | children = ( 112 | 65F49F6C1BC006F000939241 /* Info.plist */, 113 | 65BC1A481BC02BB700091F45 /* SocketTests.swift */, 114 | 65F70EAC1BC0F677002ADFB0 /* HTTPParserTests.swift */, 115 | 65F70EAE1BC0F67E002ADFB0 /* RouterTests.swift */, 116 | 65F70EB01BC0F686002ADFB0 /* SailsTests.swift */, 117 | 65BC1A4A1BC0416900091F45 /* Assertions.swift */, 118 | ); 119 | path = SailsTests; 120 | sourceTree = ""; 121 | }; 122 | /* End PBXGroup section */ 123 | 124 | /* Begin PBXHeadersBuildPhase section */ 125 | 65F49F581BC006F000939241 /* Headers */ = { 126 | isa = PBXHeadersBuildPhase; 127 | buildActionMask = 2147483647; 128 | files = ( 129 | 65F49F5F1BC006F000939241 /* Sails.h in Headers */, 130 | ); 131 | runOnlyForDeploymentPostprocessing = 0; 132 | }; 133 | /* End PBXHeadersBuildPhase section */ 134 | 135 | /* Begin PBXNativeTarget section */ 136 | 65F49F5A1BC006F000939241 /* Sails */ = { 137 | isa = PBXNativeTarget; 138 | buildConfigurationList = 65F49F6F1BC006F000939241 /* Build configuration list for PBXNativeTarget "Sails" */; 139 | buildPhases = ( 140 | 65F49F561BC006F000939241 /* Sources */, 141 | 65F49F571BC006F000939241 /* Frameworks */, 142 | 65F49F581BC006F000939241 /* Headers */, 143 | 65F49F591BC006F000939241 /* Resources */, 144 | ); 145 | buildRules = ( 146 | ); 147 | dependencies = ( 148 | ); 149 | name = Sails; 150 | productName = Sails; 151 | productReference = 65F49F5B1BC006F000939241 /* Sails.framework */; 152 | productType = "com.apple.product-type.framework"; 153 | }; 154 | 65F49F641BC006F000939241 /* SailsTests */ = { 155 | isa = PBXNativeTarget; 156 | buildConfigurationList = 65F49F721BC006F000939241 /* Build configuration list for PBXNativeTarget "SailsTests" */; 157 | buildPhases = ( 158 | 65F49F611BC006F000939241 /* Sources */, 159 | 65F49F621BC006F000939241 /* Frameworks */, 160 | 65F49F631BC006F000939241 /* Resources */, 161 | ); 162 | buildRules = ( 163 | ); 164 | dependencies = ( 165 | 65F49F681BC006F000939241 /* PBXTargetDependency */, 166 | ); 167 | name = SailsTests; 168 | productName = SailsTests; 169 | productReference = 65F49F651BC006F000939241 /* SailsTests.xctest */; 170 | productType = "com.apple.product-type.bundle.unit-test"; 171 | }; 172 | /* End PBXNativeTarget section */ 173 | 174 | /* Begin PBXProject section */ 175 | 65F49F521BC006F000939241 /* Project object */ = { 176 | isa = PBXProject; 177 | attributes = { 178 | LastSwiftUpdateCheck = 0700; 179 | LastUpgradeCheck = 0700; 180 | ORGANIZATIONNAME = "Danielle Lancashire"; 181 | TargetAttributes = { 182 | 65F49F5A1BC006F000939241 = { 183 | CreatedOnToolsVersion = 7.0; 184 | }; 185 | 65F49F641BC006F000939241 = { 186 | CreatedOnToolsVersion = 7.0; 187 | }; 188 | }; 189 | }; 190 | buildConfigurationList = 65F49F551BC006F000939241 /* Build configuration list for PBXProject "Sails" */; 191 | compatibilityVersion = "Xcode 3.2"; 192 | developmentRegion = English; 193 | hasScannedForEncodings = 0; 194 | knownRegions = ( 195 | en, 196 | ); 197 | mainGroup = 65F49F511BC006F000939241; 198 | productRefGroup = 65F49F5C1BC006F000939241 /* Products */; 199 | projectDirPath = ""; 200 | projectRoot = ""; 201 | targets = ( 202 | 65F49F5A1BC006F000939241 /* Sails */, 203 | 65F49F641BC006F000939241 /* SailsTests */, 204 | ); 205 | }; 206 | /* End PBXProject section */ 207 | 208 | /* Begin PBXResourcesBuildPhase section */ 209 | 65F49F591BC006F000939241 /* Resources */ = { 210 | isa = PBXResourcesBuildPhase; 211 | buildActionMask = 2147483647; 212 | files = ( 213 | ); 214 | runOnlyForDeploymentPostprocessing = 0; 215 | }; 216 | 65F49F631BC006F000939241 /* Resources */ = { 217 | isa = PBXResourcesBuildPhase; 218 | buildActionMask = 2147483647; 219 | files = ( 220 | ); 221 | runOnlyForDeploymentPostprocessing = 0; 222 | }; 223 | /* End PBXResourcesBuildPhase section */ 224 | 225 | /* Begin PBXSourcesBuildPhase section */ 226 | 65F49F561BC006F000939241 /* Sources */ = { 227 | isa = PBXSourcesBuildPhase; 228 | buildActionMask = 2147483647; 229 | files = ( 230 | 65F70EA71BC0F544002ADFB0 /* HTTPMethods.swift in Sources */, 231 | 65BC1A4F1BC0F50200091F45 /* HTTPResponse.swift in Sources */, 232 | 65BC1A4D1BC0F4FB00091F45 /* HTTPRequest.swift in Sources */, 233 | 65F70EAB1BC0F5D6002ADFB0 /* HTTPParser.swift in Sources */, 234 | 65F49F781BC00E6E00939241 /* Socket.swift in Sources */, 235 | 65F70EA91BC0F5BB002ADFB0 /* Router.swift in Sources */, 236 | 65F49F761BC00E1D00939241 /* Sails.swift in Sources */, 237 | ); 238 | runOnlyForDeploymentPostprocessing = 0; 239 | }; 240 | 65F49F611BC006F000939241 /* Sources */ = { 241 | isa = PBXSourcesBuildPhase; 242 | buildActionMask = 2147483647; 243 | files = ( 244 | 65F70EAF1BC0F67E002ADFB0 /* RouterTests.swift in Sources */, 245 | 65F70EB11BC0F686002ADFB0 /* SailsTests.swift in Sources */, 246 | 65BC1A4B1BC0416A00091F45 /* Assertions.swift in Sources */, 247 | 65F70EAD1BC0F677002ADFB0 /* HTTPParserTests.swift in Sources */, 248 | 65BC1A491BC02BB700091F45 /* SocketTests.swift in Sources */, 249 | ); 250 | runOnlyForDeploymentPostprocessing = 0; 251 | }; 252 | /* End PBXSourcesBuildPhase section */ 253 | 254 | /* Begin PBXTargetDependency section */ 255 | 65F49F681BC006F000939241 /* PBXTargetDependency */ = { 256 | isa = PBXTargetDependency; 257 | target = 65F49F5A1BC006F000939241 /* Sails */; 258 | targetProxy = 65F49F671BC006F000939241 /* PBXContainerItemProxy */; 259 | }; 260 | /* End PBXTargetDependency section */ 261 | 262 | /* Begin XCBuildConfiguration section */ 263 | 65F49F6D1BC006F000939241 /* Debug */ = { 264 | isa = XCBuildConfiguration; 265 | buildSettings = { 266 | ALWAYS_SEARCH_USER_PATHS = NO; 267 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 268 | CLANG_CXX_LIBRARY = "libc++"; 269 | CLANG_ENABLE_MODULES = YES; 270 | CLANG_ENABLE_OBJC_ARC = YES; 271 | CLANG_WARN_BOOL_CONVERSION = YES; 272 | CLANG_WARN_CONSTANT_CONVERSION = YES; 273 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 274 | CLANG_WARN_EMPTY_BODY = YES; 275 | CLANG_WARN_ENUM_CONVERSION = YES; 276 | CLANG_WARN_INT_CONVERSION = YES; 277 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 278 | CLANG_WARN_UNREACHABLE_CODE = YES; 279 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 280 | COPY_PHASE_STRIP = NO; 281 | CURRENT_PROJECT_VERSION = 1; 282 | DEBUG_INFORMATION_FORMAT = dwarf; 283 | ENABLE_STRICT_OBJC_MSGSEND = YES; 284 | ENABLE_TESTABILITY = YES; 285 | GCC_C_LANGUAGE_STANDARD = gnu99; 286 | GCC_DYNAMIC_NO_PIC = NO; 287 | GCC_NO_COMMON_BLOCKS = YES; 288 | GCC_OPTIMIZATION_LEVEL = 0; 289 | GCC_PREPROCESSOR_DEFINITIONS = ( 290 | "DEBUG=1", 291 | "$(inherited)", 292 | ); 293 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 294 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 295 | GCC_WARN_UNDECLARED_SELECTOR = YES; 296 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 297 | GCC_WARN_UNUSED_FUNCTION = YES; 298 | GCC_WARN_UNUSED_VARIABLE = YES; 299 | MACOSX_DEPLOYMENT_TARGET = 10.11; 300 | MTL_ENABLE_DEBUG_INFO = YES; 301 | ONLY_ACTIVE_ARCH = YES; 302 | SDKROOT = macosx; 303 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 304 | VERSIONING_SYSTEM = "apple-generic"; 305 | VERSION_INFO_PREFIX = ""; 306 | }; 307 | name = Debug; 308 | }; 309 | 65F49F6E1BC006F000939241 /* Release */ = { 310 | isa = XCBuildConfiguration; 311 | buildSettings = { 312 | ALWAYS_SEARCH_USER_PATHS = NO; 313 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 314 | CLANG_CXX_LIBRARY = "libc++"; 315 | CLANG_ENABLE_MODULES = YES; 316 | CLANG_ENABLE_OBJC_ARC = YES; 317 | CLANG_WARN_BOOL_CONVERSION = YES; 318 | CLANG_WARN_CONSTANT_CONVERSION = YES; 319 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 320 | CLANG_WARN_EMPTY_BODY = YES; 321 | CLANG_WARN_ENUM_CONVERSION = YES; 322 | CLANG_WARN_INT_CONVERSION = YES; 323 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 324 | CLANG_WARN_UNREACHABLE_CODE = YES; 325 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 326 | COPY_PHASE_STRIP = NO; 327 | CURRENT_PROJECT_VERSION = 1; 328 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 329 | ENABLE_NS_ASSERTIONS = NO; 330 | ENABLE_STRICT_OBJC_MSGSEND = YES; 331 | GCC_C_LANGUAGE_STANDARD = gnu99; 332 | GCC_NO_COMMON_BLOCKS = YES; 333 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 334 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 335 | GCC_WARN_UNDECLARED_SELECTOR = YES; 336 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 337 | GCC_WARN_UNUSED_FUNCTION = YES; 338 | GCC_WARN_UNUSED_VARIABLE = YES; 339 | MACOSX_DEPLOYMENT_TARGET = 10.11; 340 | MTL_ENABLE_DEBUG_INFO = NO; 341 | SDKROOT = macosx; 342 | VERSIONING_SYSTEM = "apple-generic"; 343 | VERSION_INFO_PREFIX = ""; 344 | }; 345 | name = Release; 346 | }; 347 | 65F49F701BC006F000939241 /* Debug */ = { 348 | isa = XCBuildConfiguration; 349 | buildSettings = { 350 | CLANG_ENABLE_MODULES = YES; 351 | COMBINE_HIDPI_IMAGES = YES; 352 | DEFINES_MODULE = YES; 353 | DYLIB_COMPATIBILITY_VERSION = 1; 354 | DYLIB_CURRENT_VERSION = 1; 355 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 356 | FRAMEWORK_VERSION = A; 357 | INFOPLIST_FILE = Sails/Info.plist; 358 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 359 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; 360 | PRODUCT_BUNDLE_IDENTIFIER = co.rocketapps.Sails; 361 | PRODUCT_NAME = "$(TARGET_NAME)"; 362 | SKIP_INSTALL = YES; 363 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 364 | }; 365 | name = Debug; 366 | }; 367 | 65F49F711BC006F000939241 /* Release */ = { 368 | isa = XCBuildConfiguration; 369 | buildSettings = { 370 | CLANG_ENABLE_MODULES = YES; 371 | COMBINE_HIDPI_IMAGES = YES; 372 | DEFINES_MODULE = YES; 373 | DYLIB_COMPATIBILITY_VERSION = 1; 374 | DYLIB_CURRENT_VERSION = 1; 375 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 376 | FRAMEWORK_VERSION = A; 377 | INFOPLIST_FILE = Sails/Info.plist; 378 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 379 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; 380 | PRODUCT_BUNDLE_IDENTIFIER = co.rocketapps.Sails; 381 | PRODUCT_NAME = "$(TARGET_NAME)"; 382 | SKIP_INSTALL = YES; 383 | }; 384 | name = Release; 385 | }; 386 | 65F49F731BC006F000939241 /* Debug */ = { 387 | isa = XCBuildConfiguration; 388 | buildSettings = { 389 | CLANG_ENABLE_MODULES = YES; 390 | COMBINE_HIDPI_IMAGES = YES; 391 | INFOPLIST_FILE = SailsTests/Info.plist; 392 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; 393 | PRODUCT_BUNDLE_IDENTIFIER = co.rocketapps.SailsTests; 394 | PRODUCT_NAME = "$(TARGET_NAME)"; 395 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 396 | }; 397 | name = Debug; 398 | }; 399 | 65F49F741BC006F000939241 /* Release */ = { 400 | isa = XCBuildConfiguration; 401 | buildSettings = { 402 | CLANG_ENABLE_MODULES = YES; 403 | COMBINE_HIDPI_IMAGES = YES; 404 | INFOPLIST_FILE = SailsTests/Info.plist; 405 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; 406 | PRODUCT_BUNDLE_IDENTIFIER = co.rocketapps.SailsTests; 407 | PRODUCT_NAME = "$(TARGET_NAME)"; 408 | }; 409 | name = Release; 410 | }; 411 | /* End XCBuildConfiguration section */ 412 | 413 | /* Begin XCConfigurationList section */ 414 | 65F49F551BC006F000939241 /* Build configuration list for PBXProject "Sails" */ = { 415 | isa = XCConfigurationList; 416 | buildConfigurations = ( 417 | 65F49F6D1BC006F000939241 /* Debug */, 418 | 65F49F6E1BC006F000939241 /* Release */, 419 | ); 420 | defaultConfigurationIsVisible = 0; 421 | defaultConfigurationName = Release; 422 | }; 423 | 65F49F6F1BC006F000939241 /* Build configuration list for PBXNativeTarget "Sails" */ = { 424 | isa = XCConfigurationList; 425 | buildConfigurations = ( 426 | 65F49F701BC006F000939241 /* Debug */, 427 | 65F49F711BC006F000939241 /* Release */, 428 | ); 429 | defaultConfigurationIsVisible = 0; 430 | defaultConfigurationName = Release; 431 | }; 432 | 65F49F721BC006F000939241 /* Build configuration list for PBXNativeTarget "SailsTests" */ = { 433 | isa = XCConfigurationList; 434 | buildConfigurations = ( 435 | 65F49F731BC006F000939241 /* Debug */, 436 | 65F49F741BC006F000939241 /* Release */, 437 | ); 438 | defaultConfigurationIsVisible = 0; 439 | defaultConfigurationName = Release; 440 | }; 441 | /* End XCConfigurationList section */ 442 | }; 443 | rootObject = 65F49F521BC006F000939241 /* Project object */; 444 | } 445 | --------------------------------------------------------------------------------