Skip to content

Commit

Permalink
Handle when response is a file URL. (#6469)
Browse files Browse the repository at this point in the history
This is the equivalent change in the swift4 module which was made in the swift3 module in this PR:

#6274

This updates AlamofireImplementations.mustache to handle when the response is an URL. It also makes changes in the generated sample code for:

* default configuration (no promisekit or rxswift)
* promisekit
* rxswift

Also, in order to build, the generated code needed to be updated with the change in CodableHelper which changes dataDecodingStrategy to ".base64" from its previous definition in earlier Xcode 9 betas.
*
  • Loading branch information
ehyche authored and wing328 committed Sep 12, 2017
1 parent d639b38 commit 8067612
Show file tree
Hide file tree
Showing 7 changed files with 446 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,56 @@ open class AlamofireRequestBuilder<T>: RequestBuilder<T> {
nil
)
})
case is URL.Type:
validatedRequest.responseData(completionHandler: { (dataResponse) in
cleanupRequest()
do {
guard !dataResponse.result.isFailure else {
throw DownloadException.responseFailed
}

guard let data = dataResponse.data else {
throw DownloadException.responseDataMissing
}

guard let request = request.request else {
throw DownloadException.requestMissing
}

let fileManager = FileManager.default
let urlRequest = try request.asURLRequest()
let documentsDirectory = fileManager.urls(for: .documentDirectory, in: .userDomainMask)[0]
let requestURL = try self.getURL(from: urlRequest)

var requestPath = try self.getPath(from: requestURL)

if let headerFileName = self.getFileName(fromContentDisposition: dataResponse.response?.allHeaderFields["Content-Disposition"] as? String) {
requestPath = requestPath.appending("/\(headerFileName)")
}

let filePath = documentsDirectory.appendingPathComponent(requestPath)
let directoryPath = filePath.deletingLastPathComponent().path

try fileManager.createDirectory(atPath: directoryPath, withIntermediateDirectories: true, attributes: nil)
try data.write(to: filePath, options: .atomic)

completion(
Response(
response: dataResponse.response!,
body: (filePath as! T)
),
nil
)

} catch let requestParserError as DownloadException {
completion(nil, ErrorResponse.Error(400, dataResponse.data, requestParserError))
} catch let error {
completion(nil, ErrorResponse.Error(400, dataResponse.data, error))
}
return
})
case is Void.Type:
validatedRequest.responseData(completionHandler: { (voidResponse) in
cleanupRequest()
Expand Down Expand Up @@ -191,6 +241,66 @@ open class AlamofireRequestBuilder<T>: RequestBuilder<T> {
}
return httpHeaders
}

fileprivate func getFileName(fromContentDisposition contentDisposition : String?) -> String? {
guard let contentDisposition = contentDisposition else {
return nil
}

let items = contentDisposition.components(separatedBy: ";")

var filename : String? = nil

for contentItem in items {
let filenameKey = "filename="
guard let range = contentItem.range(of: filenameKey) else {
break
}

filename = contentItem
return filename?
.replacingCharacters(in: range, with:"")
.replacingOccurrences(of: "\"", with: "")
.trimmingCharacters(in: .whitespacesAndNewlines)
}

return filename

}

fileprivate func getPath(from url : URL) throws -> String {
guard var path = NSURLComponents(url: url, resolvingAgainstBaseURL: true)?.path else {
throw DownloadException.requestMissingPath
}

if path.hasPrefix("/") {
path.remove(at: path.startIndex)
}

return path

}

fileprivate func getURL(from urlRequest : URLRequest) throws -> URL {
guard let url = urlRequest.url else {
throw DownloadException.requestMissingURL
}

return url
}

}

fileprivate enum DownloadException : Error {
case responseDataMissing
case responseFailed
case requestMissing
case requestMissingPath
case requestMissingURL
}

public enum AlamofireDecodableRequestBuilderError: Error {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,56 @@ open class AlamofireRequestBuilder<T>: RequestBuilder<T> {
nil
)
})
case is URL.Type:
validatedRequest.responseData(completionHandler: { (dataResponse) in
cleanupRequest()

do {

guard !dataResponse.result.isFailure else {
throw DownloadException.responseFailed
}

guard let data = dataResponse.data else {
throw DownloadException.responseDataMissing
}

guard let request = request.request else {
throw DownloadException.requestMissing
}

let fileManager = FileManager.default
let urlRequest = try request.asURLRequest()
let documentsDirectory = fileManager.urls(for: .documentDirectory, in: .userDomainMask)[0]
let requestURL = try self.getURL(from: urlRequest)

var requestPath = try self.getPath(from: requestURL)

if let headerFileName = self.getFileName(fromContentDisposition: dataResponse.response?.allHeaderFields["Content-Disposition"] as? String) {
requestPath = requestPath.appending("/\(headerFileName)")
}

let filePath = documentsDirectory.appendingPathComponent(requestPath)
let directoryPath = filePath.deletingLastPathComponent().path

try fileManager.createDirectory(atPath: directoryPath, withIntermediateDirectories: true, attributes: nil)
try data.write(to: filePath, options: .atomic)

completion(
Response(
response: dataResponse.response!,
body: (filePath as! T)
),
nil
)

} catch let requestParserError as DownloadException {
completion(nil, ErrorResponse.Error(400, dataResponse.data, requestParserError))
} catch let error {
completion(nil, ErrorResponse.Error(400, dataResponse.data, error))
}
return
})
case is Void.Type:
validatedRequest.responseData(completionHandler: { (voidResponse) in
cleanupRequest()
Expand Down Expand Up @@ -191,6 +241,66 @@ open class AlamofireRequestBuilder<T>: RequestBuilder<T> {
}
return httpHeaders
}

fileprivate func getFileName(fromContentDisposition contentDisposition : String?) -> String? {

guard let contentDisposition = contentDisposition else {
return nil
}

let items = contentDisposition.components(separatedBy: ";")

var filename : String? = nil

for contentItem in items {

let filenameKey = "filename="
guard let range = contentItem.range(of: filenameKey) else {
break
}

filename = contentItem
return filename?
.replacingCharacters(in: range, with:"")
.replacingOccurrences(of: "\"", with: "")
.trimmingCharacters(in: .whitespacesAndNewlines)
}

return filename

}

fileprivate func getPath(from url : URL) throws -> String {

guard var path = NSURLComponents(url: url, resolvingAgainstBaseURL: true)?.path else {
throw DownloadException.requestMissingPath
}

if path.hasPrefix("/") {
path.remove(at: path.startIndex)
}

return path

}

fileprivate func getURL(from urlRequest : URLRequest) throws -> URL {

guard let url = urlRequest.url else {
throw DownloadException.requestMissingURL
}

return url
}

}

