Swift 3 - Rest Api HTTP Header Values are not being sent - ios

I'm trying to build an app with Swift, which makes a REST API call with an authorization header. The code looks like this:
var request = URLRequest(url: url!)
request.httpMethod = "GET"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
request.addValue("username:password", forHTTPHeaderField: "Authorization")
request.addValue("de", forHTTPHeaderField: "Content-Language")
URLSession.shared.dataTask(with: request) { (data, response, error) in
...
...
My problem is that the HTTP Header values are somehow not being sent. I verified that the requests values are being set by printing out request.allHTTPHeaderFields, but the response from the server still holds all the default values for the headers. This is not only for the Authorization header but also for any other header I try to change.
It would be great if someone can find the mistake... I mean, it is a very simple piece of code, so I'm really confused to where it went wrong.

Related

Swift getting error while upload base64 to server?

My scenario, I am trying to upload the user camera and photolibrary captured image to my server. Here, Already we are sending few parameters like (name, phone number, etc…) within this we are added photo parameter and sending base64 image data to the server. Now, while sending the base64 strings to the server I am getting below error.
My Error
2019-03-08 17:49:52.872545+0530 myapp[441:40026] [BoringSSL]
nw_protocol_boringssl_error(1584) [C3.1:2][0x12dfd9e80] Lower protocol
stack error: 54 2019-03-08 17:49:52.873175+0530 myapp[441:40026] TIC
Read Status [3:0x280be5140]: 1:54 2019-03-08 17:49:52.877753+0530
myapp[441:40026] Task .<4> HTTP
load failed (error code: -1005 [4:-4]) 2019-03-08 17:49:52.878073+0530
myapp[441:40125] Task .<4>
finished with error - code: -1005
I am using below code for JSON
apiPath = “https://.........com?country=\(get_countryID ?? "unknown")&last_update_date=\(today_string)&device_id=\(deviceID)&app_type=1&location=\(get_latlong)&photo=\(get_photobase64)”
if let encodeString = apiPath.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed),
let url = URL(string: encodeString) {
let session = URLSession.shared
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
request.addValue(access_key, forHTTPHeaderField: "access-key")
request.addValue(auth_token!, forHTTPHeaderField: "auth-token")
request.timeoutInterval = 10
I gave already Allow Arbitrary Loads = YES.

How to set a 'Token xxxxxxxxxx' for 'Authorization' in HTTP header in URLSession

The backend APIs I'm working with require a token to be sent with every request against the HTTP header key Authorization in this format - Token xxxxxxxxxx.
Right now, I'm doing the following.
var getRequest = URLRequest(url: url)
getRequest.addValue("Token xxxxxxxx", forHTTPHeaderField: "Authorization")
This works sometimes and some other times, the header field Authorization is stripped when the request is sent out. I checked this using Charles proxy.
Apple's documentation states the following.
An NSURLSession object is designed to handle various aspects of the
HTTP protocol for you. As a result, you should not modify the
following headers: Authorization, Connection, Host, WWW-Authenticate
As a solution to this, many suggest using the didReceiveAuthenticationChallenge delegate method for URLSession.
Here, you need to pass a URLSession.AuthChallengeDisposition instance to tell how you want to respond to the challenge and a URLCredential instance to pass the credentials to respond to the authenticate challenge.
I do not know how to and if I can create a URLCredential instance that will add Token xxxxxxxx for the header field Authorization.
Can somebody more knowledgeable please help me how to go about solving this?
PS - All code mentioned in this question is in Swift 3.
This question asks something similar to what I have. But, the answers given there don't work for me. And, some of the questions asked under the questions regarding Apple not allowing headers for Authorization to be added have gone unanswered.
Edit:
Posting relevant code.
var getRequest = URLRequest(url: url)
getRequest.httpMethod = "GET"
getRequest.addValue("application/json", forHTTPHeaderField: "Content-Type")
getRequest.addValue("application/json", forHTTPHeaderField: "Accept")
let token = DataProvider.sharedInstance.token
getRequest.addValue("Token \(token)", forHTTPHeaderField: "Authorization")
let getTask = URLSession.shared.dataTask(with: getRequest) { (data, response, error) in
if let data = data {
print("--------GET REQUEST RESPONSE START--------")
print("CODE: \((response as? HTTPURLResponse)?.statusCode ?? 0)")
print("Response Data:")
print(String(data: data, encoding: .utf8) ?? "")
print("--------GET REQUEST RESPONSE END--------")
}
}
getTask.resume()
Here, I can confirm that the header field for 'Authorization' is getting added to the request's header dictionary.
But, when I check what request hits the server, the header field for 'Authorization' is missing. Any thoughts?
I ran into this exact same issue and discovered that my lack of a trailing slash, /, was the problem.
The server was sending back a 301 Redirect response. URLSession automatically follows the redirect, but will also drop the Authorization header. This is likely due to Authorization's "special status". According to URLSessionConfiguration's documentation:
An URLSession object is designed to handle various aspects of the HTTP protocol for you. As a result, you should not modify the following headers:
Authorization
Connection
Host
WWW-Authenticate
If the Authorization header is required, implement urlSession(_:task:willPerformHTTPRedirection:newRequest:completionHandler:) from URLSessionTaskDelegate. That method is passed the new request on redirect, allowing you to add back the header.
e.g.
class APIClient: URLSessionTaskDelegate {
let session: URLSession!
initializeSession() {
// Create a new session with APIClient as the delegate
session = URLSession(configuration: URLSessionConfiguration.default,
delegate: self,
delegateQueue: nil)
}
// Perform the request
func fetchRecords(handler: () => void) {
var request = URLRequest(url: URL(string: "http://127.0.0.1:8000/api/employee/records")!)
request.setValue(retrieveToken(), forHTTPHeaderField: "Authorization")
session.dataTask(with: request, completionHandler: handler).resume()
}
// Implement URLSessionTaskDelegate's HTTP Redirection method
func urlSession(_ session: URLSession, task: URLSessionTask, willPerformHTTPRedirection response: HTTPURLResponse, newRequest request: URLRequest, completionHandler: #escaping (URLRequest?) -> Void) {
// Create a mutable copy of the new request, add the header, call completionHandler
var newRequest = request
newRequest.addValue(retrieveToken(), forHTTPHeaderField: "Authorization")
completionHandler(newRequest)
}
}
IMPORTANT NOTE!
It's a bad idea to blindly trust a redirect. You should ensure that the URL you're being redirected to is the same domain as the original request. I've left that out of my code example for brevity.

Alamofire timeout not working when larger than 60 seconds

In my project, I use Alamofire to send a POST request, the code looks like this:
var request = URLRequest(url: URL(string: url as! String)!)
request.httpMethod = method.rawValue
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpBody = try? JSONSerialization.data(withJSONObject: parameters)
request.timeoutInterval = 120
let alamofireRequest = Alamofire.request(request)
alamofireRequest.responseJSON(completionHandler: { response in
// do somthing
}
when I set the timeoutInterval to 10, it works well. But, when I set it to 120, after about 60 second I receive a timeout error from sever.
Does iOS has any default setting for the timeout property? It can't be lager than 60?
Where I can find some documentations for it?
Hope anyone can give me some suggestion.
Changing the timeoutInterval in Alamofire won't change the server's timoutInterval.
Server responds according to its own configuration.
But if you need, you can change the timeout on the server side by modifying the API.

"HTTP Status 400 - Bad Request - The request sent by the client was syntactically incorrect"?

I've done a http request with post parameters so many times, and I have now so many of them working just fine, I don't know why this one is not
this is the code
let url = NSURL(string: "bla bla lba")
let request = NSMutableURLRequest(URL: url)
let body = "id=\(requestClient!.id!)"
print("body = \(body)")
request.HTTPBody = body.dataUsingEncoding(NSASCIIStringEncoding)
request.HTTPMethod = "POST"
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "content-type")
let session = NSURLSession.sharedSession()
let task1 = session.dataTaskWithRequest(request, completionHandler: {(data, response, error) in
the server expects a form parameter named id and its value is long
when I print the id from swift (as you can see the code), I get this
id=1453045943881.0
and i get this error
HTTP Status 400 - Bad Request - The request sent by the client was syntactically incorrect.
sounds like the server said the request is not correct, but where is the wrong?
this is the server
#Path("/checkForResponses")
#POST
public Response checkForResponeses (#FormParam("id") long id) {

Put request IOS

I try to update a object in the database trough a API call. I do this action with a PUT request. A Post request was already made and is working fine. I thought it is just copy paste...
The API part works fine because if I execute the following curl command than it updates the row I wanted in the database
$ curl -H 'Accept: application/json' -i -X PUT -d 'UserLogin=Ub0D&EndDate=2014-01-17 00:00:00.0000000&Sport=Fietsen&Distance=1000&Duration=10&Achieved=true&DateCreated=2015-05-09 12:01:00.000000' http://localhost:8089/api/goal/ub0d -k -u ub0d:test123
But now the part in swift gives me a bad request error (400)...
This is my code
var url : NSURL
url = NSURL(string: _apiUrl + connectToApi(apiCall) + String("\(AccountRepository.Instance.getCurrentUserName())"))!
let request = NSMutableURLRequest(URL: url)
if postString != nil {
let postData : NSData = ("UserLogin=Ub0D&EndDate=2014-01-1700:00:00.0000000&Sport=Fietsen&Distance=1000&Duration=10&Achieved=true&DateCreated=2014-01-1700:00:00.0000000").dataUsingEncoding(NSUTF8StringEncoding)!
// create the request
request.HTTPMethod = "PUT"
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "content-type")
request.setValue("application/json", forHTTPHeaderField: "Content-type")
request.setValue("application/json", forHTTPHeaderField: "Accept")
request.HTTPBody = postData
}
var connection: NSURLConnection = NSURLConnection(request: request, delegate: self, startImmediately: true)!
I'm really stuck on it:(
You request can't have two different content types at the same time:
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "content-type")
request.setValue("application/json", forHTTPHeaderField: "Content-type")
The data you are sending are obviously not JSON, so I guess you want only
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "content-type")
and remove the "application/json" line.
There is also a difference between your date formats:
CURL
EndDate=2014-01-17 00:00:00.0000000
Swift
EndDate=2014-01-1700:00:00.0000000
Note the missing space between date and time, probably should be URL encoded (+):
EndDate=2014-01-17+00:00:00.0000000
In general, most REST APIs send error messages in response body, so it is always good to log the response for failed requests.

Resources