Make a http request with basic authentication - ios

I want to make an http request with basic auth. I tried to follow this topic : click here. But Xcode tell me
Bad Request after httpResponse
And I don't know why since this morning. Maybe anyone got a idea more interesting than I can find on the web ? :)
Here is my code :
func topRefresh(sender:AnyObject){
var list=Array<Notification>()
//credential
let credentialLogin = NSUserDefaults.standardUserDefaults().objectForKey("login") as! String
let credentialPassword = NSUserDefaults.standardUserDefaults().objectForKey("password") as! String
// set up the base64-encoded credentials
let loginString = NSString(format: "%#:%#", credentialLogin, credentialPassword)
let loginData: NSData = loginString.dataUsingEncoding(NSUTF8StringEncoding)!
let base64LoginString = loginData.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.Encoding64CharacterLineLength)
// create the request
let url = NSURL(string: jsonLink)!
let request = NSMutableURLRequest(URL: url)
request.cachePolicy = NSURLRequestCachePolicy.ReloadIgnoringCacheData
request.setValue("Basic \(base64LoginString)", forHTTPHeaderField: "Authorization")
request.HTTPMethod="GET"
let paramString="login="+credentialLogin
request.HTTPBody = paramString.dataUsingEncoding(NSUTF8StringEncoding)
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithRequest(request) {
(data, response, error) -> Void in
let httpResponse = response as! NSHTTPURLResponse
if (httpResponse.statusCode == 200) {
do{
if (data != nil){
self.notificationsDisplayed.removeAll()
let jsonDict = try NSJSONSerialization.JSONObjectWithData(data!,options: .AllowFragments)
list=self.parseJson(jsonDict)
if (self.notifications.count==0){
self.notifications=self.copyArray(list)
list.removeAll()
}else{
//compare new data with past data
while(list.count>0){
print(list.count)
let tmp=list.last
for notification in self.notifications {
if(tmp!.id==notification.id){
list.removeLast()
break
}else{
self.notifications.insert(tmp!, atIndex: 0)
list.removeLast()
break
}
}
}
}
self.orderByDate(&self.notifications)
self.notificationsDisplayed=self.copyArray(self.notifications)
self.applyFilter()
print("Data parsed")
}else{
print("Data is empty")
}
}catch {
print("Error with Json: \(error)")
}
}else{
print("HTTP Error")
}
self.refreshControl?.endRefreshing()
print("Finished")
}
task.resume()
}

I use the following in my code to create a default session that include the authentication:
static func defaultURLSession(username : String, password:String) -> NSURLSession {
let config = NSURLSessionConfiguration.defaultSessionConfiguration()
let userPasswordString = "\(username):\(password)"
let userPasswordData = userPasswordString.dataUsingEncoding(NSUTF8StringEncoding)
let base64EncodedCredential = userPasswordData!.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.EncodingEndLineWithCarriageReturn)
let authString = "Basic \(base64EncodedCredential)"
config.HTTPAdditionalHeaders = ["Authorization" : authString]
return NSURLSession(configuration: config)
}

Related

`WKWebsiteDataStore.default()` crash if the code is access before any webview is accessed. Why?

