├── 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 |
--------------------------------------------------------------------------------