Upload image with URL parameters using Alamofire on iOS 9 issue - swift2

I have an iOS app written in Swift 2.0 wich uploads images to Microsoft Azure Blob Storage. I use Alamofire for the requests.
On an device with iOS 8 everything works fine, but on iOS 9 it get errors on upload:
let AlamofireManager = Alamofire.Manager.sharedInstance
AlamofireManager.session.configuration.HTTPAdditionalHeaders = [
"Content-Type": "image/jpg",
"x-ms-blob-type": "BlockBlob"
]
AlamofireManager.upload(.PUT, uploadURL, data: imageData)
.responseJSON { (request, response, result) in
print("Request=\(request)")
print("response=\(response)")
print("result=\(result)")
if (response) != nil {
let statusString = String(stringInterpolationSegment: response!.statusCode)
let statusCode = self.getStatusCodeFromStatusString(statusString)
if (statusCode == 201) {
// MY SUCCESS CODE IS HERE
}
else {
// STATUSCODE != 201
}
}
else {
// OTHER ERROR
}
}
An sample URL for the upload (uploadURL) might be:
https://mystorage.blob.core.windows.net:443/thumbs/7346e38a-eb54-48ea-b0fe-89357100dd18.jpg?sv=2013-08-15&sr=b&sig=GYwHvnUc52GsajFJCAu1v4W5qG0wSBpaXvxncD%2FAt34%3D&st=2015-10-01T11%3A25%3A57Z&se=2015-10-01T11%3A40%3A57Z&sp=w
For Azure it is important, that:
a) The HTTP-Verb is PUT
b) The Url parameters are included in Url and not as multipart data (this is the access token for the upload).
Perhaps Alamofire has problems on creating the URL with parameters in combination with the PUT?
This solution does not work, because it´s based on multipart data upload: Upload image with parameters in Swift
Because I think about the URL parameter problem, I tried following:
let AlamofireManager = Alamofire.Manager.sharedInstance
AlamofireManager.session.configuration.HTTPAdditionalHeaders = [
"Content-Type": "image/jpg",
"x-ms-blob-type": "BlockBlob"
]
var URLRequest: NSMutableURLRequest {
let URL = NSURL(string: uploadURL)!
var mutableRequest = NSMutableURLRequest(URL: URL)
mutableRequest.HTTPMethod = Alamofire.Method.PUT.rawValue
return mutableRequest
}
AlamofireManager.upload(URLRequest, data: imageData)
:
: rest is same like above
:
But this does´t work, too. In both cases I always get an 400 error (in response.statusCode) from the server. result contains Failure and the information NSCocoaErrorDomain - code 3840 with description Invalid value around character 3.
But on iOS 8, the solution works like a charm :(
Any ideas, what the problem is and how to solve it?
Edit: Or could the port be the problem?

Got it on my own. Alamofire seems not to send the HTTP-Headers as expected with the AlamofireManager. I added the headers manually:
var URLRequest: NSMutableURLRequest {
let URL = NSURL(string: uploadURL)!
var mutableRequest = NSMutableURLRequest(URL: URL)
mutableRequest.HTTPMethod = Alamofire.Method.PUT.rawValue
mutableRequest.setValue("image/jpg", forHTTPHeaderField: "Content-Type")
mutableRequest.setValue("BlockBlob", forHTTPHeaderField: "x-ms-blob-type")
return mutableRequest
}
AlamofireManager.upload(URLRequest, data: imageData)
:
:

Related

How to convert data(Type Data) into a zip file(Type File) in swift 4 and cocoa for Mac OS App?

I am developing a mac os application where i have to convert the data from server API to a zip file. The API is returning a zip file itself(i am fetching a zip file from server) in encoded format of type Data, but i want to convert that data to a zip file and want to store in the disk.
My Function:
func DownloadExamZip(){
let request = NSMutableURLRequest(url: NSURL(string: "http://localhost:5000/api/DownloadExamZip/EX0000018/ST000000195/874059")! as URL)
request.httpMethod = "GET"
let AuthorizationToken = "Hidden"
request.setValue("application/x-www-form-urlencoded; charset=utf-8", forHTTPHeaderField: "Content-Type")
request.setValue(AuthorizationToken, forHTTPHeaderField: "Authorization")
let task = URLSession.shared.dataTask(with: request as URLRequest) { data, response, error in
do {
guard data != nil else {
print("data is nil")
return
}
//Here i want to convert the type data to a zip file
}
catch {
print("Error -> \(error)")
}
}
task.resume()
}
Can anyone help me to convert that data into a zip file please. I also have to store that file in the disk.
You can use write(to:options:) method to write your data to file at particular URL
let fileURL = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false).appendingPathComponent("yourfile.zip")
do {
try data.write(to: fileURL, options: .atomic)
} catch {
print(error)
}