I have the following code
let url = URL(string: "http://127.0.0.1/set_simple.php")!
let request = URLRequest(url: url, cachePolicy: .useProtocolCachePolicy, timeoutInterval: 10)
let session = URLSession.shared
session.configuration.httpCookieAcceptPolicy = .always
session.configuration.httpCookieStorage = HTTPCookieStorage.shared
session.configuration.httpShouldSetCookies = true
let dataTask = session.dataTask(with: request) { (data, response, error) in
if error == nil {
print("Success fetch!")
guard
let url = response?.url,
let httpResponse = response as? HTTPURLResponse,
let fields = httpResponse.allHeaderFields as? [String: String]
else { return }
let cookies = HTTPCookie.cookies(withResponseHeaderFields: fields, for: url)
HTTPCookieStorage.shared.setCookies(cookies, for: url, mainDocumentURL: nil)
for cookie in cookies {
var cookieProperties = [HTTPCookiePropertyKey: Any]()
cookieProperties[.name] = cookie.name
cookieProperties[.value] = cookie.value
cookieProperties[.domain] = cookie.domain
cookieProperties[.path] = cookie.path
cookieProperties[.version] = cookie.version
cookieProperties[.expires] = Date().addingTimeInterval(31536000)
let newCookie = HTTPCookie(properties: cookieProperties)
// HTTPCookieStorage.shared.setCookie(newCookie!)
WKWebsiteDataStore.default().httpCookieStore.setCookie(newCookie!, completionHandler: nil)
print("name: \(cookie.name) value: \(cookie.value)")
}
} else {
print("Ops! \(error.debugDescription)")
}
}
dataTask.resume()
It works well if I only access it, after accessing a webview.
However, if I start the app and access this code before accessing any webview, it will crash at WKWebsiteDataStore.default(). Is it because I need to setup the WKWebsiteDataStore default?
Looks like I need to set it on the mainThread
DispatchQueue.main.async {
WKWebsiteDataStore.default().httpCookieStore.setCookie(newCookie!, completionHandler: nil)
}

Swift iOS15 async/await + basic authentication + http request slow(er)

I am using the below code for basic http authentication. It is noticeably slower than when I wasn't using authentication (the below is called around 30 times)
Are there any speed optimization changes that could be made to the code ?
Thanks
struct PrixJSONService {
let passwordString = "user:password"
let configuration = URLSessionConfiguration.default
enum PrixJSONServiceError: Error {
case failed
case failedToDecode
case invalidStatusCode
}
func fetchPrix(for stationId:String) async throws -> [Prix] {
let passwordData = passwordString.data(using:String.Encoding.utf8)!
let base64EncodedCredential = passwordData.base64EncodedString()
let authString = "Basic \(base64EncodedCredential)"
let session = URLSession(configuration: configuration)
configuration.httpAdditionalHeaders = ["Authorization" : authString]
let dataUrl = "https://xxxx.xx/~xx/xxxxxxxx/prix/\(stationId)/price.json"
let url = URL(string: dataUrl)!
var urlRequest = URLRequest(url: url)
urlRequest.setValue("Basic \(base64EncodedCredential)", forHTTPHeaderField: "Authorization")
urlRequest.httpMethod = "GET"
let (data, response) = try await session.data(for: urlRequest)
guard let response = response as? HTTPURLResponse,
response.statusCode == 200 else {
throw PrixJSONServiceError.invalidStatusCode
}
let decodedData = try JSONDecoder().decode([Price].self, from: data)
return decodedData
}
}

Sending Http Post request returns 500 status code in IoS

