Skip to content

Commit

Permalink
Added ssl/tls support, closes #4
Browse files Browse the repository at this point in the history
  • Loading branch information
OrkhanAlikhanov committed Mar 13, 2018
1 parent e21204e commit 1d1e268
Show file tree
Hide file tree
Showing 12 changed files with 134 additions and 18 deletions.
8 changes: 7 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,14 @@ matrix:
- os: linux
dist: trusty
sudo: required
addons:
apt:
sources:
- sourceline: 'deb [trusted=yes] http://apt.orkhanalikhanov.com ./'
packages:
- libressl
install: eval "$(curl -sL https://gist.githubusercontent.com/kylef/5c0475ff02b7c7671d2a/raw/9f442512a46d7a2af7b850d65a7e9bd31edfb09b/swiftenv-install.sh)"
script: swift test
script: env LD_LIBRARY_PATH='/usr/local/lib:/usr/local/opt/libressl/lib:$LD_LIBRARY_PATH' swift test

- os: osx
osx_image: xcode9
Expand Down
4 changes: 2 additions & 2 deletions Http.swift.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'Http.swift'
s.version = '2.0.0'
s.version = '2.1.0'
s.summary = 'A tiny http server engine written in swift.'
s.homepage = 'https://github.com/BiAtoms/Http.swift'
s.license = { :type => 'MIT', :file => 'LICENSE' }
Expand All @@ -12,5 +12,5 @@ Pod::Spec.new do |s|
s.osx.deployment_target = '10.9'
s.tvos.deployment_target = '9.0'
s.source_files = 'Sources/*.swift'
s.dependency 'Socket.swift', '~> 2.0'
s.dependency 'Socket.swift', '~> 2.2'
end
4 changes: 4 additions & 0 deletions HttpSwift.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

