Authenticate Client certificate and get response from server - ios

I am working on get data from client server(ratin24 API). The API basically work after Authentication means I have one certificate and I was authenticate it with NSURLSession "didReceiveChallenge" delegate method. Everything is working fine but now issue is that I Got only header parts as a response not BOTY. so how to get actual data from there. I Pass XML Parameter in request body and the response should be XML but Got only header so please help me how to get BODY data in this situation.
let xmlString = "<?xml version='1.0' encoding='ISO-8859-1'?><TICKETANYWHERE><COUPON VER='1.0'><TEMPLATELIST /></COUPON></TICKETANYWHERE>"
let xmlData = xmlString.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)
let request = NSMutableURLRequest(URL: NSURL(string: "My URL")!)
request.HTTPMethod = "POST"
request.HTTPBody = xmlData
request.addValue("text/html; charset=ISO-8859-1", forHTTPHeaderField: "Content-Type")
struct SessionProperties {
static let identifier : String! = "url_session_background_download"
}
let configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
let backgroundSession = NSURLSession(configuration: configuration, delegate:self as? NSURLSessionDelegate, delegateQueue: NSOperationQueue.mainQueue())
let downloadTask = backgroundSession.downloadTaskWithRequest(request){ (data, response, error) -> Void in
let httpResponse = response as! NSHTTPURLResponse
let statusCode = httpResponse.statusCode
if (statusCode == 200) {
print("Everyone is fine, file downloaded successfully.")
}
}
downloadTask.resume()
Response Data (only Header) body ? :
status code: 200, headers {
Connection = close;
"Content-Length" = 23113;
"Content-Type" = "text/html; charset=ISO-8859-1";
Date = "Mon, 27 Jun 2016 11:36:12 GMT";
Server = "Apache/2.2.15 (CentOS)";
}

The response object isn't supposed to contain the body data. An NSURLResponse object contains only metadata, such as the status code and headers. The actual body data should be in the NSData object for a data task, or in the provided file for a download task.
Note that for a download task the first parameter is an NSURL, not an NSData object. That NSURL contains the location of a file on disk from which you must immediately read the response data in your completion handler or move the file to a permanent location.

Related

HTTP Post Request data could not be read Swift 3

I've been trying to get data by Http "POST" method.In my php script i have a key call "categoryWise" which has a value called "flower".I put all the necessary codes but it doesn't work and says The data couldn’t be read because it isn’t in the correct format.Please help.
let values = "categoryWise= nature"
let parameter = values.data(using: .utf8)
let url = "https://mahadehasancom.000webhostapp.com/WallpaperApp/php_scripts/getImageByCategory.php"
var request = URLRequest(url: URL(string: url)!)
request.httpMethod = "POST"
request.httpBody = parameter
request.setValue("application/x-content-type-options", forHTTPHeaderField: "Content-Type")
request.setValue("application/x-content-type-options", forHTTPHeaderField: "Accept")
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
if (error != nil)
{
print(error!)
}
else
{
do
{
let fetchData = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? NSDictionary
//print(fetchData)
let actorArray = fetchData?["result"] as? NSArray
for actor in actorArray!
{
let nameDict = actor as? NSDictionary
let name = nameDict?["date"] as! String
let countryname = nameDict?["category"] as! String
let imageUrl = nameDict?["url"] as! String
//let pageUrl = nameDict?["url"] as! String
authorArray.append(name)
titleArray.append(countryname)
imageURL.append(imageUrl)
//urlArray.append(pageUrl)
}
DispatchQueue.main.async {
self.CountryNameTable.reloadData()
}
print(authorArray)
print(titleArray)
print(imageURL)
print(urlArray)
}
catch let Error2
{
print(Error2.localizedDescription)
if let string = String(data: data!, encoding: .utf8)
{
print(string)
print(response!)
}
}
}
}
task.resume()
A few observations:
You shared PHP that is using $_POST. That means it's expecting x-www-form-urlencoded request. So, in Swift, you should set Content-Type of the request to be application/x-www-form-urlencoded because that's what you're sending. Likewise, in Swift, the Accept of the request should be application/json because your code will "accept" (or expect) a JSON response.
The values string you've supplied has a space in it. There can be no spaces in the key-value pairs that you send in a x-www-form-urlencoded request. (Note, if you have any non-alphanumeric characters in your values key pairs, you should be percent encoding them.)
In your Swift error handler, in addition to printing the error, you might want to try converting the data to a String, and looking to see what it says, e.g.
if let string = String(data: data!, encoding: .utf8) {
print(string)
}
You might also want to look at response and see what statusCode it reported. Having done that, you subsequently told us that it reported a statusCode of 500.
Status code 500 means that there was some internal error in the web service. (The code is 200 if successful.) This is generally a result of some error with the request not being handled correctly. For example, if the request neglected to format the request correctly and the web service doesn't anticipate/catch that, or if there was some other internal error on the web server, you could get 500 error code. For list of status codes, see http://w3.org/Protocols/rfc2616/rfc2616-sec10.html.
If the text in the body of the response from your web service is not illuminating, you might want to turn on error reporting (see How to get useful error messages in PHP? or How do I catch a PHP Fatal Error) and then look at the body of the response again. For example, you might include the following in your PHP:
<?php
function __fatalHandler() {
$error = error_get_last();
//check if it's a core/fatal error, otherwise it's a normal shutdown
if ($error !== NULL && in_array($error['type'], array(E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR, E_COMPILE_WARNING))) {
header("Content-Type: application/json");
$result = Array("success" => false, "error" => $error);
echo json_encode($result);
die;
}
}
register_shutdown_function('__fatalHandler');
// the rest of your PHP here
?>

HTTP Session Management in swift