fileprivate enum DownloadException : Error {
case responseDataMissing
case responseFailed
case requestMissing
case requestMissingPath
case requestMissingURL
}

public enum AlamofireDecodableRequestBuilderError: Error {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ open class CodableHelper {
var returnedError: Error? = nil

let decoder = JSONDecoder()
decoder.dataDecodingStrategy = .base64Decode
decoder.dataDecodingStrategy = .base64
if #available(iOS 10.0, *) {
decoder.dateDecodingStrategy = .iso8601
}
Expand All @@ -38,7 +38,7 @@ open class CodableHelper {
if prettyPrint {
encoder.outputFormatting = .prettyPrinted
}
encoder.dataEncodingStrategy = .base64Encode
encoder.dataEncodingStrategy = .base64
if #available(iOS 10.0, *) {
encoder.dateEncodingStrategy = .iso8601
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,56 @@ open class AlamofireRequestBuilder<T>: RequestBuilder<T> {
nil
)
})
case is URL.Type:
validatedRequest.responseData(completionHandler: { (dataResponse) in
cleanupRequest()

do {

guard !dataResponse.result.isFailure else {
throw DownloadException.responseFailed
}

guard let data = dataResponse.data else {
throw DownloadException.responseDataMissing
}

guard let request = request.request else {
throw DownloadException.requestMissing
}

let fileManager = FileManager.default
let urlRequest = try request.asURLRequest()
let documentsDirectory = fileManager.urls(for: .documentDirectory, in: .userDomainMask)[0]
let requestURL = try self.getURL(from: urlRequest)

var requestPath = try self.getPath(from: requestURL)

if let headerFileName = self.getFileName(fromContentDisposition: dataResponse.response?.allHeaderFields["Content-Disposition"] as? String) {
requestPath = requestPath.appending("/\(headerFileName)")
}

let filePath = documentsDirectory.appendingPathComponent(requestPath)
let directoryPath = filePath.deletingLastPathComponent().path

try fileManager.createDirectory(atPath: directoryPath, withIntermediateDirectories: true, attributes: nil)
try data.write(to: filePath, options: .atomic)

completion(
Response(
response: dataResponse.response!,
body: (filePath as! T)
),
nil
)

} catch let requestParserError as DownloadException {
completion(nil, ErrorResponse.Error(400, dataResponse.data, requestParserError))
} catch let error {
completion(nil, ErrorResponse.Error(400, dataResponse.data, error))
}
return
})
case is Void.Type:
validatedRequest.responseData(completionHandler: { (voidResponse) in
cleanupRequest()
Expand Down Expand Up @@ -191,6 +241,66 @@ open class AlamofireRequestBuilder<T>: RequestBuilder<T> {
}
return httpHeaders
}

fileprivate func getFileName(fromContentDisposition contentDisposition : String?) -> String? {

guard let contentDisposition = contentDisposition else {
return nil
}

let items = contentDisposition.components(separatedBy: ";")

var filename : String? = nil

for contentItem in items {

let filenameKey = "filename="
guard let range = contentItem.range(of: filenameKey) else {
break
}

filename = contentItem
return filename?
.replacingCharacters(in: range, with:"")
.replacingOccurrences(of: "\"", with: "")
.trimmingCharacters(in: .whitespacesAndNewlines)
}

return filename

}

fileprivate func getPath(from url : URL) throws -> String {

guard var path = NSURLComponents(url: url, resolvingAgainstBaseURL: true)?.path else {
throw DownloadException.requestMissingPath
}

if path.hasPrefix("/") {
path.remove(at: path.startIndex)
}

return path

}

fileprivate func getURL(from urlRequest : URLRequest) throws -> URL {

guard let url = urlRequest.url else {
throw DownloadException.requestMissingURL
}

return url
}

}

fileprivate enum DownloadException : Error {
case responseDataMissing
case responseFailed
case requestMissing
case requestMissingPath
case requestMissingURL
}

public enum AlamofireDecodableRequestBuilderError: Error {
Expand Down
Loading

0 comments on commit 8067612

Please sign in to comment.