diff --git a/.swift-version b/.swift-version
index 7d5c902..a75b92f 100644
--- a/.swift-version
+++ b/.swift-version
@@ -1 +1 @@
-4.1
+5.1
diff --git a/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata b/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000..919434a
--- /dev/null
+++ b/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+
+
+
+
+
diff --git a/.swiftpm/xcode/package.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/.swiftpm/xcode/package.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
new file mode 100644
index 0000000..18d9810
--- /dev/null
+++ b/.swiftpm/xcode/package.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
@@ -0,0 +1,8 @@
+
+
+
+
+ IDEDidComputeMac32BitWarning
+
+
+
diff --git a/.swiftpm/xcode/package.xcworkspace/xcuserdata/calebkleveter.xcuserdatad/UserInterfaceState.xcuserstate b/.swiftpm/xcode/package.xcworkspace/xcuserdata/calebkleveter.xcuserdatad/UserInterfaceState.xcuserstate
new file mode 100644
index 0000000..0100a09
Binary files /dev/null and b/.swiftpm/xcode/package.xcworkspace/xcuserdata/calebkleveter.xcuserdatad/UserInterfaceState.xcuserstate differ
diff --git a/.swiftpm/xcode/xcuserdata/calebkleveter.xcuserdatad/xcschemes/xcschememanagement.plist b/.swiftpm/xcode/xcuserdata/calebkleveter.xcuserdatad/xcschemes/xcschememanagement.plist
new file mode 100644
index 0000000..5bb8aa3
--- /dev/null
+++ b/.swiftpm/xcode/xcuserdata/calebkleveter.xcuserdatad/xcschemes/xcschememanagement.plist
@@ -0,0 +1,67 @@
+
+
+
+
+ SchemeUserState
+
+ S3-Package.xcscheme_^#shared#^_
+
+ orderHint
+ 0
+
+ S3.xcscheme_^#shared#^_
+
+ orderHint
+ 1
+
+ S3DemoRun.xcscheme_^#shared#^_
+
+ orderHint
+ 4
+
+ S3Signer.xcscheme_^#shared#^_
+
+ orderHint
+ 2
+
+ S3TestTools.xcscheme_^#shared#^_
+
+ orderHint
+ 3
+
+
+ SuppressBuildableAutocreation
+
+ S3
+
+ primary
+
+
+ S3DemoApp
+
+ primary
+
+
+ S3DemoRun
+
+ primary
+
+
+ S3Signer
+
+ primary
+
+
+ S3TestTools
+
+ primary
+
+
+ S3Tests
+
+ primary
+
+
+
+
+
diff --git a/Package.resolved b/Package.resolved
index 126f8d3..55aeeb5 100644
--- a/Package.resolved
+++ b/Package.resolved
@@ -2,75 +2,57 @@
"object": {
"pins": [
{
- "package": "Console",
- "repositoryURL": "https://github.com/vapor/console.git",
+ "package": "async-kit",
+ "repositoryURL": "https://github.com/vapor/async-kit.git",
"state": {
"branch": null,
- "revision": "74cfbea629d4aac34a97cead2447a6870af1950b",
- "version": "3.1.1"
+ "revision": "b5742bfbbe2d60f3b77465a0907777261e418f23",
+ "version": "1.0.0-alpha.1"
}
},
{
- "package": "Core",
- "repositoryURL": "https://github.com/vapor/core.git",
+ "package": "console-kit",
+ "repositoryURL": "https://github.com/vapor/console-kit.git",
"state": {
"branch": null,
- "revision": "727ae2905ebdca162c5da5bfe187c406555859e2",
- "version": "3.7.3"
+ "revision": "252a8b8e22cc70ebe8a073b241b7275a3b3880d9",
+ "version": "4.0.0-alpha.1"
}
},
{
- "package": "Crypto",
- "repositoryURL": "https://github.com/vapor/crypto.git",
+ "package": "crypto-kit",
+ "repositoryURL": "https://github.com/vapor/crypto-kit.git",
"state": {
"branch": null,
- "revision": "45bb12d13cdec80dbd1cc0685ea002e51ab83439",
- "version": "3.3.2"
+ "revision": "9d5e780ad8f621e14226f0c2824648a9c062d37c",
+ "version": "4.0.0-alpha.1"
}
},
{
- "package": "DatabaseKit",
- "repositoryURL": "https://github.com/vapor/database-kit.git",
+ "package": "nio-websocket-client",
+ "repositoryURL": "https://github.com/vapor/nio-websocket-client.git",
"state": {
"branch": null,
- "revision": "8f352c8e66dab301ab9bfef912a01ce1361ba1e4",
- "version": "1.3.3"
+ "revision": "3e515024c4c9eab6adb1ab516be15777a28a233e",
+ "version": "1.0.0-alpha.1"
}
},
{
- "package": "HTTP",
- "repositoryURL": "https://github.com/vapor/http.git",
+ "package": "routing-kit",
+ "repositoryURL": "https://github.com/vapor/routing-kit.git",
"state": {
"branch": null,
- "revision": "8da7d475a1a060714766d9ad4b24eb0dae243aab",
- "version": "3.1.11"
+ "revision": "6c7f4b471f9662d05045d82e64e22d5572a16a82",
+ "version": "4.0.0-alpha.1"
}
},
{
- "package": "Multipart",
- "repositoryURL": "https://github.com/vapor/multipart.git",
+ "package": "swift-log",
+ "repositoryURL": "https://github.com/apple/swift-log.git",
"state": {
"branch": null,
- "revision": "bd7736c5f28e48ed8b683dcc9df3dcd346064c2b",
- "version": "3.0.3"
- }
- },
- {
- "package": "Routing",
- "repositoryURL": "https://github.com/vapor/routing.git",
- "state": {
- "branch": null,
- "revision": "626190ddd2bd9f967743b60ba6adaf90bbd2651c",
- "version": "3.0.2"
- }
- },
- {
- "package": "Service",
- "repositoryURL": "https://github.com/vapor/service.git",
- "state": {
- "branch": null,
- "revision": "fa5b5de62bd68bcde9a69933f31319e46c7275fb",
- "version": "1.0.2"
+ "revision": "f4240bf022a69815241a883c03645444b58ac553",
+ "version": "1.1.0"
}
},
{
@@ -78,89 +60,53 @@
"repositoryURL": "https://github.com/apple/swift-nio.git",
"state": {
"branch": null,
- "revision": "29a9f2aca71c8afb07e291336f1789337ce235dd",
- "version": "1.13.2"
- }
- },
- {
- "package": "swift-nio-ssl",
- "repositoryURL": "https://github.com/apple/swift-nio-ssl.git",
- "state": {
- "branch": null,
- "revision": "0f3999f3e3c359cc74480c292644c3419e44a12f",
- "version": "1.4.0"
+ "revision": "7f20464df31e85f86bedf4a8afdd1785e0cb5059",
+ "version": "2.3.0"
}
},
{
- "package": "swift-nio-ssl-support",
- "repositoryURL": "https://github.com/apple/swift-nio-ssl-support.git",
+ "package": "swift-nio-extras",
+ "repositoryURL": "https://github.com/apple/swift-nio-extras.git",
"state": {
"branch": null,
- "revision": "c02eec4e0e6d351cd092938cf44195a8e669f555",
- "version": "1.0.0"
+ "revision": "96e8335180ca61c7187efe47058a1c99eadaf265",
+ "version": "1.1.0"
}
},
{
- "package": "swift-nio-zlib-support",
- "repositoryURL": "https://github.com/apple/swift-nio-zlib-support.git",
+ "package": "swift-nio-http-client",
+ "repositoryURL": "https://github.com/vapor/swift-nio-http-client.git",
"state": {
"branch": null,
- "revision": "37760e9a52030bb9011972c5213c3350fa9d41fd",
- "version": "1.0.0"
+ "revision": "93682abeb568b3df47f0744558c4436bb325f860",
+ "version": "0.0.0"
}
},
{
- "package": "TemplateKit",
- "repositoryURL": "https://github.com/vapor/template-kit.git",
+ "package": "swift-nio-http2",
+ "repositoryURL": "https://github.com/apple/swift-nio-http2.git",
"state": {
"branch": null,
- "revision": "4b1073d74be9f5c6a5bc63a07a84e83efec26229",
- "version": "1.1.2"
+ "revision": "06880b0abdc5d2aa68b96d6b3b29b089cb423922",
+ "version": "1.3.0"
}
},
{
- "package": "URLEncodedForm",
- "repositoryURL": "https://github.com/vapor/url-encoded-form.git",
- "state": {
- "branch": null,
- "revision": "82d8d63bdb76b6dd8febe916c639ab8608dbbaed",
- "version": "1.0.6"
- }
- },
- {
- "package": "Validation",
- "repositoryURL": "https://github.com/vapor/validation.git",
+ "package": "swift-nio-ssl",
+ "repositoryURL": "https://github.com/apple/swift-nio-ssl.git",
"state": {
"branch": null,
- "revision": "4de213cf319b694e4ce19e5339592601d4dd3ff6",
+ "revision": "77173ac9038e8e9b92f3efe8780923447e3c890b",
"version": "2.1.1"
}
},
{
- "package": "Vapor",
+ "package": "vapor",
"repositoryURL": "https://github.com/vapor/vapor.git",
"state": {
"branch": null,
- "revision": "c86ada59b31c69f08a6abd4f776537cba48d5df6",
- "version": "3.3.0"
- }
- },
- {
- "package": "VaporTestTools",
- "repositoryURL": "https://github.com/LiveUI/VaporTestTools.git",
- "state": {
- "branch": null,
- "revision": "135d02e2e2a632c134567754d65ce2afe262bab3",
- "version": "0.1.7"
- }
- },
- {
- "package": "WebSocket",
- "repositoryURL": "https://github.com/vapor/websocket.git",
- "state": {
- "branch": null,
- "revision": "d85e5b6dce4d04065865f77385fc3324f98178f6",
- "version": "1.1.2"
+ "revision": "e415cbcacc14a5f8d02e3b6e1aea36f86064b98e",
+ "version": "4.0.0-alpha.1.5"
}
},
{
diff --git a/Package.swift b/Package.swift
index 0f6e3ea..100c593 100644
--- a/Package.swift
+++ b/Package.swift
@@ -9,9 +9,8 @@ let package = Package(
.library(name: "S3TestTools", targets: ["S3TestTools"])
],
dependencies: [
- .package(url: "https://github.com/vapor/vapor.git", from: "3.0.0"),
- .package(url: "https://github.com/LiveUI/XMLCoding.git", from: "0.1.0"),
- .package(url: "https://github.com/LiveUI/VaporTestTools.git", from: "0.1.5")
+ .package(url: "https://github.com/vapor/vapor.git", from: "4.0.0-alpha"),
+ .package(url: "https://github.com/LiveUI/XMLCoding.git", from: "0.1.0")
],
targets: [
.target(name: "S3", dependencies: [
@@ -36,7 +35,6 @@ let package = Package(
),
.target(name: "S3TestTools", dependencies: [
"Vapor",
- "VaporTestTools",
"S3"
]
),
diff --git a/README.md b/README.md
index 5eef124..9297b7b 100644
--- a/README.md
+++ b/README.md
@@ -79,70 +79,70 @@ s3.headers(...)
public protocol S3Client: Service {
/// Get list of objects
- func buckets(on: Container) throws -> Future
+ func buckets(on: Container) -> EventLoopFuture
/// Create a bucket
- func create(bucket: String, region: Region?, on container: Container) throws -> Future
+ func create(bucket: String, region: Region?, on container: Container) -> EventLoopFuture
/// Delete a bucket
- func delete(bucket: String, region: Region?, on container: Container) throws -> Future
+ func delete(bucket: String, region: Region?, on container: Container) -> EventLoopFuture
/// Get bucket location
- func location(bucket: String, on container: Container) throws -> Future
+ func location(bucket: String, on container: Container) -> EventLoopFuture
/// Get list of objects
- func list(bucket: String, region: Region?, on container: Container) throws -> Future
+ func list(bucket: String, region: Region?, on container: Container) -> EventLoopFuture
/// Get list of objects
- func list(bucket: String, region: Region?, headers: [String: String], on container: Container) throws -> Future
+ func list(bucket: String, region: Region?, headers: [String: String], on container: Container) -> EventLoopFuture
/// Upload file to S3
- func put(file: File.Upload, headers: [String: String], on: Container) throws -> EventLoopFuture
+ func put(file: File.Upload, headers: [String: String], on: Container) throws -> EventLoopEventLoopFuture
/// Upload file to S3
- func put(file url: URL, destination: String, access: AccessControlList, on: Container) throws -> Future
+ func put(file url: URL, destination: String, access: AccessControlList, on: Container) -> EventLoopFuture
/// Upload file to S3
- func put(file url: URL, destination: String, bucket: String?, access: AccessControlList, on: Container) throws -> Future
+ func put(file url: URL, destination: String, bucket: String?, access: AccessControlList, on: Container) -> EventLoopFuture
/// Upload file to S3
- func put(file path: String, destination: String, access: AccessControlList, on: Container) throws -> Future
+ func put(file path: String, destination: String, access: AccessControlList, on: Container) -> EventLoopFuture
/// Upload file to S3
- func put(file path: String, destination: String, bucket: String?, access: AccessControlList, on: Container) throws -> Future
+ func put(file path: String, destination: String, bucket: String?, access: AccessControlList, on: Container) -> EventLoopFuture
/// Upload file to S3
- func put(string: String, destination: String, on: Container) throws -> Future
+ func put(string: String, destination: String, on: Container) -> EventLoopFuture
/// Upload file to S3
- func put(string: String, destination: String, access: AccessControlList, on: Container) throws -> Future
+ func put(string: String, destination: String, access: AccessControlList, on: Container) -> EventLoopFuture
/// Upload file to S3
- func put(string: String, mime: MediaType, destination: String, on: Container) throws -> Future
+ func put(string: String, mime: MediaType, destination: String, on: Container) -> EventLoopFuture
/// Upload file to S3
- func put(string: String, mime: MediaType, destination: String, access: AccessControlList, on: Container) throws -> Future
+ func put(string: String, mime: MediaType, destination: String, access: AccessControlList, on: Container) -> EventLoopFuture
/// Upload file to S3
- func put(string: String, mime: MediaType, destination: String, bucket: String?, access: AccessControlList, on: Container) throws -> Future
+ func put(string: String, mime: MediaType, destination: String, bucket: String?, access: AccessControlList, on: Container) -> EventLoopFuture
/// Retrieve file data from S3
- func get(fileInfo file: LocationConvertible, on container: Container) throws -> Future
+ func get(fileInfo file: LocationConvertible, on container: Container) -> EventLoopFuture
/// Retrieve file data from S3
- func get(fileInfo file: LocationConvertible, headers: [String: String], on container: Container) throws -> Future
+ func get(fileInfo file: LocationConvertible, headers: [String: String], on container: Container) -> EventLoopFuture
/// Retrieve file data from S3
- func get(file: LocationConvertible, on: Container) throws -> Future
+ func get(file: LocationConvertible, on: Container) -> EventLoopFuture
/// Retrieve file data from S3
- func get(file: LocationConvertible, headers: [String: String], on: Container) throws -> Future
+ func get(file: LocationConvertible, headers: [String: String], on: Container) -> EventLoopFuture
/// Delete file from S3
- func delete(file: LocationConvertible, on: Container) throws -> Future
+ func delete(file: LocationConvertible, on: Container) -> EventLoopFuture
/// Delete file from S3
- func delete(file: LocationConvertible, headers: [String: String], on: Container) throws -> Future
+ func delete(file: LocationConvertible, headers: [String: String], on: Container) -> EventLoopFuture
}
```
@@ -152,13 +152,13 @@ public protocol S3Client: Service {
public func routes(_ router: Router) throws {
// Get all available buckets
- router.get("buckets") { req -> Future in
+ router.get("buckets") { req -> EventLoopFuture in
let s3 = try req.makeS3Client()
return try s3.buckets(on: req)
}
// Create new bucket
- router.put("bucket") { req -> Future in
+ router.put("bucket") { req -> EventLoopFuture in
let s3 = try req.makeS3Client()
return try s3.create(bucket: "api-created-bucket", region: .euCentral1, on: req).map(to: String.self) {
return ":)"
@@ -172,7 +172,7 @@ public func routes(_ router: Router) throws {
}
// Locate bucket (get region)
- router.get("bucket/location") { req -> Future in
+ router.get("bucket/location") { req -> EventLoopFuture in
let s3 = try req.makeS3Client()
return try s3.location(bucket: "bucket-name", on: req).map(to: String.self) { region in
return region.hostUrlString()
@@ -190,7 +190,7 @@ public func routes(_ router: Router) throws {
)
}
// Delete bucket
- router.delete("bucket") { req -> Future in
+ router.delete("bucket") { req -> EventLoopFuture in
let s3 = try req.makeS3Client()
return try s3.delete(bucket: "api-created-bucket", region: .euCentral1, on: req).map(to: String.self) {
return ":)"
@@ -204,7 +204,7 @@ public func routes(_ router: Router) throws {
}
// Get list of objects
- router.get("files") { req -> Future in
+ router.get("files") { req -> EventLoopFuture in
let s3 = try req.makeS3Client()
return try s3.list(bucket: "booststore", region: .usEast1, headers: [:], on: req).catchMap({ (error) -> (BucketResults) in
if let error = error.s3ErrorMessage() {
@@ -215,7 +215,7 @@ public func routes(_ router: Router) throws {
}
// Demonstrate work with files
- router.get("files/test") { req -> Future in
+ router.get("files/test") { req -> EventLoopFuture in
let string = "Content of my example file"
let fileName = "file-hu.txt"
diff --git a/Sources/S3/Extensions/HTTPHeaders+Tools.swift b/Sources/S3/Extensions/HTTPHeaders+Tools.swift
index 0534ab7..a6053ff 100644
--- a/Sources/S3/Extensions/HTTPHeaders+Tools.swift
+++ b/Sources/S3/Extensions/HTTPHeaders+Tools.swift
@@ -12,8 +12,7 @@ import Vapor
extension HTTPHeaders {
func string(_ name: String) -> String? {
- let header = HTTPHeaderName(name)
- return self[header].first
+ return self[name].first
}
func int(_ name: String) -> Int? {
diff --git a/Sources/S3/Extensions/Region+Tools.swift b/Sources/S3/Extensions/Region+Tools.swift
index 6034f46..31faebb 100644
--- a/Sources/S3/Extensions/Region+Tools.swift
+++ b/Sources/S3/Extensions/Region+Tools.swift
@@ -5,9 +5,8 @@
// Created by Ondrej Rafaj on 19/04/2018.
//
-import Foundation
-import Core
@_exported import S3Signer
+import Foundation
extension Region {
diff --git a/Sources/S3/Extensions/Response+XMLDecoding.swift b/Sources/S3/Extensions/Response+XMLDecoding.swift
index de3384c..3ab119d 100644
--- a/Sources/S3/Extensions/Response+XMLDecoding.swift
+++ b/Sources/S3/Extensions/Response+XMLDecoding.swift
@@ -31,7 +31,7 @@ extension Response {
}()
func decode(to: T.Type) throws -> T where T: Decodable {
- guard let data = http.body.data else {
+ guard let data = self.body.data else {
throw S3.Error.badResponse(self)
}
diff --git a/Sources/S3/Extensions/S3+Bucket.swift b/Sources/S3/Extensions/S3+Bucket.swift
index b9f17f5..1c861ea 100644
--- a/Sources/S3/Extensions/S3+Bucket.swift
+++ b/Sources/S3/Extensions/S3+Bucket.swift
@@ -16,17 +16,23 @@ extension S3 {
// MARK: Buckets
/// Get bucket location
- public func location(bucket: String, on container: Container) throws -> Future {
- let builder = urlBuilder(for: container)
+ public func location(bucket: String, on eventLoop: EventLoop) -> EventLoopFuture {
+ let url: URL
+ let awsHeaders: HTTPHeaders
let region = Region.euWest2
- let url = try builder.url(region: region, bucket: bucket, path: nil)
-
- let awsHeaders = try signer.headers(for: .GET, urlString: url.absoluteString, region: region, bucket: bucket, payload: .none)
- return try make(request: url, method: .GET, headers: awsHeaders, data: emptyData(), on: container).map(to: Region.self) { response in
- if response.http.status == .notFound {
+
+ do {
+ url = try makeURLBuilder().url(region: region, bucket: bucket, path: nil)
+ awsHeaders = try signer.headers(for: .GET, urlString: url.absoluteString, region: region, bucket: bucket, payload: .none)
+ } catch let error {
+ return eventLoop.future(error: error)
+ }
+
+ return make(request: url, method: .GET, headers: awsHeaders, data: emptyData(), on: eventLoop).flatMapThrowing { response in
+ if response.status == .notFound {
throw Error.notFound
}
- if response.http.status == .ok {
+ if response.status == .ok {
return region
} else {
if let error = try? response.decode(to: ErrorMessage.self), error.code == "PermanentRedirect", let endpoint = error.endpoint {
@@ -49,36 +55,41 @@ extension S3 {
}
/// Delete bucket
- public func delete(bucket: String, region: Region? = nil, on container: Container) throws -> Future {
- let builder = urlBuilder(for: container)
- let url = try builder.url(region: region, bucket: bucket, path: nil)
-
- let awsHeaders = try signer.headers(for: .DELETE, urlString: url.absoluteString, region: region, bucket: bucket, payload: .none)
- return try make(request: url, method: .DELETE, headers: awsHeaders, data: emptyData(), on: container).map(to: Void.self) { response in
- try self.check(response)
- return Void()
+ public func delete(bucket: String, region: Region? = nil, on eventLoop: EventLoop) -> EventLoopFuture {
+ let url: URL
+ let awsHeaders: HTTPHeaders
+
+ do {
+ url = try makeURLBuilder().url(region: region, bucket: bucket, path: nil)
+ awsHeaders = try signer.headers(for: .DELETE, urlString: url.absoluteString, region: region, bucket: bucket, payload: .none)
+ } catch let error {
+ return eventLoop.future(error: error)
}
+
+ return make(request: url, method: .DELETE, headers: awsHeaders, data: emptyData(), on: eventLoop).flatMapThrowing(self.check).transform(to: ())
}
/// Create a bucket
- public func create(bucket: String, region: Region? = nil, on container: Container) throws -> Future {
+ public func create(bucket: String, region: Region? = nil, on eventLoop: EventLoop) -> EventLoopFuture {
let region = region ?? signer.config.region
-
- let builder = urlBuilder(for: container)
- let url = try builder.url(region: region, bucket: bucket, path: nil)
-
let content = """
-
- \(region.name)
-
- """
-
- let data = content.convertToData()
- let awsHeaders = try signer.headers(for: .PUT, urlString: url.absoluteString, region: region, bucket: bucket, payload: .bytes(data))
- return try make(request: url, method: .PUT, headers: awsHeaders, data: data, on: container).map(to: Void.self) { response in
- try self.check(response)
- return Void()
+
+ \(region.name)
+
+ """
+ let data = Data(content.utf8)
+
+ let awsHeaders: HTTPHeaders
+ let url: URL
+
+ do {
+ url = try makeURLBuilder().url(region: region, bucket: bucket, path: nil)
+ awsHeaders = try signer.headers(for: .PUT, urlString: url.absoluteString, region: region, bucket: bucket, payload: .bytes(data))
+ } catch let error {
+ return eventLoop.future(error: error)
}
+
+ return make(request: url, method: .PUT, headers: awsHeaders, data: data, on: eventLoop).flatMapThrowing(self.check).transform(to: ())
}
}
diff --git a/Sources/S3/Extensions/S3+Copy.swift b/Sources/S3/Extensions/S3+Copy.swift
index 1fefdf4..c8505ef 100644
--- a/Sources/S3/Extensions/S3+Copy.swift
+++ b/Sources/S3/Extensions/S3+Copy.swift
@@ -14,30 +14,32 @@ extension S3 {
// MARK: Copy
/// Copy file on S3
- public func copy(file: LocationConvertible, to: LocationConvertible, headers: [String: String], on container: Container) throws -> Future {
- let builder = urlBuilder(for: container)
- let originPath = "\(file.bucket ?? defaultBucket)/\(file.path)"
- let destinationUrl = try builder.url(file: to)
-
- var awsHeaders: [String: String] = headers
- awsHeaders["x-amz-copy-source"] = originPath
- let headers = try signer.headers(
- for: .PUT,
- urlString: destinationUrl.absoluteString,
- headers: awsHeaders,
- payload: .none
- )
-
- let request = Request(using: container)
- request.http.method = .PUT
- request.http.headers = headers
- request.http.body = .empty
- request.http.url = destinationUrl
+ public func copy(file: LocationConvertible, to: LocationConvertible, headers strHeaders: [String: String], on eventLoop: EventLoop) -> EventLoopFuture {
+ let headers: HTTPHeaders
+ let destinationUrl: URL
+
+ do {
+ destinationUrl = try makeURLBuilder().url(file: to)
+
+ var awsHeaders: [String: String] = strHeaders
+ awsHeaders["x-amz-copy-source"] = "\(file.bucket ?? defaultBucket)/\(file.path)"
+ headers = try signer.headers(
+ for: .PUT,
+ urlString: destinationUrl.absoluteString,
+ headers: awsHeaders,
+ payload: .none
+ )
+ } catch let error {
+ return eventLoop.future(error: error)
+ }
- let client = try container.make(Client.self)
- return client.send(request).map {
- try self.check($0)
- return try $0.decode(to: File.CopyResponse.self)
+ var request = ClientRequest()
+ request.method = .PUT
+ request.headers = headers
+ request.url = URI(string: destinationUrl.description)
+
+ return self.execute(request, on: eventLoop).flatMapThrowing { response in
+ return try self.check(response).content.decode(File.CopyResponse.self)
}
}
diff --git a/Sources/S3/Extensions/S3+Delete.swift b/Sources/S3/Extensions/S3+Delete.swift
index c7bf11d..10ca393 100644
--- a/Sources/S3/Extensions/S3+Delete.swift
+++ b/Sources/S3/Extensions/S3+Delete.swift
@@ -15,21 +15,24 @@ extension S3 {
// MARK: Delete
/// Delete file from S3
- public func delete(file: LocationConvertible, headers: [String: String], on container: Container) throws -> Future {
- let builder = urlBuilder(for: container)
- let url = try builder.url(file: file)
-
- let headers = try signer.headers(for: .DELETE, urlString: url.absoluteString, headers: headers, payload: .none)
- return try make(request: url, method: .DELETE, headers: headers, data: emptyData(), on: container).map(to: Void.self) { response in
- try self.check(response)
-
- return Void()
+ public func delete(file: LocationConvertible, headers strHeaders: [String: String], on eventLoop: EventLoop) -> EventLoopFuture {
+ let headers: HTTPHeaders
+ let url: URL
+
+ do {
+ url = try makeURLBuilder().url(file: file)
+ headers = try signer.headers(for: .DELETE, urlString: url.absoluteString, headers: strHeaders, payload: .none)
+ } catch let error {
+ return eventLoop.future(error: error)
}
+
+ return make(request: url, method: .DELETE, headers: headers, data: emptyData(), on: eventLoop).flatMapThrowing(self.check).transform(to: ())
}
/// Delete file from S3
- public func delete(file: LocationConvertible, on container: Container) throws -> Future {
- return try delete(file: file, headers: [:], on: container)
+ public func delete(file: LocationConvertible, on eventLoop: EventLoop) -> EventLoopFuture {
+ return
+ delete(file: file, headers: [:], on: eventLoop)
}
}
diff --git a/Sources/S3/Extensions/S3+Get.swift b/Sources/S3/Extensions/S3+Get.swift
index 6375e5e..7c4f933 100644
--- a/Sources/S3/Extensions/S3+Get.swift
+++ b/Sources/S3/Extensions/S3+Get.swift
@@ -15,8 +15,8 @@ extension S3 {
// MARK: URL
/// File URL
- public func url(fileInfo file: LocationConvertible, on container: Container) throws -> URL {
- let builder = urlBuilder(for: container)
+ public func url(fileInfo file: LocationConvertible) throws -> URL {
+ let builder = makeURLBuilder()
let url = try builder.url(file: file)
return url
}
@@ -24,15 +24,21 @@ extension S3 {
// MARK: Get
/// Retrieve file data from S3
- public func get(file: LocationConvertible, headers: [String: String], on container: Container) throws -> Future {
- let builder = urlBuilder(for: container)
- let url = try builder.url(file: file)
-
- let headers = try signer.headers(for: .GET, urlString: url.absoluteString, headers: headers, payload: .none)
- return try make(request: url, method: .GET, headers: headers, on: container).map(to: File.Response.self) { response in
+ public func get(file: LocationConvertible, headers strHeaders: [String: String], on eventLoop: EventLoop) -> EventLoopFuture {
+ let url: URL
+ let headers: HTTPHeaders
+
+ do {
+ url = try makeURLBuilder().url(file: file)
+ headers = try signer.headers(for: .GET, urlString: url.absoluteString, headers: strHeaders, payload: .none)
+ } catch let error {
+ return eventLoop.future(error: error)
+ }
+
+ return make(request: url, method: .GET, headers: headers, on: eventLoop).flatMapThrowing { response in
try self.check(response)
- guard let data = response.http.body.data else {
+ guard let data = response.body.data else {
throw Error.missingData
}
@@ -42,8 +48,8 @@ extension S3 {
}
/// Retrieve file data from S3
- public func get(file: LocationConvertible, on container: Container) throws -> EventLoopFuture {
- return try get(file: file, headers: [:], on: container)
+ public func get(file: LocationConvertible, on eventLoop: EventLoop) -> EventLoopFuture {
+ return get(file: file, headers: [:], on: eventLoop)
}
}
diff --git a/Sources/S3/Extensions/S3+List.swift b/Sources/S3/Extensions/S3+List.swift
index a88a766..e72b530 100644
--- a/Sources/S3/Extensions/S3+List.swift
+++ b/Sources/S3/Extensions/S3+List.swift
@@ -6,36 +6,45 @@
//
import Foundation
+import NIOHTTP1
// Helper S3 extension for getting file indexes
extension S3 {
/// Get list of objects
- public func list(bucket: String, region: Region? = nil, headers: [String: String], on container: Container) throws -> Future {
+ public func list(bucket: String, region: Region? = nil, headers: [String: String], on eventLoop: EventLoop) -> EventLoopFuture {
let region = region ?? signer.config.region
guard let baseUrl = URL(string: region.hostUrlString(bucket: bucket)), let host = baseUrl.host,
var components = URLComponents(string: baseUrl.absoluteString) else {
- throw S3.Error.invalidUrl
+ return eventLoop.future(error: S3.Error.invalidUrl)
}
components.queryItems = [
URLQueryItem(name: "list-type", value: "2")
]
guard let url = components.url else {
- throw S3.Error.invalidUrl
+ return eventLoop.future(error: S3.Error.invalidUrl)
}
- var headers = headers
- headers["host"] = host
- let awsHeaders = try signer.headers(for: .GET, urlString: url.absoluteString, region: region, bucket: bucket, headers: headers, payload: .none)
- return try make(request: url, method: .GET, headers: awsHeaders, data: emptyData(), on: container).map(to: BucketResults.self) { response in
+
+ let awsHeaders: HTTPHeaders
+
+ do {
+ var headers = headers
+ headers["host"] = host
+ awsHeaders = try signer.headers(for: .GET, urlString: url.absoluteString, region: region, bucket: bucket, headers: headers, payload: .none)
+ } catch let error {
+ return eventLoop.future(error: error)
+ }
+
+ return make(request: url, method: .GET, headers: awsHeaders, data: emptyData(), on: eventLoop).flatMapThrowing { response in
try self.check(response)
return try response.decode(to: BucketResults.self)
}
}
/// Get list of objects
- public func list(bucket: String, region: Region? = nil, on container: Container) throws -> Future {
- return try list(bucket: bucket, region: region, headers: [:], on: container)
+ public func list(bucket: String, region: Region? = nil, on eventLoop: EventLoop) -> EventLoopFuture {
+ return list(bucket: bucket, region: region, headers: [:], on: eventLoop)
}
}
diff --git a/Sources/S3/Extensions/S3+Move.swift b/Sources/S3/Extensions/S3+Move.swift
index de67935..0fbaaf3 100644
--- a/Sources/S3/Extensions/S3+Move.swift
+++ b/Sources/S3/Extensions/S3+Move.swift
@@ -14,11 +14,9 @@ extension S3 {
// MARK: Move
/// Copy file on S3
- public func move(file: LocationConvertible, to destination: LocationConvertible, headers: [String: String], on container: Container) throws -> EventLoopFuture {
- return try copy(file: file, to: destination, headers: headers, on: container).flatMap(to: File.CopyResponse.self) { copyResult in
- return try self.delete(file: file, on: container).map(to: File.CopyResponse.self) { _ in
- return copyResult
- }
+ public func move(file: LocationConvertible, to destination: LocationConvertible, headers: [String: String], on eventLoop: EventLoop) -> EventLoopFuture {
+ return copy(file: file, to: destination, headers: headers, on: eventLoop).flatMap { copyResult in
+ return self.delete(file: file, on: eventLoop).transform(to: copyResult)
}
}
diff --git a/Sources/S3/Extensions/S3+ObjectInfo.swift b/Sources/S3/Extensions/S3+ObjectInfo.swift
index 9cfd05b..ad677d6 100644
--- a/Sources/S3/Extensions/S3+ObjectInfo.swift
+++ b/Sources/S3/Extensions/S3+ObjectInfo.swift
@@ -17,37 +17,43 @@ extension S3 {
/// Get acl file information (ACL)
/// https://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectGETacl.html
- public func get(acl file: LocationConvertible, headers: [String: String], on container: Container) throws -> Future {
+ public func get(acl file: LocationConvertible, headers: [String: String], on eventLoop: EventLoop) -> EventLoopFuture {
fatalError("Not implemented")
}
/// Get acl file information
/// https://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectGETacl.html
- func get(acl file: LocationConvertible, on container: Container) throws -> Future {
- return try get(fileInfo: file, headers: [:], on: container)
+ func get(acl file: LocationConvertible, on eventLoop: EventLoop) -> EventLoopFuture {
+ return get(fileInfo: file, headers: [:], on: eventLoop)
}
/// Get file information (HEAD)
/// https://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectHEAD.html
- public func get(fileInfo file: LocationConvertible, headers: [String: String], on container: Container) throws -> Future {
- let builder = urlBuilder(for: container)
- let url = try builder.url(file: file)
-
- let headers = try signer.headers(for: .HEAD, urlString: url.absoluteString, headers: headers, payload: .none)
- return try make(request: url, method: .HEAD, headers: headers, data: emptyData(), on: container).map(to: File.Info.self) { response in
+ public func get(fileInfo file: LocationConvertible, headers strHeaders: [String: String], on eventLoop: EventLoop) -> EventLoopFuture {
+ let url: URL
+ let headers: HTTPHeaders
+
+ do {
+ url = try makeURLBuilder().url(file: file)
+ headers = try signer.headers(for: .HEAD, urlString: url.absoluteString, headers: strHeaders, payload: .none)
+ } catch let error {
+ return eventLoop.future(error: error)
+ }
+
+ return make(request: url, method: .HEAD, headers: headers, data: emptyData(), on: eventLoop).flatMapThrowing { response in
try self.check(response)
let bucket = file.bucket ?? self.defaultBucket
let region = file.region ?? self.signer.config.region
- let mime = response.http.headers.string(File.Info.CodingKeys.mime.rawValue)
- let size = response.http.headers.int(File.Info.CodingKeys.size.rawValue)
- let server = response.http.headers.string(File.Info.CodingKeys.server.rawValue)
- let etag = response.http.headers.string(File.Info.CodingKeys.etag.rawValue)
- let expiration = response.http.headers.date(File.Info.CodingKeys.expiration.rawValue)
- let created = response.http.headers.date(File.Info.CodingKeys.created.rawValue)
- let modified = response.http.headers.date(File.Info.CodingKeys.modified.rawValue)
- let versionId = response.http.headers.string(File.Info.CodingKeys.versionId.rawValue)
- let storageClass = response.http.headers.string(File.Info.CodingKeys.storageClass.rawValue)
+ let mime = response.headers.string(File.Info.CodingKeys.mime.rawValue)
+ let size = response.headers.int(File.Info.CodingKeys.size.rawValue)
+ let server = response.headers.string(File.Info.CodingKeys.server.rawValue)
+ let etag = response.headers.string(File.Info.CodingKeys.etag.rawValue)
+ let expiration = response.headers.date(File.Info.CodingKeys.expiration.rawValue)
+ let created = response.headers.date(File.Info.CodingKeys.created.rawValue)
+ let modified = response.headers.date(File.Info.CodingKeys.modified.rawValue)
+ let versionId = response.headers.string(File.Info.CodingKeys.versionId.rawValue)
+ let storageClass = response.headers.string(File.Info.CodingKeys.storageClass.rawValue)
let info = File.Info(bucket: bucket, region: region, path: file.path, access: .authenticatedRead, mime: mime, size: size, server: server, etag: etag, expiration: expiration, created: created, modified: modified, versionId: versionId, storageClass: storageClass)
return info
@@ -56,8 +62,8 @@ extension S3 {
/// Get file information (HEAD)
/// https://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectHEAD.html
- public func get(fileInfo file: LocationConvertible, on container: Container) throws -> Future {
- return try get(fileInfo: file, headers: [:], on: container)
+ public func get(fileInfo file: LocationConvertible, on eventLoop: EventLoop) -> EventLoopFuture {
+ return get(fileInfo: file, headers: [:], on: eventLoop)
}
}
diff --git a/Sources/S3/Extensions/S3+Private.swift b/Sources/S3/Extensions/S3+Private.swift
index deaafde..201685d 100644
--- a/Sources/S3/Extensions/S3+Private.swift
+++ b/Sources/S3/Extensions/S3+Private.swift
@@ -7,12 +7,11 @@
import Foundation
import Vapor
-import HTTP
extension S3 {
/// Make an S3 request
- func make(request url: URL, method: HTTPMethod, headers: HTTPHeaders, data: Data? = nil, cachePolicy: URLRequest.CachePolicy = .useProtocolCachePolicy, on container: Container) throws -> Future {
+ func make(request url: URL, method: HTTPMethod, headers: HTTPHeaders, data: Data? = nil, cachePolicy: URLRequest.CachePolicy = .useProtocolCachePolicy, on eventLoop: EventLoop) -> EventLoopFuture {
var request = URLRequest(url: url, cachePolicy: cachePolicy)
request.httpMethod = method.string
request.httpBody = data
@@ -20,38 +19,50 @@ extension S3 {
request.addValue(val, forHTTPHeaderField: key.description)
}
- return execute(request, on: container)
+ return execute(request, on: eventLoop)
}
-
+
+ func execute(_ request: ClientRequest, on eventLoop: EventLoop) -> EventLoopFuture {
+ guard let url = URL(string: request.url.string) else {
+ return eventLoop.future(error: Abort(.internalServerError, reason: "Found an invalid URL"))
+ }
+
+ var urlRequest = URLRequest(url: url, cachePolicy: .useProtocolCachePolicy)
+ urlRequest.httpMethod = request.method.rawValue
+ urlRequest.httpBody = Data(request.body!.readableBytesView)
+ request.headers.forEach { key, value in
+ urlRequest.addValue(value, forHTTPHeaderField: key)
+ }
+
+ return self.execute(urlRequest, on: eventLoop)
+ }
+
/// Execute given request with URLSession.shared
- func execute(_ request: URLRequest, on container: Container) -> Future {
- let promise = container.eventLoop.newPromise(Response.self)
+ func execute(_ request: URLRequest, on eventLoop: EventLoop) -> EventLoopFuture {
+ let promise = eventLoop.makePromise(of: Response.self)
URLSession.shared.dataTask(with: request, completionHandler: { (data, urlResponse, error) in
if let error = error {
- promise.fail(error: error)
+ promise.fail(error)
return
}
guard let httpResponse = urlResponse as? HTTPURLResponse else {
- let error = VaporError(identifier: "httpURLResponse", reason: "URLResponse was not a HTTPURLResponse.")
- promise.fail(error: error)
+ promise.fail(Abort(.internalServerError, reason: "URLResponse was not a HTTPURLResponse."))
return
}
- let response = S3.convert(foundationResponse: httpResponse, data: data, on: container)
-
- promise.succeed(result: Response(http: response, using: container))
+ promise.succeed(S3.convert(foundationResponse: httpResponse, data: data))
}).resume()
return promise.futureResult
}
-
+
/// Convert given response and data to HTTPResponse from Vapors HTTP package
- static func convert(foundationResponse httpResponse: HTTPURLResponse, data: Data?, on worker: Worker) -> HTTPResponse {
- var response = HTTPResponse(status: .init(statusCode: httpResponse.statusCode))
+ static func convert(foundationResponse httpResponse: HTTPURLResponse, data: Data?) -> Response {
+ let response = Response(status: .init(statusCode: httpResponse.statusCode))
if let data = data {
- response.body = HTTPBody(data: data)
+ response.body = Response.Body(data: data)
}
for (key, value) in httpResponse.allHeaderFields {
response.headers.replaceOrAdd(name: "\(key)", value: "\(value)")
diff --git a/Sources/S3/Extensions/S3+Put.swift b/Sources/S3/Extensions/S3+Put.swift
index 6fa4641..d9c9ef0 100755
--- a/Sources/S3/Extensions/S3+Put.swift
+++ b/Sources/S3/Extensions/S3+Put.swift
@@ -16,24 +16,31 @@ extension S3 {
// MARK: Upload
/// Upload file to S3
- public func put(file: File.Upload, headers: [String: String], on container: Container) throws -> EventLoopFuture {
- let builder = urlBuilder(for: container)
- let url = try builder.url(file: file)
-
-// let url = URL(string: "https://s3.eu-west-2.amazonaws.com/s3-liveui-test/file-hu.txt")!
-
- var awsHeaders: [String: String] = headers
- awsHeaders["content-type"] = file.mime.description
- awsHeaders["x-amz-acl"] = file.access.rawValue
- let headers = try signer.headers(for: .PUT, urlString: url.absoluteString, headers: awsHeaders, payload: Payload.bytes(file.data))
-
- let request = Request(using: container)
- request.http.method = .PUT
- request.http.headers = headers
- request.http.body = HTTPBody(data: file.data)
- request.http.url = url
- let client = try container.make(Client.self)
- return client.send(request).map(to: File.Response.self) { response in
+ public func put(file: File.Upload, headers strHeaders: [String: String], on eventLoop: EventLoop) -> EventLoopFuture {
+ let headers: HTTPHeaders
+ let url: URL
+
+ do {
+ url = try makeURLBuilder().url(file: file)
+
+ var awsHeaders: [String: String] = strHeaders
+ awsHeaders["content-type"] = file.mime.description
+ awsHeaders["x-amz-acl"] = file.access.rawValue
+ headers = try signer.headers(for: .PUT, urlString: url.absoluteString, headers: awsHeaders, payload: .bytes(file.data))
+ } catch let error {
+ return eventLoop.future(error: error)
+ }
+
+ var buffer = ByteBufferAllocator().buffer(capacity: file.data.count)
+ buffer.writeBytes(file.data)
+
+ var request = ClientRequest()
+ request.method = .PUT
+ request.headers = headers
+ request.body = buffer
+ request.url = URI(string: url.description)
+
+ return self.execute(request, on: eventLoop).flatMapThrowing { response in
try self.check(response)
let res = File.Response(data: file.data, bucket: file.bucket ?? self.defaultBucket, path: file.path, access: file.access, mime: file.mime)
return res
@@ -41,34 +48,46 @@ extension S3 {
}
/// Upload file to S3
- public func put(file: File.Upload, on container: Container) throws -> EventLoopFuture {
- return try put(file: file, headers: [:], on: container)
+ public func put(file: File.Upload, on eventLoop: EventLoop) -> EventLoopFuture {
+ return put(file: file, headers: [:], on: eventLoop)
}
/// Upload file by it's URL to S3
- public func put(file url: URL, destination: String, access: AccessControlList = .privateAccess, on container: Container) throws -> Future {
- let data: Data = try Data(contentsOf: url)
+ public func put(file url: URL, destination: String, access: AccessControlList = .privateAccess, on eventLoop: EventLoop) -> EventLoopFuture {
+ let data: Data
+ do {
+ data = try Data(contentsOf: url)
+ } catch let error {
+ return eventLoop.future(error: error)
+ }
+
let file = File.Upload(data: data, bucket: nil, destination: destination, access: access, mime: mimeType(forFileAtUrl: url))
- return try put(file: file, on: container)
+ return put(file: file, on: eventLoop)
}
/// Upload file by it's path to S3
- public func put(file path: String, destination: String, access: AccessControlList = .privateAccess, on container: Container) throws -> Future {
+ public func put(file path: String, destination: String, access: AccessControlList = .privateAccess, on eventLoop: EventLoop) -> EventLoopFuture {
let url: URL = URL(fileURLWithPath: path)
- return try put(file: url, destination: destination, bucket: nil, access: access, on: container)
+ return put(file: url, destination: destination, bucket: nil, access: access, on: eventLoop)
}
/// Upload file by it's URL to S3, full set
- public func put(file url: URL, destination: String, bucket: String?, access: AccessControlList = .privateAccess, on container: Container) throws -> Future {
- let data: Data = try Data(contentsOf: url)
+ public func put(file url: URL, destination: String, bucket: String?, access: AccessControlList = .privateAccess, on eventLoop: EventLoop) -> EventLoopFuture {
+ let data: Data
+ do {
+ data = try Data(contentsOf: url)
+ } catch let error {
+ return eventLoop.future(error: error)
+ }
+
let file = File.Upload(data: data, bucket: bucket, destination: destination, access: access, mime: mimeType(forFileAtUrl: url))
- return try put(file: file, on: container)
+ return put(file: file, on: eventLoop)
}
/// Upload file by it's path to S3, full set
- public func put(file path: String, destination: String, bucket: String?, access: AccessControlList = .privateAccess, on container: Container) throws -> Future {
+ public func put(file path: String, destination: String, bucket: String?, access: AccessControlList = .privateAccess, on eventLoop: EventLoop) -> EventLoopFuture {
let url: URL = URL(fileURLWithPath: path)
- return try put(file: url, destination: destination, bucket: bucket, access: access, on: container)
+ return put(file: url, destination: destination, bucket: bucket, access: access, on: eventLoop)
}
}
diff --git a/Sources/S3/Extensions/S3+Service.swift b/Sources/S3/Extensions/S3+Service.swift
index 634c99b..7578db9 100644
--- a/Sources/S3/Extensions/S3+Service.swift
+++ b/Sources/S3/Extensions/S3+Service.swift
@@ -16,11 +16,18 @@ extension S3 {
// MARK: Buckets
/// Get list of buckets
- public func buckets(on container: Container) throws -> Future {
- let builder = urlBuilder(for: container)
- let url = try builder.plain(region: nil)
- let headers = try signer.headers(for: .GET, urlString: url.absoluteString, payload: .none)
- return try make(request: url, method: .GET, headers: headers, data: emptyData(), on: container).map(to: BucketsInfo.self) { response in
+ public func buckets(on eventLoop: EventLoop) -> EventLoopFuture {
+ let headers: HTTPHeaders
+ let url: URL
+
+ do {
+ url = try makeURLBuilder().plain(region: nil)
+ headers = try signer.headers(for: .GET, urlString: url.absoluteString, payload: .none)
+ } catch let error {
+ return eventLoop.future(error: error)
+ }
+
+ return make(request: url, method: .GET, headers: headers, data: emptyData(), on: eventLoop).flatMapThrowing { response in
try self.check(response)
return try response.decode(to: BucketsInfo.self)
}
diff --git a/Sources/S3/Extensions/S3+Strings.swift b/Sources/S3/Extensions/S3+Strings.swift
index 4c69440..3eb0a1c 100755
--- a/Sources/S3/Extensions/S3+Strings.swift
+++ b/Sources/S3/Extensions/S3+Strings.swift
@@ -13,32 +13,32 @@ import Vapor
extension S3 {
/// Upload file content to S3, full set
- public func put(string: String, mime: MediaType, destination: String, bucket: String?, access: AccessControlList, on container: Container) throws -> Future {
+ public func put(string: String, mime: HTTPMediaType, destination: String, bucket: String?, access: AccessControlList, on eventLoop: EventLoop) -> EventLoopFuture {
guard let data: Data = string.data(using: String.Encoding.utf8) else {
- throw Error.badStringData
+ return eventLoop.future(error: Error.badStringData)
}
let file = File.Upload(data: data, bucket: bucket, destination: destination, access: access, mime: mime.description)
- return try put(file: file, on: container)
+ return put(file: file, on: eventLoop)
}
/// Upload file content to S3
- public func put(string: String, mime: MediaType, destination: String, access: AccessControlList, on container: Container) throws -> Future {
- return try put(string: string, mime: mime, destination: destination, bucket: nil, access: access, on: container)
+ public func put(string: String, mime: HTTPMediaType, destination: String, access: AccessControlList, on eventLoop: EventLoop) -> EventLoopFuture {
+ return put(string: string, mime: mime, destination: destination, bucket: nil, access: access, on: eventLoop)
}
/// Upload file content to S3
- public func put(string: String, destination: String, access: AccessControlList, on container: Container) throws -> Future {
- return try put(string: string, mime: .plainText, destination: destination, bucket: nil, access: access, on: container)
+ public func put(string: String, destination: String, access: AccessControlList, on eventLoop: EventLoop) -> EventLoopFuture {
+ return put(string: string, mime: .plainText, destination: destination, bucket: nil, access: access, on: eventLoop)
}
/// Upload file content to S3
- public func put(string: String, mime: MediaType, destination: String, on container: Container) throws -> Future {
- return try put(string: string, mime: mime, destination: destination, access: .privateAccess, on: container)
+ public func put(string: String, mime: HTTPMediaType, destination: String, on eventLoop: EventLoop) -> EventLoopFuture {
+ return put(string: string, mime: mime, destination: destination, access: .privateAccess, on: eventLoop)
}
/// Upload file content to S3
- public func put(string: String, destination: String, on container: Container) throws -> Future {
- return try put(string: string, mime: .plainText, destination: destination, bucket: nil, access: .privateAccess, on: container)
+ public func put(string: String, destination: String, on eventLoop: EventLoop) -> EventLoopFuture {
+ return put(string: string, mime: .plainText, destination: destination, bucket: nil, access: .privateAccess, on: eventLoop)
}
}
diff --git a/Sources/S3/Extensions/Service+S3.swift b/Sources/S3/Extensions/Service+S3.swift
index c99efa6..2a33eef 100644
--- a/Sources/S3/Extensions/Service+S3.swift
+++ b/Sources/S3/Extensions/Service+S3.swift
@@ -5,10 +5,9 @@
// Created by Ondrej Rafaj on 19/04/2018.
//
-import Foundation
-import Service
@_exported import S3Signer
-
+import Foundation
+import Vapor
extension Services {
diff --git a/Sources/S3/Models/File.swift b/Sources/S3/Models/File.swift
index ed7e1b1..312a798 100644
--- a/Sources/S3/Models/File.swift
+++ b/Sources/S3/Models/File.swift
@@ -36,7 +36,7 @@ public struct File {
// MARK: Initialization
/// File data to be uploaded
- public init(data: Data, bucket: String? = nil, destination: String, access: AccessControlList = .privateAccess, mime: String = MediaType.plainText.description) {
+ public init(data: Data, bucket: String? = nil, destination: String, access: AccessControlList = .privateAccess, mime: String = HTTPMediaType.plainText.description) {
self.data = data
self.bucket = bucket
self.path = destination
diff --git a/Sources/S3/Protocols/S3Client.swift b/Sources/S3/Protocols/S3Client.swift
index 0d61637..fd146d2 100644
--- a/Sources/S3/Protocols/S3Client.swift
+++ b/Sources/S3/Protocols/S3Client.swift
@@ -10,92 +10,92 @@ import Vapor
/// S3 client Protocol
-public protocol S3Client: Service {
+public protocol S3Client {
/// Get list of objects
- func buckets(on: Container) throws -> Future
+ func buckets(on eventLoop: EventLoop) -> EventLoopFuture
/// Create a bucket
- func create(bucket: String, region: Region?, on container: Container) throws -> Future
+ func create(bucket: String, region: Region?, on eventLoop: EventLoop) -> EventLoopFuture
/// Delete a bucket wherever it is
-// func delete(bucket: String, on container: Container) throws -> Future
+// func delete(bucket: String, on container: Container) -> EventLoopFuture
/// Delete a bucket
- func delete(bucket: String, region: Region?, on container: Container) throws -> Future
+ func delete(bucket: String, region: Region?, on eventLoop: EventLoop) -> EventLoopFuture
/// Get bucket location
- func location(bucket: String, on container: Container) throws -> Future
+ func location(bucket: String, on eventLoop: EventLoop) -> EventLoopFuture
/// Get list of objects
- func list(bucket: String, region: Region?, on container: Container) throws -> Future
+ func list(bucket: String, region: Region?, on eventLoop: EventLoop) -> EventLoopFuture
/// Get list of objects
- func list(bucket: String, region: Region?, headers: [String: String], on container: Container) throws -> Future
+ func list(bucket: String, region: Region?, headers: [String: String], on eventLoop: EventLoop) -> EventLoopFuture
/// Upload file to S3
- func put(file: File.Upload, on container: Container) throws -> EventLoopFuture
+ func put(file: File.Upload, on eventLoop: EventLoop) -> EventLoopFuture
/// Upload file to S3
- func put(file: File.Upload, headers: [String: String], on: Container) throws -> EventLoopFuture
+ func put(file: File.Upload, headers: [String: String], on eventLoop: EventLoop) -> EventLoopFuture
/// Upload file to S3
- func put(file url: URL, destination: String, access: AccessControlList, on: Container) throws -> Future
+ func put(file url: URL, destination: String, access: AccessControlList, on eventLoop: EventLoop) -> EventLoopFuture
/// Upload file to S3
- func put(file url: URL, destination: String, bucket: String?, access: AccessControlList, on: Container) throws -> Future
+ func put(file url: URL, destination: String, bucket: String?, access: AccessControlList, on eventLoop: EventLoop) -> EventLoopFuture
/// Upload file to S3
- func put(file path: String, destination: String, access: AccessControlList, on: Container) throws -> Future
+ func put(file path: String, destination: String, access: AccessControlList, on eventLoop: EventLoop) -> EventLoopFuture
/// Upload file to S3
- func put(file path: String, destination: String, bucket: String?, access: AccessControlList, on: Container) throws -> Future
+ func put(file path: String, destination: String, bucket: String?, access: AccessControlList, on eventLoop: EventLoop) -> EventLoopFuture
/// Upload file to S3
- func put(string: String, destination: String, on: Container) throws -> Future
+ func put(string: String, destination: String, on eventLoop: EventLoop) -> EventLoopFuture
/// Upload file to S3
- func put(string: String, destination: String, access: AccessControlList, on: Container) throws -> Future
+ func put(string: String, destination: String, access: AccessControlList, on eventLoop: EventLoop) -> EventLoopFuture
/// Upload file to S3
- func put(string: String, mime: MediaType, destination: String, on: Container) throws -> Future
+ func put(string: String, mime: HTTPMediaType, destination: String, on eventLoop: EventLoop) -> EventLoopFuture
/// Upload file to S3
- func put(string: String, mime: MediaType, destination: String, access: AccessControlList, on: Container) throws -> Future
+ func put(string: String, mime: HTTPMediaType, destination: String, access: AccessControlList, on eventLoop: EventLoop) -> EventLoopFuture
/// Upload file to S3
- func put(string: String, mime: MediaType, destination: String, bucket: String?, access: AccessControlList, on: Container) throws -> Future
+ func put(string: String, mime: HTTPMediaType, destination: String, bucket: String?, access: AccessControlList, on eventLoop: EventLoop) -> EventLoopFuture
/// File URL
- func url(fileInfo file: LocationConvertible, on container: Container) throws -> URL
+ func url(fileInfo file: LocationConvertible) throws -> URL
/// Retrieve file data from S3
- func get(fileInfo file: LocationConvertible, on container: Container) throws -> Future
+ func get(fileInfo file: LocationConvertible, on eventLoop: EventLoop) -> EventLoopFuture
/// Retrieve file data from S3
- func get(fileInfo file: LocationConvertible, headers: [String: String], on container: Container) throws -> Future
+ func get(fileInfo file: LocationConvertible, headers: [String: String], on eventLoop: EventLoop) -> EventLoopFuture
/// Retrieve file data from S3
- func get(file: LocationConvertible, on: Container) throws -> Future
+ func get(file: LocationConvertible, on eventLoop: EventLoop) -> EventLoopFuture
/// Retrieve file data from S3
- func get(file: LocationConvertible, headers: [String: String], on: Container) throws -> Future
+ func get(file: LocationConvertible, headers: [String: String], on eventLoop: EventLoop) -> EventLoopFuture
/// Delete file from S3
- func delete(file: LocationConvertible, on: Container) throws -> Future
+ func delete(file: LocationConvertible, on eventLoop: EventLoop) -> EventLoopFuture
/// Delete file from S3
- func delete(file: LocationConvertible, headers: [String: String], on: Container) throws -> Future
+ func delete(file: LocationConvertible, headers: [String: String], on eventLoop: EventLoop) -> EventLoopFuture
/// Copy file on S3
- func copy(file: LocationConvertible, to: LocationConvertible, headers: [String: String], on: Container) throws -> Future
+ func copy(file: LocationConvertible, to: LocationConvertible, headers: [String: String], on eventLoop: EventLoop) -> EventLoopFuture
}
extension S3Client {
/// Copy file on S3
- public func copy(file: LocationConvertible, to: LocationConvertible, on container: Container) throws -> Future {
- return try self.copy(file: file, to: to, headers: [:], on: container)
+ public func copy(file: LocationConvertible, to: LocationConvertible, on eventLoop: EventLoop) -> EventLoopFuture {
+ return self.copy(file: file, to: to, headers: [:], on: eventLoop)
}
}
diff --git a/Sources/S3/S3.swift b/Sources/S3/S3.swift
index 9a27f83..43f8d74 100755
--- a/Sources/S3/S3.swift
+++ b/Sources/S3/S3.swift
@@ -6,11 +6,9 @@
// Copyright © 2016 manGoweb UK Ltd. All rights reserved.
//
+@_exported import S3Signer
import Foundation
import Vapor
-import HTTP
-@_exported import S3Signer
-
/// Main S3 class
public class S3: S3Client {
@@ -19,6 +17,7 @@ public class S3: S3Client {
public enum Error: Swift.Error {
case invalidUrl
case errorResponse(HTTPResponseStatus, ErrorMessage)
+ case badClientResponse(ClientResponse)
case badResponse(Response)
case badStringData
case missingData
@@ -40,9 +39,9 @@ public class S3: S3Client {
@discardableResult public convenience init(defaultBucket: String, config: S3Signer.Config, services: inout Services) throws {
let signer = try S3Signer(config)
try self.init(defaultBucket: defaultBucket, signer: signer)
-
- services.register(signer)
- services.register(self, as: S3Client.self)
+
+ services.instance(signer)
+ services.instance(S3Client.self, self)
}
/// Basic initialization method
@@ -68,25 +67,37 @@ extension S3 {
// QUESTION: Can we replace this with just Data()?
/// Serve empty data
func emptyData() -> Data {
- return "".convertToData()
+ return Data("".utf8)
}
/// Check response for error
@discardableResult func check(_ response: Response) throws -> Response {
- guard response.http.status == .ok || response.http.status == .noContent else {
+ guard response.status == .ok || response.status == .noContent else {
if let error = try? response.decode(to: ErrorMessage.self) {
- throw Error.errorResponse(response.http.status, error)
+ throw Error.errorResponse(response.status, error)
} else {
throw Error.badResponse(response)
}
}
return response
}
+
+ /// Check response for error
+ @discardableResult func check(_ response: ClientResponse) throws -> ClientResponse {
+ guard response.status == .ok || response.status == .noContent else {
+ if let error = try? response.content.decode(ErrorMessage.self) {
+ throw Error.errorResponse(response.status, error)
+ } else {
+ throw Error.badClientResponse(response)
+ }
+ }
+ return response
+ }
/// Get mime type for file
static func mimeType(forFileAtUrl url: URL) -> String {
- guard let mediaType = MediaType.fileExtension(url.pathExtension) else {
- return MediaType(type: "application", subType: "octet-stream").description
+ guard let mediaType = HTTPMediaType.fileExtension(url.pathExtension) else {
+ return HTTPMediaType(type: "application", subType: "octet-stream").description
}
return mediaType.description
}
@@ -97,8 +108,8 @@ extension S3 {
}
/// Create URL builder
- func urlBuilder(for container: Container) -> URLBuilder {
- return urlBuilder ?? S3URLBuilder(container, defaultBucket: defaultBucket, config: signer.config)
+ func makeURLBuilder() -> URLBuilder {
+ return urlBuilder ?? S3URLBuilder(defaultBucket: defaultBucket, config: signer.config)
}
}
diff --git a/Sources/S3/URLBuilder/S3URLBuilder.swift b/Sources/S3/URLBuilder/S3URLBuilder.swift
index 9fcbf1d..4e3bcbc 100644
--- a/Sources/S3/URLBuilder/S3URLBuilder.swift
+++ b/Sources/S3/URLBuilder/S3URLBuilder.swift
@@ -13,9 +13,6 @@ import S3Signer
/// URL builder
public final class S3URLBuilder: URLBuilder {
- /// Container
- let container: Container
-
/// Default bucket
let defaultBucket: String
@@ -23,8 +20,7 @@ public final class S3URLBuilder: URLBuilder {
let config: S3Signer.Config
/// Initializer
- public init(_ container: Container, defaultBucket: String, config: S3Signer.Config) {
- self.container = container
+ public init(defaultBucket: String, config: S3Signer.Config) {
self.defaultBucket = defaultBucket
self.config = config
}
diff --git a/Sources/S3/URLBuilder/URLBuilder.swift b/Sources/S3/URLBuilder/URLBuilder.swift
index da5e206..c474a83 100644
--- a/Sources/S3/URLBuilder/URLBuilder.swift
+++ b/Sources/S3/URLBuilder/URLBuilder.swift
@@ -31,7 +31,7 @@ extension Region {
public protocol URLBuilder {
/// Initializer
- init(_ container: Container, defaultBucket: String, config: S3Signer.Config)
+ init(defaultBucket: String, config: S3Signer.Config)
/// Plain Base URL with no bucket specified
/// *Format: https://s3.eu-west-2.amazonaws.com/
diff --git a/Sources/S3DemoApp/S3DemoApp.swift b/Sources/S3DemoApp/S3DemoApp.swift
index 0d78d6c..140c402 100644
--- a/Sources/S3DemoApp/S3DemoApp.swift
+++ b/Sources/S3DemoApp/S3DemoApp.swift
@@ -3,122 +3,109 @@ import Vapor
@testable import S3
-public func routes(_ router: Router) throws {
+public func routes(_ router: RoutesBuilder, s3: S3Client) throws {
// Get all available buckets
- router.get("buckets") { req -> Future in
- let s3 = try req.makeS3Client()
- return try s3.buckets(on: req)
+ router.get("buckets") { req -> EventLoopFuture in
+ return s3.buckets(on: req.eventLoop)
}
// Create new bucket
- router.put("bucket") { req -> Future in
- let s3 = try req.makeS3Client()
- return try s3.create(bucket: "api-created-bucket", region: .euCentral1, on: req).map(to: String.self) {
+ router.put("bucket") { req -> EventLoopFuture in
+ return s3.create(bucket: "api-created-bucket", region: .euCentral1, on: req.eventLoop).map {
return ":)"
- }.catchMap({ (error) -> (String) in
- if let error = error.s3ErrorMessage() {
- return error.message
- }
- return ":("
+ }.recover { error in
+ if let error = error.s3ErrorMessage() {
+ return error.message
}
- )
+ return ":("
+ }
}
// Delete bucket
- router.delete("bucket") { req -> Future in
- let s3 = try req.makeS3Client()
- return try s3.delete(bucket: "api-created-bucket", region: .euCentral1, on: req).map(to: String.self) {
+ router.delete("bucket") { req -> EventLoopFuture in
+ return s3.delete(bucket: "api-created-bucket", region: .euCentral1, on: req.eventLoop).map {
return ":)"
- }.catchMap({ (error) -> (String) in
- if let error = error.s3ErrorMessage() {
- return error.message
- }
- return ":("
- }
- )
+ }.recover { error in
+ if let error = error.s3ErrorMessage() {
+ return error.message
+ }
+ return ":("
+ }
}
// Delete bucket
- router.get("files") { req -> Future in
- let s3 = try req.makeS3Client()
- return try s3.list(bucket: "booststore", region: .usEast1, headers: [:], on: req).catchMap({ (error) -> (BucketResults) in
+ router.get("files") { req -> EventLoopFuture in
+ return s3.list(bucket: "booststore", region: .usEast1, headers: [:], on: req.eventLoop).flatMapErrorThrowing { error in
if let error = error.s3ErrorMessage() {
print(error.message)
}
+
throw error
- })
+ }
}
// Bucket location
- router.get("bucket/location") { req -> Future in
- let s3 = try req.makeS3Client()
- return try s3.location(bucket: "adfasdfasdfasdf", on: req).map(to: String.self) { region in
+ router.get("bucket/location") { req -> EventLoopFuture in
+ return s3.location(bucket: "adfasdfasdfasdf", on: req.eventLoop).map { region in
return region.hostUrlString()
- }.catchMap({ (error) -> (String) in
- if let error = error as? S3.Error {
- switch error {
- case .errorResponse(_, let error):
- return error.message
- default:
- return "S3 :("
- }
+ }.recover { error -> String in
+ if let error = error as? S3.Error {
+ switch error {
+ case .errorResponse(_, let error):
+ return error.message
+ default:
+ return "S3 :("
}
- return ":("
}
- )
+ return ":("
+ }
}
// Demonstrate work with files
- router.get("files/test") { req -> Future in
+ router.get("files/test") { req -> EventLoopFuture in
let string = "Content of my example file"
let fileName = "file-hu.txt"
-
- let s3 = try req.makeS3Client()
- do {
- return try s3.put(string: string, destination: fileName, access: .publicRead, on: req).flatMap(to: String.self) { putResponse in
- print("PUT response:")
- print(putResponse)
- return try s3.get(file: fileName, on: req).flatMap(to: String.self) { getResponse in
- print("GET response:")
- print(getResponse)
- print(String(data: getResponse.data, encoding: .utf8) ?? "Unknown content!")
- return try s3.get(fileInfo: fileName, on: req).flatMap(to: String.self) { infoResponse in
- print("HEAD/Info response:")
- print(infoResponse)
- return try s3.delete(file: fileName, on: req).map() { response in
- print("DELETE response:")
- print(response)
- let json = try JSONEncoder().encode(infoResponse)
- return String(data: json, encoding: .utf8) ?? "Unknown content!"
- }.catchMap({ error -> (String) in
- if let error = error.s3ErrorMessage() {
- return error.message
- }
- return ":("
- }
- )
+ return s3.put(string: string, destination: fileName, access: .publicRead, on: req.eventLoop).flatMap { putResponse -> EventLoopFuture in
+ print("PUT response:")
+ print(putResponse)
+ return s3.get(file: fileName, on: req.eventLoop).flatMap { getResponse in
+ print("GET response:")
+ print(getResponse)
+ print(String(data: getResponse.data, encoding: .utf8) ?? "Unknown content!")
+
+ return s3.get(fileInfo: fileName, on: req.eventLoop).flatMap { infoResponse in
+ print("HEAD/Info response:")
+ print(infoResponse)
+
+ return s3.delete(file: fileName, on: req.eventLoop).flatMapThrowing { response in
+ print("DELETE response:")
+ print(response)
+ let json = try JSONEncoder().encode(infoResponse)
+ return String(data: json, encoding: .utf8) ?? "Unknown content!"
+ }.recover { error -> (String) in
+ if let error = error.s3ErrorMessage() {
+ return error.message
+ }
+ return ":("
}
}
- }.catchMap({ error -> (String) in
- if let error = error.s3ErrorMessage() {
- return error.message
- }
- return ":("
- })
- } catch {
- print(error)
- fatalError()
+ }
+ }.recover { error -> (String) in
+ if let error = error.s3ErrorMessage() {
+ return error.message
+ }
+ return ":("
}
}
}
-public func configure(_ config: inout Config, _ env: inout Vapor.Environment, _ services: inout Services) throws {
- let router = EngineRouter.default()
- try routes(router)
- services.register(router, as: Router.self)
+public func configure(env: inout Vapor.Environment, _ services: inout Services) throws {
+ services.extend(RoutesBuilder.self) { router, container in
+ try routes(router, s3: container.makeS3Client())
+ }
// Get API key and secret from environmental variables
guard let key = Environment.get("S3_ACCESS_KEY"), let secret = Environment.get("S3_SECRET") else {
diff --git a/Sources/S3DemoRun/main.swift b/Sources/S3DemoRun/main.swift
index 36cd445..791108e 100644
--- a/Sources/S3DemoRun/main.swift
+++ b/Sources/S3DemoRun/main.swift
@@ -3,18 +3,11 @@ import Service
import Vapor
do {
- var config = Config.default()
- var env = try Environment.detect()
- var services = Services.default()
-
- try S3DemoApp.configure(&config, &env, &services)
-
- let app = try Application(
- config: config,
- environment: env,
- services: services
- )
-
+ var env: Vapor.Environment = .testing
+ let app = Application(environment: env, configure: { services in
+ try S3DemoApp.configure(env: &env, &services)
+ })
+
try app.run()
} catch {
print("Top-level failure: \(error)")
diff --git a/Sources/S3Signer/HTTPMethod+Description.swift b/Sources/S3Signer/HTTPMethod+Description.swift
index b645684..a736cb4 100755
--- a/Sources/S3Signer/HTTPMethod+Description.swift
+++ b/Sources/S3Signer/HTTPMethod+Description.swift
@@ -1,5 +1,5 @@
import Foundation
-import HTTP
+import NIOHTTP1
extension HTTPMethod {
@@ -38,6 +38,8 @@ extension HTTPMethod {
return "PURGE"
case .NOTIFY:
return "NOTIFY"
+ case .SOURCE:
+ return "SOURCE"
case .SEARCH:
return "SEARCH"
case .UNLOCK:
diff --git a/Sources/S3Signer/Payload.swift b/Sources/S3Signer/Payload.swift
index 72652fa..f43f5c3 100755
--- a/Sources/S3Signer/Payload.swift
+++ b/Sources/S3Signer/Payload.swift
@@ -1,5 +1,5 @@
import Vapor
-import Crypto
+import CryptoKit
/// Payload object
@@ -21,16 +21,16 @@ extension Payload {
case .bytes(let bytes):
return bytes
default:
- return "".convertToData()
+ return Data("".utf8)
}
}
func hashed() throws -> String {
switch self {
case .bytes(let bytes):
- return try SHA256.hash(bytes).hexEncodedString()
+ return try SHA256.hash(.data(bytes)).hexEncodedString()
case .none:
- return try SHA256.hash(Data()).hexEncodedString()
+ return try SHA256.hash(.data(Data())).hexEncodedString()
case .unsigned:
return "UNSIGNED-PAYLOAD"
}
diff --git a/Sources/S3Signer/S3Signer+Private.swift b/Sources/S3Signer/S3Signer+Private.swift
index 39c522f..e53e351 100755
--- a/Sources/S3Signer/S3Signer+Private.swift
+++ b/Sources/S3Signer/S3Signer+Private.swift
@@ -1,7 +1,6 @@
import Foundation
-import HTTP
-import Crypto
-
+import CryptoKit
+import Vapor
/// Private interface
@@ -50,16 +49,16 @@ extension S3Signer {
}
func createSignature(_ stringToSign: String, timeStampShort: String, region: Region) throws -> String {
- let dateKey = try HMAC.SHA256.authenticate(timeStampShort.convertToData(), key: "AWS4\(config.secretKey)".convertToData())
- let dateRegionKey = try HMAC.SHA256.authenticate(region.name.description.convertToData(), key: dateKey)
- let dateRegionServiceKey = try HMAC.SHA256.authenticate(config.service.convertToData(), key: dateRegionKey)
- let signingKey = try HMAC.SHA256.authenticate("aws4_request".convertToData(), key: dateRegionServiceKey)
- let signature = try HMAC.SHA256.authenticate(stringToSign.convertToData(), key: signingKey)
+ let dateKey = try HMAC.SHA256.authenticate(.string(timeStampShort), key: .string("AWS4\(config.secretKey)"))
+ let dateRegionKey = try HMAC.SHA256.authenticate(.string(region.name.description), key: dateKey)
+ let dateRegionServiceKey = try HMAC.SHA256.authenticate(.string(config.service), key: dateRegionKey)
+ let signingKey = try HMAC.SHA256.authenticate(.string("aws4_request"), key: dateRegionServiceKey)
+ let signature = try HMAC.SHA256.authenticate(.string(stringToSign), key: signingKey)
return signature.hexEncodedString()
}
func createStringToSign(_ canonicalRequest: String, dates: Dates, region: Region) throws -> String {
- let canonRequestHash = try SHA256.hash(canonicalRequest.convertToData()).hexEncodedString()
+ let canonRequestHash = try SHA256.hash(.string(canonicalRequest)).hexEncodedString()
return ["AWS4-HMAC-SHA256", dates.long, credentialScope(dates.short, region: region), canonRequestHash].joined(separator: "\n")
}
@@ -122,7 +121,7 @@ extension S3Signer {
let canonicalizedAmzHeaders = canonicalHeadersV2(headers)
let canonicalizedResource = canonicalResourceV2(url: url, region: region, bucket: bucket)
let stringToSign = "\(method)\n\(contentMD5)\n\(contentType)\n\(date)\n\(canonicalizedAmzHeaders)\n\(canonicalizedResource)"
- let signature = try HMAC.SHA1.authenticate(stringToSign.convertToData(), key: config.secretKey.convertToData()).base64EncodedString()
+ let signature = try Data(HMAC.SHA1.authenticate(.string(stringToSign), key: .string(config.secretKey)).bytes()).base64EncodedString()
let authHeader = "AWS \(config.accessKey):\(signature)"
return authHeader
}
@@ -217,8 +216,8 @@ extension S3Signer {
return presignedURL
}
- func headers(for httpMethod: HTTPMethod, urlString: URLRepresentable, region: Region? = nil, bucket: String? = nil, headers: [String: String] = [:], payload: Payload, dates: Dates) throws -> HTTPHeaders {
- guard let url = urlString.convertToURL() else {
+ func headers(for httpMethod: HTTPMethod, urlString: String, region: Region? = nil, bucket: String? = nil, headers: [String: String] = [:], payload: Payload, dates: Dates) throws -> HTTPHeaders {
+ guard let url = URL(string: urlString) else {
throw Error.badURL("\(urlString)")
}
@@ -227,13 +226,13 @@ extension S3Signer {
var updatedHeaders = update(headers: headers, url: url, longDate: dates.long, bodyDigest: bodyDigest, region: region)
if httpMethod == .PUT && payload.isBytes {
- updatedHeaders["content-md5"] = try MD5.hash(payload.bytes).base64EncodedString()
+ updatedHeaders["content-md5"] = try Data(MD5.hash(.data(payload.bytes)).bytes()).base64EncodedString()
}
-
+
if httpMethod == .PUT || httpMethod == .DELETE {
updatedHeaders["content-length"] = payload.size()
if httpMethod == .PUT && url.pathExtension != "" {
- updatedHeaders["content-type"] = (MediaType.fileExtension(url.pathExtension) ?? .plainText).description
+ updatedHeaders["content-type"] = (HTTPMediaType.fileExtension(url.pathExtension) ?? .plainText).description
}
}
diff --git a/Sources/S3Signer/S3Signer.swift b/Sources/S3Signer/S3Signer.swift
index 77180ce..66407cf 100755
--- a/Sources/S3Signer/S3Signer.swift
+++ b/Sources/S3Signer/S3Signer.swift
@@ -1,11 +1,10 @@
import Foundation
-import Service
-import HTTP
-import Crypto
+import CryptoKit
+import Vapor
/// S3 Client: All network calls to and from AWS' S3 servers
-public final class S3Signer: Service {
+public final class S3Signer {
/// Errors
public enum Error: Swift.Error {
@@ -21,7 +20,7 @@ public final class S3Signer: Service {
}
/// S3 Configuration
- public struct Config: Service {
+ public struct Config {
/// AWS authentication version
let authVersion: Version
@@ -65,7 +64,7 @@ public final class S3Signer: Service {
extension S3Signer {
/// Generates auth headers for Simple Storage Services
- public func headers(for httpMethod: HTTPMethod, urlString: URLRepresentable, region: Region? = nil, bucket: String? = nil, headers: [String: String] = [:], payload: Payload) throws -> HTTPHeaders {
+ public func headers(for httpMethod: HTTPMethod, urlString: String, region: Region? = nil, bucket: String? = nil, headers: [String: String] = [:], payload: Payload) throws -> HTTPHeaders {
return try self.headers(for: httpMethod, urlString: urlString, region: region, bucket: bucket, headers: headers, payload: payload, dates: Dates(Date()))
}
diff --git a/Sources/S3TestTools/Extensions/Services+S3Mock.swift b/Sources/S3TestTools/Extensions/Services+S3Mock.swift
index 1528205..3ccc6ec 100644
--- a/Sources/S3TestTools/Extensions/Services+S3Mock.swift
+++ b/Sources/S3TestTools/Extensions/Services+S3Mock.swift
@@ -6,15 +6,14 @@
//
import Foundation
-import Service
+import Vapor
import S3Signer
import S3
-extension Services {
-
+extension Vapor.Services {
public mutating func registerS3Mock() throws {
- register(try! S3Mock(), as: S3Client.self)
+ try self.instance(S3Client.self, S3Mock())
}
}