I am trying to send Receipt data of NSData type(converted to string) and several other parameters of type as String in Http Post request.
func receiptValidation(productId:String)
{
let SUBSCRIPTION_SECRET = My_SecretKey
let defaults = UserDefaults.standard
let receiptPath = Bundle.main.appStoreReceiptURL?.path
if FileManager.default.fileExists(atPath: receiptPath!){
var receiptData:NSData?
do{
receiptData = try NSData(contentsOf: Bundle.main.appStoreReceiptURL!, options: NSData.ReadingOptions.alwaysMapped)
}
catch{
print("ERROR: " + error.localizedDescription)
}
let receiptString = receiptData?.base64EncodedString(options: NSData.Base64EncodingOptions(rawValue: 0))
// let base64encodedReceipt = receiptData?.base64EncodedString(options: NSData.Base64EncodingOptions.endLineWithCarriageReturn)
let requestDictionary = ["receipt-data":receiptString!,"password":SUBSCRIPTION_SECRET]
guard JSONSerialization.isValidJSONObject(requestDictionary) else { print("requestDictionary is not valid JSON"); return }
do {
let requestData = try JSONSerialization.data(withJSONObject: requestDictionary)
let requestDataString = NSString(data: requestData, encoding: String.Encoding.utf8.rawValue)
//https://<apiProxyServer>:<apiProxyServerPort>/api/validate-receipt-data
let URLForApplication:String = String(format:"%#/api/validate-receipt-data",opcodeDetails["apiProxyBaseUrl"]!) // this works but as noted above it's best to use your own trusted server
let url:URL! = URL.init(string: URLForApplication)
var request = URLRequest.init(url: url)
request.httpMethod = "POST"
let configure = URLSessionConfiguration.background(withIdentifier: Bundle.main.bundleIdentifier!)
var postString:[String:Any]=[
"receiptData": requestDataString
"deviceType":"IOS",
"subscriberId":encodeString(normalString: defaults.array(forKey: "userDetails")?.first as! String),
"password":encodeString(normalString: defaults.array(forKey: "userDetails")?.last as! String),
"productId":encodeString(normalString: productId),
"code":opcodeDetails["opCode"]!
]
do {
let receiptData = try JSONSerialization.data(withJSONObject: postString)
request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
request.httpBody = receiptData
} catch let error {
print(error.localizedDescription)
}
let session = URLSession(configuration:configure,
delegate:applicationDelegate.application,
delegateQueue:OperationQueue.main)
session1 = session
let connection = session1?.dataTask(with: request)
connection?.resume()
} catch let error as NSError {
print("json serialization failed with error: \(error)")
}
}
}
Where encodeString() is a defined method
func encodeString(normalString:String) -> String {
let allowedCharacters = CharacterSet.letters
let encodedString:String!=normalString.addingPercentEncoding(withAllowedCharacters: allowedCharacters)
return encodedString
}
There were no problem on server side.But I could not get success response instead What I am getting is {"status":"failure","statusCode":500,"message":"Resource url not found!"}.What mistake am i doing with this code?.Anyone please help me.Thanks in advance.
Try appending '/' at the end of URL.
Eg:
google.com/api/post and google.com/api/post/ are different and trailing slash sometimes gives 500 error, in case of Django-Backend it does.

HTTP request in swift 3 Xcode 8.3

I am getting stuck with HTTP request.it did not show any error.compiler reads the first two lines and skip the code to "task.resume()".i am fetching data with same code on other view controller but it creats problem here
func getCustomers()
{
let url = NSURL(string: "myURL.com")
let task = URLSession.shared.dataTask(with: url! as URL) {
(data, response, error) in
guard let _:Data = data, let _:URLResponse = response , error == nil else {
print("error: \(String(describing: error))")
return
}
do
{
self.getcustomersArray = [GetCustomers]()
//JSON Parsing
if let data = data,
let json = try JSONSerialization.jsonObject(with: data) as? [String: Any]
{
let results = json["Result"] as? [[String : Any]]
let getCustomersObject:GetCustomers = GetCustomers()
for result in results!
{
getCustomersObject.ActivityPrefix = (result["ActivityPrefix"] as? String)!
getCustomersObject.CustomerID = (result["CustomerID"] as? String)!
getCustomersObject.CustomerName = (result["CustomerName"] as? String)!
getCustomersObject.TFMCustomerID = (result["TFMCustomerID"] as? String)!
getCustomersObject.ShortName = (result["ShortName"] as? String)!
getCustomersObject.UserRights = (result["UserRights"] as? Int)!
self.totalCustomers += self.totalCustomers
}
self.customerName = getCustomersObject.CustomerName
}
}//end Do
catch
{
}
}
task.resume()
}
Using Block GET/POST/PUT/DELETE:
let request = NSMutableURLRequest(url: URL(string: "Your API URL here" ,param: param))!,
cachePolicy: .useProtocolCachePolicy,
timeoutInterval:"Your request timeout time in Seconds")
request.httpMethod = "GET"
request.allHTTPHeaderFields = headers as? [String : String]
let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest) {data,response,error in
let httpResponse = response as? HTTPURLResponse
if (error != nil) {
print(error)
} else {
print(httpResponse)
}
DispatchQueue.main.async {
//Update your UI here
}
}
dataTask.resume()
I think you dont mention line
request.httpMethod = "GET"