I have to update user location when the user is logged in only. As I need to update location in background mode (I used https://github.com/voyage11/Location repository to receive background mode delegate call), so I put update location call in AppDelegate.
When a user logs into the server and requests any other rest API, HTTP request gets session object. But only update location rest API request doesn't get the session object.
I have tried to send cookie by setting a cookie to the HTTPHeader of request object directly. But, it doesn't contain session object.
extension AppDelegate : LocationTrackerDelegate {
func updateLocation(location: CLLocationCoordinate2D) {
let loc = [ "lat": location.latitude, "lng": location.longitude]
let urlStr = IRAPIPathManager.sharedManager.pathForUpdateLocation()
let cookie = NSHTTPCookieStorage.sharedHTTPCookieStorage().cookies?.last
// create post request
let url = NSURL(string: urlStr)!
let request = NSMutableURLRequest(URL: url)
request.HTTPMethod = "POST"
request.HTTPShouldHandleCookies = true
// Set Cookie
if cookie != nil {
let date = Utility.getDateStringFromNSDate((cookie?.expiresDate)!, format: "EEE dd MMM yyyy HH:mm:ss ZZZZ")
let cooki = "\(cookie!.name)=\(cookie!.value); Path=\(cookie!.path); Expires=\(date); HttpOnly"
request.setValue( cooki , forHTTPHeaderField: "Set-Cookie")
}
request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
let jsonData = try NSJSONSerialization.dataWithJSONObject(loc, options: .PrettyPrinted)
request.HTTPBody = jsonData
let task = NSURLSession.sharedSession().dataTaskWithRequest(request){ data, response, error in
}
task.resume()
}
}
When a user logs in to the server, the server sends a session object to the device. When any HTTP rest calls are made, the session object is inserted into the request internally. But, updateLocation API call is only one which does get the session object. Is there any scope of HTTP session object? Please pardon me if I am wrong.
Please help me, Thanks.

"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) {

Differences between Using NSJSONSerialization.dataWithJSONObject and dataUsingEncoding to make up the HTTP body in Swift

I have seen two kinds of methods to make up the HTTP body.
First one is:
let url = NSURL(string: "http://example.com")
let request = NSMutableURLRequest(URL: url!)
request.HTTPMethod = "POST"
let postString = "id=13&name=Jack"
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
Second one is:
let url = NSURL(string: "http://example.com")
let request = NSMutableURLRequest(URL: url!)
request.HTTPMethod = "POST"
let params = ["id":"13", "name":"Jack"] as Dictionary<String, String>
var err: NSError?
request.HTTPBody = NSJSONSerialization.dataWithJSONObject(params, options: nil, error: &err)
When I directly print out the request.HTTPBody the data is different. So I am wondering are there any differences between these two methods in terms of the implementation of the server side? Assuming I'am using PHP.
there're two format data.
in code using postString.dataUsingEncoding it will send data in urlencoded format. In client you must set request's Content-Type header to "application/x-www-form-urlencoded" or something like "application/x-www-form-urlencoded charset=utf-8"
in code using NSJSONSerialization.dataWithJSONObject it will send data in json format. In client you must set request's Content-Type header field to "application/json"
I'm iOS dev so I don't know about format's effect to server side PHP. to answer your question you must find difference between application/x-www-form-urlencoded and application/json format in server side

Upload image into asp.net web service in swift

How can I upload an image into my web service then I can save it on my server!
I have tried the below code using POST method but I got this error
(A potentially dangerous Request.Form value was detected from the client (uploadFile="<ffd8ffe0 00104a46 4...").)
func myImageUploadRequest() {
let imageData = UIImageJPEGRepresentation(myImageView, 1)
let boundary = generateBoundaryString()
var base64String = imageData.base64EncodedStringWithOptions(.allZeros)
let myUrl = NSURL(string: "http://xxxxx/UploadImageTest");
let request = NSMutableURLRequest(URL:myUrl!);
request.HTTPMethod = "POST";
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
if(imageData==nil) { return; }
var body = NSMutableData();
body.appendString("uploadFile=\(imageData)")
request.HTTPBody = body
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
data, response, error in
if error != nil {
println("error=\(error)")
return
}
// You can print out response object
println("******* response = \(response)")
// Print out reponse body
let responseString = NSString(data: data, encoding: NSUTF8StringEncoding)
println("****** response data = \(responseString!)")
dispatch_async(dispatch_get_main_queue(),{
});
}
task.resume()
}
And this the POST SOAP on my Asp.net web service
POST /xxxx.asmx/UploadImageTest HTTP/1.1
Host: xxxx.com
Content-Type: application/x-www-form-urlencoded Content-Length: length
uploadFile=string&uploadFile=string
The error was sending NSData to Asp.net web service.
convert the image int base64 using this code
let imageData = UIImageJPEGRepresentation(myImageView, 1)
var base64String = imageData.base64EncodedStringWithOptions(.allZeros)
then send it to web service and make sure in your web service receive String data, not byte() array.
in your web service convert the base64 into Image and save into your server.
That's it!.
I am not familiar with Swift but in Objective C I would have prepared data something like this:
....
NSMutableString* body = [NSMutableString new];
[body appendFormat:#"uploadFile=%#",base64String];
....
The reason it is erring out is pretty obvious from the error description. You might find your code is formatting your base64 image string as
uploadFile="<ffd8ffe0 00104a46 4...
The text after uploadFile= is not at all a base64 encoded string rather the string representation of NSData and that extra < at the starting of the data is being treated as a html tag in server. ASP.NET request validation does not allow such tags in your request body as security measure, to prevent code/script injection and cross site scripting.
Even if you disable request validation from server web.config or .asmx the data would still not be interpreted by server as it would still not be in valid base64 format as the server might expect.
So my advice is to frame your request properly before sending it to server and everything should work seamlessly.

Resources