URL Sessions returning server not found even though URL is valid - Swift4

I am trying to use URLSession to do a API Request. The request/link is the following https://api.nanopool.org/v1/zec/user/t1KcroGeTYz6Tn4hsgwnuiUzw65xgAAaknc
When I put it into safari it loads. When I try preform the request in Xcode 9 with Swift4, I get an error that the server was not found.
Here is the entire error.
The top to lines are just from a print function, the rest is the error.
Here is the code I used:
let api = "https://api.nanopool.org/v1/zec/user/"
let urlString = api+addr
print(urlString)
guard let url = URL(string: urlString) else { return }
URLSession.shared.dataTask(with: url) { (data, response, error) in
if error != nil {
print(error!.localizedDescription)
}
guard let data = data else { return }
print(data)
}.resume()
What is the issue with it that it causing it to return that the server cannot be found even though its a valid URL/Request?

Swift 2.0 NSURLConnection sendSynchronousRequest

I am using the code below to check for an internet connection. It was working correctly but after the Swift 2.0 update I now see an error on the line var data = NSURLConnection.sendSynchronousRequest(request, returningResponse: &response, error: nil) as NSData? saying extra argument 'error' in call.
class func isConnectedToNetwork()->Bool{
var Status:Bool = false
let url = NSURL(string: "http://google.com/")
let request = NSMutableURLRequest(URL: url!)
request.HTTPMethod = "HEAD"
request.cachePolicy = NSURLRequestCachePolicy.ReloadIgnoringLocalAndRemoteCacheData
request.timeoutInterval = 10.0
var response: NSURLResponse?
var data = NSURLConnection.sendSynchronousRequest(request, returningResponse: &response, error: nil) as NSData?
if let httpResponse = response as? NSHTTPURLResponse {
if httpResponse.statusCode == 200 {
Status = true
}
}
return Status
}
Do you have any ideas what I should change it to?
Thanks
If you look at apples documentation (https://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSURLConnection_Class/#//apple_ref/occ/clm/NSURLConnection/sendSynchronousRequest:returningResponse:error:) you'll see that the definition changed to this:
class func sendSynchronousRequest(_ request: NSURLRequest,
returningResponse response: AutoreleasingUnsafeMutablePointer<NSURLResponse?>) throws -> NSData
They have removed the error parameter and the method throws now an ErrorType, if the request fails. So this should work:
do {
let data = try NSURLConnection.sendSynchronousRequest(request, returningResponse: &response)
} catch (let e) {
print(e)
}
However you shouldn't use this method: It's deprecated in favor of NSURLSession since iOS 9 and OS X 10.11.

Making Amazon Web Services S3 POST request in Swift

I am trying to use AWS S3 service to host images of my iOS application in Swift language.
At this step I am just trying to simply post png image with POST request.
In any POST request for AWS S3 we need to make an authorization header which consists of the information that authenticate this request. To encode data with HMAC SHA256 which is required by Amazon I use GitHub project as my Subproject from this link: https://github.com/krzyzanowskim/CryptoSwift
This helped me to encrypt the signature however when I tried to send this request I received an error which says: "SignatureDoesNotMatchThe request signature we calculated does not match the signature you provided. Check your key and signing method."
Here is my code:
var img = UIImage(named: "myImage.png")
var imageData : NSData = UIImageJPEGRepresentation(img, 1.0)
let key = "mybucketname"
let url = NSURL(string:"http://mybucket.s3.amazonaws.com/")
var request = NSMutableURLRequest(URL: url!)
request.HTTPMethod = "POST"
let uniqueId = NSProcessInfo.processInfo().globallyUniqueString
var postBody:NSMutableData = NSMutableData()
var boundary:String = "------WebKitFormBoundary\(uniqueId)"
request.addValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField:"Content-Type")
// I am trying to generate a date stamp compatible for request
let date = NSDate()
let formatter = NSDateFormatter()
formatter.timeStyle = .ShortStyle
formatter.stringFromDate(date)
var dateKey = ["AWS4"+"My AWSSecretKey","20150317"]
// Here is the signature that I'm trying to make
var signature = "My AWSSecretKey".sha256()?.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: true)?.base64EncodedStringWithOptions(NSDataBase64EncodingOptions())
request.addValue("AWS MYAWSACCESSKEYID:\(signature)", forHTTPHeaderField: "Authorization")
request.addValue("Wed, 18 Mar 2015 20:39:27 +0000", forHTTPHeaderField: "Date")
request.addValue(key, forHTTPHeaderField:"key")
request.addValue("\(postBody.length)", forHTTPHeaderField:"Content-Length")
postBody.appendData("--\(boundary)\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
postBody.appendData("Content-Type: image/png\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
postBody.appendData(imageData)
var postData = String()
postData += "\r\n"
postData += "\r\n--\(boundary)--\r\n"
postBody.appendData(postData.dataUsingEncoding(NSUTF8StringEncoding)!)
request.HTTPBody = postBody
var error: NSError?
let session = NSURLSession.sharedSession()
var task = session.dataTaskWithRequest(request, completionHandler: { (data, response, err) -> Void in
var stringData = NSString(data: data, encoding: NSUTF8StringEncoding)
var conversionError: NSError?
var jsonDictionary = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableLeaves, error: &conversionError) as? NSDictionary
})
task.resume()
I need to find out how to make a proper signature and how I should encrypt it since its my fire time using such tools.
You shouldn't have a secret key hard-coded in your app - this negates its security. I'd suggest generating the key from your own server (eg using the excellent S3Direct django module), then obtain the key like this:
let filename = "myfile.mp4"
let requestUrl = Constants.my_own_server+"/s3direct/get_upload_params/"
println("Uploading file of name ***" + filename + "***")
let defaults = NSUserDefaults.standardUserDefaults()
let authToken : String = defaults.stringForKey("token")!
let manager = Manager.sharedInstance
manager.session.configuration.HTTPAdditionalHeaders = [
"Authorization": "Token " + authToken
]
let parameters : [ String : AnyObject] = [
"type": "video/mp4",
"name": filename,
"dest": "vids"
]
Alamofire.request(.POST, requestUrl, parameters: parameters).response(serializer: Request.JSONResponseSerializer(), completionHandler: { (request, response, object, error) -> Void in
//println(object)
//println(error)
if (error == nil) {
self.uploadFile(videoData!, parameters: object as! [ String : String], filename: filename)
}
else {
print("Failed to sign file")
}
})
Good luck - I have found this particular stack unusually painful to get working.

Xcode Swift Quickbooks call

I want to do an API request to my Quickbooks company, but I'm having some issues. Every time I try to connect, I get an error saying "The operation can't be completed": error 1012. I searched it up, and this error has to do with the OAuth tokens being wrong. I do not know which tokens to put in the following headers:
var request = NSMutableURLRequest(URL: NSURL(string: "https://quickbooks.api.intuit.com/v3/company/myCompanyId/query?query=SELECT%2A%20FROM%20Customer")!)
request.HTTPMethod = "GET"
request.setValue("secret", forHTTPHeaderField: "oauth_token")
request.setValue("secret", forHTTPHeaderField: "app_token")
request.setValue("secret", forHTTPHeaderField: "oauth_consumer_key")
request.setValue("D3jdR1LMb5T2mF0yggcgHsYjVjs%3D", forHTTPHeaderField: "oauth_signature")
request.setValue("HMAC-SHA1", forHTTPHeaderField: "oauth_signature_method")
request.setValue("1424984263", forHTTPHeaderField: "oauth_timestamp")
request.setValue("1.0", forHTTPHeaderField: "oauth_version")
request.setValue("f3b666ee-2d2a-42a1-81b3-8370b74c4c3a", forHTTPHeaderField: "oauth_nonce")
println(request.allHTTPHeaderFields!)
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue()) {
(response, data, error) in
println(response)
println(error)
println(data)
if error == nil {
if let HTTPResponse = response as? NSHTTPURLResponse {
let statusCode = HTTPResponse.statusCode
if statusCode == 200 {
println("success")
println(response)
}
}
}
}
Can anybody tell me where to find the correct keys for these values? I can only find keys for app token, oauth consumer key, and oath consumer key secret. Where do these values go too?
Using consumerKey and consumerSecret , you can generate accessToken and accessSecret from the OAuthPlayground. https://appcenter.intuit.com/Playground/OAuth/IA
PN - After completing C2QB(OAuth) flow, you should use 'App Menu API Test.' option which will show you accessToken and accessSecret.

Resources