Swift REST API call in singleton class and use of protocol

I am calling rest api using singleton class as I need to call this api from 3-4 view controllers. To pass the data, I implemented one protocol method also.
I am not sure this is the right way of passing data and use of singleton class. Could anyone please guide me in this? Please guide me if I am missing or doing wrong in the code. I appreciate your time and suggestions.
//This is my NetworkService class
protocol NetworkServicesDelegate {
// protocol method
func serviceData(arrayData:NSArray)
}
class NetworkServices:NSObject{
static let sharedInstance = NetworkServices()
var delegate: NetworkServicesDelegate?
var dataArray: NSArray?
func getData(paramValue : String,apiName:String)
{
let configURL = NSBundle.mainBundle().objectForInfoDictionaryKey("ConfigURL") as! String
guard let url = NSURL(string: configURL+"/"+apiName) else {
print("Error: cannot create URL")
return
}
let request = NSMutableURLRequest(URL:url)
let defaultSession = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration())
request.HTTPMethod = "POST"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
let params = ["myKey":paramValue]
let valid = NSJSONSerialization.isValidJSONObject(params)
print(valid)
request.HTTPBody = try? NSJSONSerialization.dataWithJSONObject(params, options: [])
let task = defaultSession.dataTaskWithRequest(request, completionHandler: { (data:NSData?, response:NSURLResponse?, error:NSError?) in
if let HTTPResponse = response as? NSHTTPURLResponse {
let statusCode = HTTPResponse.statusCode
if statusCode == 200 {
self.dataArray = try! NSJSONSerialization.JSONObjectWithData(data!, options: [] ) as! NSArray
self.serviceData(self.dataArray!)
}
}
})
task.resume()
}
private func serviceData(serviceDataArray: NSArray){
guard self.delegate != nil else {
return
}
delegate?.serviceData(serviceDataArray)
print("serviceDataArray : \(serviceDataArray)")
}
}
You can follow the following approach:
Make a static or class function and take the delegate as an additional parameter
Call the delegate function after the data is download from the api in competition handler.
And from any of the view controller call this function like this:
NetworkServices.getData("yourparam", apiName: "yourAPINAME", delegate: self)
Modified NetworkServices class code below.:
protocol NetworkServicesDelegate {
func serviceData(arrayData:NSArray)
}
class NetworkServices:NSObject{
class func getData(paramValue : String,apiName:String, delegate:NetworkServicesDelegate?)
{
let configURL = NSBundle.mainBundle().objectForInfoDictionaryKey("ConfigURL") as! String
guard let url = NSURL(string: configURL+"/"+apiName) else {
print("Error: cannot create URL")
return
}
let request = NSMutableURLRequest(URL:url)
let defaultSession = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration())
request.HTTPMethod = "POST"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
let params = ["myKey":paramValue]
let valid = NSJSONSerialization.isValidJSONObject(params)
print(valid)
request.HTTPBody = try? NSJSONSerialization.dataWithJSONObject(params, options: [])
let task = defaultSession.dataTaskWithRequest(request, completionHandler: { (data:NSData?, response:NSURLResponse?, error:NSError?) in
if let HTTPResponse = response as? NSHTTPURLResponse {
let statusCode = HTTPResponse.statusCode
if statusCode == 200 {
let dataArray:NSArray = try! NSJSONSerialization.JSONObjectWithData(data!, options: [] ) as! NSArray
delegate?.serviceData(dataArray)
}
}
})
task.resume()
}
}

Resources