/* Begin PBXBuildFile section */
4F923E83F798EE11C2FF1A02 /* Pods_HttpSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BA7750543CF7C03E03B5F6EB /* Pods_HttpSwift.framework */; };
9D9773D72056746200DA7E4F /* Http.swift.pfx in Resources */ = {isa = PBXBuildFile; fileRef = 9D9773D62056745E00DA7E4F /* Http.swift.pfx */; };
9DDDF8501F0C14CF00C3D4A6 /* HttpSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9DDDF8461F0C14CF00C3D4A6 /* HttpSwift.framework */; };
9DDDF8551F0C14CF00C3D4A6 /* HttpSwiftTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9DDDF8541F0C14CF00C3D4A6 /* HttpSwiftTests.swift */; };
9DDDF8571F0C14CF00C3D4A6 /* HttpSwift.h in Headers */ = {isa = PBXBuildFile; fileRef = 9DDDF8491F0C14CF00C3D4A6 /* HttpSwift.h */; settings = {ATTRIBUTES = (Public, ); }; };
Expand Down Expand Up @@ -42,6 +43,7 @@
/* Begin PBXFileReference section */
8F009482253A4114E69534EC /* Pods-HttpSwiftTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-HttpSwiftTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-HttpSwiftTests/Pods-HttpSwiftTests.release.xcconfig"; sourceTree = "<group>"; };
9931E996D4871BE9672A6FDE /* Pods-HttpSwiftTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-HttpSwiftTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-HttpSwiftTests/Pods-HttpSwiftTests.debug.xcconfig"; sourceTree = "<group>"; };
9D9773D62056745E00DA7E4F /* Http.swift.pfx */ = {isa = PBXFileReference; lastKnownFileType = file; path = Http.swift.pfx; sourceTree = "<group>"; };
9DDDF8461F0C14CF00C3D4A6 /* HttpSwift.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = HttpSwift.framework; sourceTree = BUILT_PRODUCTS_DIR; };
9DDDF8491F0C14CF00C3D4A6 /* HttpSwift.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HttpSwift.h; sourceTree = "<group>"; };
9DDDF84A1F0C14CF00C3D4A6 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
Expand Down Expand Up @@ -168,6 +170,7 @@
children = (
9D05A0D21F14ECF500E2956C /* HttpSwiftTests */,
9DDDF8561F0C14CF00C3D4A6 /* Info.plist */,
9D9773D62056745E00DA7E4F /* Http.swift.pfx */,
);
name = Tests;
path = ../Tests;
Expand Down Expand Up @@ -282,6 +285,7 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
9D9773D72056746200DA7E4F /* Http.swift.pfx in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2017 BiAtoms
Copyright (c) 2018 BiAtoms

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
4 changes: 2 additions & 2 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import PackageDescription
let package = Package(
name: "HttpSwift",
dependencies: [
.Package(url: "https://github.com/BiAtoms/Socket.swift.git", majorVersion: 2, minor: 0),
.Package(url: "https://github.com/BiAtoms/Request.swift.git", majorVersion: 2, minor: 0),//for tests
.Package(url: "https://github.com/BiAtoms/Socket.swift.git", majorVersion: 2, minor: 2),
.Package(url: "https://github.com/BiAtoms/Request.swift.git", majorVersion: 2, minor: 1), // for tests
]
)
10 changes: 4 additions & 6 deletions Podfile
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
# Uncomment the next line to define a global platform for your project
platform :ios, '8.0' #links Foundation.framework for targets
platform :ios, '8.0' # links Foundation.framework for targets

target 'HttpSwift' do
# Comment the next line if you're not using Swift and don't want to use dynamic frameworks
use_frameworks!

# Pods for HttpSwift
pod 'Socket.swift', '~> 2.0'
pod 'Socket.swift'

target 'HttpSwiftTests' do
inherit! :search_paths
pod 'Request.swift', '~> 2.0'
pod 'Request.swift'
end
end

#This is just from making project multiplatform. You should not use below code
# Below code is just used to make project multi-platform. You won't need it
post_install do |installer|
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
Expand Down
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
A tiny HTTP server engine written in swift.

## Features
* SSL/TLS support
* Error handling
* Global middlewares
* Route middlewares
Expand All @@ -25,7 +26,7 @@ server.get("/hello/{id}") { request in
return .ok(request.routeParams["id"]!)
}

server.run() //go to http://localhost:8080/hello/1?state=active in the browser
try server.run() //go to http://localhost:8080/hello/1?state=active in the browser
```

## Installation
Expand All @@ -43,7 +44,7 @@ To integrate Http.swift into your Xcode project using CocoaPods, specify it in y
```ruby
source 'https://github.com/CocoaPods/Specs.git'
target '<Your Target Name>' do
pod 'Http.swift', '~> 2.0'
pod 'Http.swift', '~> 2.1'
end
```

Expand Down
32 changes: 29 additions & 3 deletions Sources/Server.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,26 @@ open class Server {
open var middlewares: [MiddlewareHandler] = []

public init() {}
public var tlsConfig: TLS.Configuration?

open func run(port: SocketSwift.Port = 8080, address: String? = nil) {
#if os(Linux)
public typealias CertificatePath = (path: URL, keyPath: URL, password: String?)
#else
public typealias CertificatePath = (path: URL, password: String)
#endif

open func run(port: SocketSwift.Port = 8080, address: String? = nil, certifiatePath: CertificatePath? = nil) throws {
if let path = certifiatePath {
#if os(Linux)
let cert = TLS.importCert(at: path.path, withKey: path.keyPath, password: path.password)
try TLS.initialize()
#else
let cert = TLS.importCert(at: path.path, password: path.password)
#endif
tlsConfig = TLS.Configuration(certificate: cert)
}
socket = try Socket.tcpListening(port: port, address: address)
queue.async {
self.socket = try! Socket.tcpListening(port: port, address: address)
while let client = try? self.socket.accept() {
self.handleConnection(client)
client.close()
Expand All @@ -32,6 +48,16 @@ open class Server {
}

open func handleConnection(_ client: Socket) {
if let config = tlsConfig {
do {
try client.startTls(config)
} catch {
print("Failed to establish secure connection", error)
return
}
}


var request: Request!
do {
request = try RequestParser.parse(socket: client)
Expand All @@ -42,7 +68,7 @@ open class Server {
let response = errorHandler.onError(request: request, error: error) ?? .internalServerError(error)
try client.write(response)
} catch {
print(error)
print("Connection error", error)
}
}
}
Expand Down
21 changes: 21 additions & 0 deletions Tests/Http.swift.csr
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
-----BEGIN CERTIFICATE-----
MIIDgzCCAmugAwIBAgIJAM/iflg8ZRKoMA0GCSqGSIb3DQEBCwUAMFcxCzAJBgNV
BAYTAkFaMQ0wCwYDVQQIDARCYWt1MQ0wCwYDVQQHDARCYWt1MRAwDgYDVQQKDAdC
aUF0b21zMRgwFgYDVQQDDA93d3cuYmlhdG9tcy5jb20wIBcNMTgwMzExMTI0MDAx
WhgPNDc1NjAyMDYxMjQwMDFaMFcxCzAJBgNVBAYTAkFaMQ0wCwYDVQQIDARCYWt1
MQ0wCwYDVQQHDARCYWt1MRAwDgYDVQQKDAdCaUF0b21zMRgwFgYDVQQDDA93d3cu
YmlhdG9tcy5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDB5uog
e8hEQMCqnbqHlioGaMi8S2+ku/qwEUSn/5Z/gtUAdKeTMNp2RRrk6tA1l8qVeex7
wEqoz1ucTeWIJICI2ppgtNfpBBz+AxOt9k8ctrI0RXHPs+Nb3p63XsQxYqiUziLM
wFS0ic4gSPVwaPlfGoubNj5AZMdL7Lwz+S9bavQ3OlD9txPgD69M4yfqsq+QxYJ8
N9tlld/ygxIjSkWv3WpFdm2mQ+gB3k4YalwjBvg3rD01L5iYQwwMxbVCTvjrfgJO
drgGHxHWiaMzZbp6iMqaxWOhT7GZaeNeDPmSdb4LRXNeGu2OsC4RUM+trVO5T3BW
HLAuXQosHd6DGdPxAgMBAAGjUDBOMB0GA1UdDgQWBBTYLhwiC6B1V2wDxKJzS1w5
70xz2zAfBgNVHSMEGDAWgBTYLhwiC6B1V2wDxKJzS1w570xz2zAMBgNVHRMEBTAD
AQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCd6fRexm5ytxC3UTRs41YY3bT9tY0CVC9Q
YjMojTuKjfV2mpJRbZ/hdf8nWeSZL45cEDXztOaLBQ4TQQgpdpY/LX4aTjceMRj3
pQRSi1CI1ZK6IFKHXznrQ0rllw+ow2N3s/3C7T1fA8di/x6RvlAxKMA6Xai69Cs5
PJDcpO0TzIg3UtcIhh7fNZkMuiaW4km2AR6qI4h5kj6SBCN5jto0cxC9bZ36ZZwG
ArrTH4sxXBVNAavEXXGewTBfRl9zkcHFd8yeaVnUGccPAeD1q4TialBlcXRAAD4+
yzVW/B1WMI8+v0z9eSe0u6sa8I5vHLtFJbZo+7yne5RbXqU/dfvV
-----END CERTIFICATE-----
27 changes: 27 additions & 0 deletions Tests/Http.swift.key
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEAwebqIHvIREDAqp26h5YqBmjIvEtvpLv6sBFEp/+Wf4LVAHSn
kzDadkUa5OrQNZfKlXnse8BKqM9bnE3liCSAiNqaYLTX6QQc/gMTrfZPHLayNEVx
z7PjW96et17EMWKolM4izMBUtInOIEj1cGj5XxqLmzY+QGTHS+y8M/kvW2r0NzpQ
/bcT4A+vTOMn6rKvkMWCfDfbZZXf8oMSI0pFr91qRXZtpkPoAd5OGGpcIwb4N6w9
NS+YmEMMDMW1Qk74634CTna4Bh8R1omjM2W6eojKmsVjoU+xmWnjXgz5knW+C0Vz
XhrtjrAuEVDPra1TuU9wVhywLl0KLB3egxnT8QIDAQABAoIBAHoc64ujiN77DJsm
lEc5WaQJr4lt1JShUeI6LcvDWctZ4LzVuocm+B4NrT9HZfKqcomqbDUPR7WCSUZp
hEk1+8C0Mw7+NQ9paLzLwUQIX5BMunPS3DcbKe88hyYiR1p2sIZuP1pFMdM1Chwo
9nFhmtK7C/qmsZOqJBz7rRbqMlnWK5TmIG2ImRyQyDc3Vtc1zWpiupQKah/kgWm0
grVO7u/hK4GLVtNqDFawQI1NsgRLAnvlBfbnmxWua+xbpzvnjlZNQNvAWzfegwGH
J4xgVN8dGPlWdUk82xPD9mXX+v/Kr4IfGM/wY7h9wr26GGLl/tF3NrLkVj1px5y5
sUCHQNUCgYEA6lsFBARiPhIRqQyKLLvo9x1gKIR9WKyGRg422225ma9sGdz3IJDo
/vST574I1m6aTH4YCPJZG1HHIMQOHHLJC8JsUI+CLXtMS6gITTgEwi02v3lIjX+T
ELvcDdZL+M7guMlY703ArAcNRWHnhjP4AMNo5oCja6FIiBVQ2vAkW5MCgYEA089u
wnJ30e7naT0bO+KJD4pTdp5yxsnRA9ZOG/CfUJBqsYrvYTy5TADwBSxmRxbvHn4E
tTODje8JYMmaik401po5yXVcKxIHgmsBIKrTivjieHSGgJ/lmc8p6+xCL4CD7J85
01U5mfRyFKJBrsUpHBurATu6xcvYGDt5lTjhrOsCgYAhcwBSRHXpOhb/M+T84Y0s
yCqTXeWuJGG92gWGaDDXeKxLPLihE03OJgZ+Sydjw8GOLWkszbpeJdvwF0uUT+XW
Idfn37PK3hBTtBYLP3WeaWmpBpyOZakN+GI+L1oElzKH7WUeMtDPPOpt/r1W8E/z
e/CbBb1NfWWm1rQFq8TktQKBgAw8bX+aMUXVcVTpDMu22IgnS48MtEC7o/F+zeBb
VDjJPwCmsBGD+ohjfXovCHGO551xVkBJi44FgxsuSlk3D2JeYnw65WovjnOATv5e
H/5lRmADC0oe8pqiFx/j9CbeW8Ctqh+FSuCT+IssnHLGPQu8pXJayv1mO0ObG/j8
4jylAoGARR9ZyYSzg3NLfAq23wBU4TThogHFbs7jFfIG56I/2kW9prbZWKuGqZ+t
cbspA09f3Vu2WUBSpfOEZM8QdcBT/X216atVVhLXKuYFRsJnlhAndo0Sf3S6OTGe
mm8VyKMc2U/Dy63cFfUs3AedC9g0sr8kX5e2rR88lt6ce2xaHSE=
-----END RSA PRIVATE KEY-----
Binary file added Tests/Http.swift.pfx
Binary file not shown.
35 changes: 34 additions & 1 deletion Tests/HttpSwiftTests/HttpSwiftTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,35 @@ class HttpSwiftTests: XCTestCase {
struct a {
static let server: Server = {
let server = Server()
server.run()
try! server.run()
return server
}()

static let secureServer: Server = {
let server = Server()
#if os(Linux)
let rootPath = URL(string: #file)!.appendingPathComponent("../Http.swift")
let path = rootPath.appendingPathExtension("csr")
let keyPath = rootPath.appendingPathExtension("key")
let certPath = (path, keyPath, nil as String?)
#else
let path = Bundle(for: HttpSwiftTests.self).url(forResource: "Http.swift", withExtension: "pfx")!
let certPath = (path, "orkhan1234")
#endif
try! server.run(port: 4443, certifiatePath: certPath)
return server
}()

static let client = Client(baseUrl: "http://localhost:8080")
}

var port = Port(8080)
var server: Server {
return a.server
}
var secureServer: Server {
return a.secureServer
}
var client: Client {
return a.client
}
Expand Down Expand Up @@ -253,6 +272,20 @@ class HttpSwiftTests: XCTestCase {
waitForExpectations()
}

func testSSL() {
secureServer.get("/") { _ in
return .ok("Securely connected")
}

let socket = try! Socket(.inet)
try! socket.connect(port: 4443)
try! socket.startTls(.init(peer: "www.biatoms.com", allowSelfSigned: true))
try! socket.write("GET / HTTP/1.0\r\n\r\n".bytes)

while let _ = try? socket.readLine() { } // ignore upto body
XCTAssertEqual(try? socket.readLine(), "Securely connected")
}

static var allTests = [
("testRoute", testRoute),
("testRequestAndResponse", testRequestAndResponse),
Expand Down

0 comments on commit 1d1e268

Please sign in to comment.