AFNetworking post parameters not encoding - ios

I'm getting an error using AFNetworking 2.0 while using post method in Swift language because the body isn't encoded as it should be, here is my code:
let manager = AFHTTPRequestOperationManager()
manager.securityPolicy.allowInvalidCertificates = true;
let reqSerializer: AFJSONRequestSerializer = AFJSONRequestSerializer()
reqSerializer.setValue("T-Rex", forHTTPHeaderField: "User-Agent")
reqSerializer.setValue("no-cache", forHTTPHeaderField: "Cache-Control")
reqSerializer.setValue("apikey", forHTTPHeaderField: "Authorization")
manager.requestSerializer = reqSerializer
let resSerializer: AFJSONResponseSerializer = AFJSONResponseSerializer()
resSerializer.acceptableContentTypes = ["text/html", "application/json"]
manager.responseSerializer = resSerializer;
let params: NSDictionary = ["userName" : userName, "passWord" : passWord]
manager.POST(Constants.apiURL.url + "users/login",
parameters:params,
success: { (operation: AFHTTPRequestOperation!, responseObject: AnyObject!) in
NSLog("Success! Response is \(responseObject.description)")
},
failure: { (operation: AFHTTPRequestOperation!, error: NSError!) in
NSLog("Failure! Error is: \(error.localizedDescription)")
})
Debugging the request I get:
POST 'http://api.cc/users/login': {
Accept = "application/json";
"Accept-Language" = "pt;q=1, fr;q=0.9, en;q=0.8";
Authorization = apikey;
"Cache-Control" = "no-cache";
"Content-Type" = "application/json";
"User-Agent" = "T-Rex";
} {"passWord":"123","userName":"123"}
and my server answer:
400 'http://api.cc/users/login' [0.7545 s]: {
Age = 0;
Connection = "keep-alive";
"Content-Length" = 83;
"Content-Type" = "application/json";
Date = "Sun, 06 Sep 2015 01:03:00 GMT";
Server = "nginx/1.8.0";
Via = "1.1 varnish-v4";
"X-Varnish" = 950329;
} {"error":true,"message":"Required field(s) userName, passWord is missing or empty"}
I don't know why the username and password is encoded like this:
{"passWord":"123","userName":"123"}
instead of this:
{"passWord:123&userName":123"}

Should AFHTTPRequestSerializer instead of AFJSONRequestSerializer.
Problem solved.

Related

Alamofire and Digest-Auth

I am trying to implement in my Apps Digest-auth but i am struggling, or is not working properly.
I have setup my request as you describe in your AuthenticationTestCase and looks like the following code:
let userName = "***********"
let password = "***********"
let qop = "auth"
let xmlStr: String = "<?xml version=\"1.0\" encoding=\"utf-8\"?><methodCall><methodName>authenticate.login</methodName></methodCall>"
let postData:Data = xmlStr.data(using: String.Encoding.utf8, allowLossyConversion: true)!
let url = URL(string: "https://app.**********.co.uk/service/mobile/digest-auth/\(qop)/\(userName)/\(password)")
var request = URLRequest(url: url!)
request.httpShouldHandleCookies = true
request.setValue("\(String(describing: xmlStr))", forHTTPHeaderField: "Content-Length")
request.setValue("application/xml", forHTTPHeaderField: "Content-Type")
request.setValue("IOS133928234892nil", forHTTPHeaderField: "User-Agent")
request.setValue("application/xml", forHTTPHeaderField: "Accept")
request.httpMethod = "POST"
request.httpBody = postData
AF.request(request)
.authenticate(username: userName, password: password)
.response { response in ........
When I run the above code, I am receiving the following response from the remote server:
Response XML Error:
You must be authenticated to access this resource
Response Error Code: 401
Response Headers:
Optional([AnyHashable("X-Powered-By"): PHP/7.1.33, AnyHashable("Pragma"): no-cache, AnyHashable("Content-Length"): 310, AnyHashable("Date"): Fri, 22 May 2020 09:15:48 GMT, AnyHashable("Server"): Apache/2.4.41 () OpenSSL/1.0.2k-fips PHP/7.1.33, AnyHashable("Cache-Control"): no-store, no-cache, must-revalidate, AnyHashable("Content-Type"): Content-Type: application/xml, AnyHashable("Www-Authenticate"): Digest realm="Mobile",nonce="31JEmMdeSVfXWQ:OT/ndHY6ch/PjqFwA6uutg",opaque="c81e728d9d4c2f636f067f89cc14864c",qop="auth",algorithm="MD5", Digest realm="Mobile",nonce="31JEmMdeSVfXWQ:OT/ndHY6ch/PjqFwA6uutg",opaque="c81e728d9d4c2f636f067f89cc14864c",qop="auth",algorithm="SHA-512-256", Digest realm="Mobile",nonce="31JEmMdeSVfXWQ:OT/ndHY6ch/PjqFwA6uutg",opaque="c81e728d9d4c2f636f067f89cc14864c",qop="auth",algorithm="SHA-256", AnyHashable("Connection"): Keep-Alive, AnyHashable("Keep-Alive"): timeout=5, max=100, AnyHashable("Expires"): Thu, 19 Nov 1981 08:52:00 GMT])
Note: If I do the same request via Postman, it works properly.
It looks like the Alamofire is not properly handling the Digest challenge.
Please could you help me on this issue?

Error Domain=com.alamofire.error.serialization.response Code=-1011 "Request failed: forbidden (403)

I am using AFNetworking 3.1.0 to make a http request.
It shows below after i made the request. The code i made the request is in the bottom. The url below you can see is not visitable without ssl VPN.
Error Domain=com.alamofire.error.serialization.response Code=-1011
"Request failed: forbidden (403)"
UserInfo={com.alamofire.serialization.response.error.response= { URL:
https://223.71.215.70/web/1/http/0/10.100.5.105:6666/entry } { status
code: 403, headers {
Connection = "Keep-Alive";
"Content-Length" = 238;
"Content-Type" = "text/html; charset=iso-8859-1";
Date = "Wed, 14 Dec 2016 14:27:48 GMT";
"Keep-Alive" = "timeout=15, max=100";
"X-Frame-Options" = SAMEORIGIN; } }, NSErrorFailingURLKey=https://223.71.215.70/web/1/http/0/10.100.5.105:6666/entry,
NSLocalizedDescription=Request failed: forbidden (403),
com.alamofire.serialization.response.error.data=<3c21444f 43545950
45204854 4d4c2050 55424c49 4320222d 2f2f4945 54462f2f 44544420
48544d4c 20322e30 2f2f454e 223e0a3c 68746d6c 3e3c6865 61643e0a
3c746974 6c653e34 30332046 6f726269 6464656e 3c2f7469 746c653e
0a3c2f68 6561643e 3c626f64 793e0a3c 68313e46 6f726269 6464656e
3c2f6831 3e0a3c70 3e596f75 20646f6e 27742068 61766520 7065726d
69737369 6f6e2074 6f206163 63657373 202f7765 622f312f 68747470
2f302f31 302e3130 302e352e 3130353a 36363636 2f656e74 72790a6f
6e207468 69732073 65727665 722e3c2f 703e0a3c 2f626f64 793e3c2f
68746d6c 3e0a>} Request failed: forbidden (403)
let config = URLSessionConfiguration.default
config.timeoutIntervalForRequest = 30
let manager = AFHTTPSessionManager(sessionConfiguration: config)
manager.requestSerializer = AFHTTPRequestSerializer() // AFJSONRequestSerializer(writingOptions: .prettyPrinted)
manager.responseSerializer = AFHTTPResponseSerializer() // AFJSONResponseSerializer(readingOptions: .mutableContainers)
// manager.responseSerializer.acceptableContentTypes = ["text/html"]
manager.responseSerializer.acceptableContentTypes = ["application/json", "text/json", "text/JavaScript", "text/html", "text/plain"]
let policy = AFSecurityPolicy(pinningMode: .none)
policy.allowInvalidCertificates = true
policy.validatesDomainName = false
manager.securityPolicy = policy
manager.post(url, parameters: para, progress: nil, success: { (task:URLSessionDataTask, a:Any?) in
print(123)
}) { (task: URLSessionDataTask?, error: Error) in
// print(task?.description)
print(error)
print(error.localizedDescription)
}
I found that if my phone clock was out of sync...Maybe check that your phone is set to the right time "auto zone" and see if that works...
Reference URL: https://community.fitbit.com/t5/Charge-HR/Can-t-set-up-error-Forbidden-403/td-p/1053680

Handle non-JSON response from POST request with Alamofire

I'm using Alamofire 3 and the end point I'm calling (I don't own the server) accepts a POST request and returns HTML as a response.
I am able to get the HTML response when using curl in the command line, however Alamofire doesn't return the response body, but only the header.
This is my code:
let headers = [
"Referer": "SOMEURL"
]
Alamofire.request(.POST, url, headers: headers)
.validate()
.response { request, response, data, error in
// do something with response
}
response is:
Optional(<NSHTTPURLResponse: 0x7f9ba3759760> { URL: SOMEURL } { status code: 200, headers {
Connection = "keep-alive";
"Content-Encoding" = gzip;
"Content-Type" = "text/html";
Date = "Thu, 22 Sep 2016 15:19:20 GMT";
Server = nginx;
"Transfer-Encoding" = Identity;
Vary = "Accept-Encoding";
} })
and data is:
Optional<NSData>
- Some : <>
Any thoughts?

Sending data to PHP server

I'm trying to set up sending data to a PHP server but I'm having no luck at all.
Here is my PHP code.
<?php
require_once "../config/config.php";
var_dump($_POST);
var_dump($_REQUEST);
// Read request parameters
if(isset($_REQUEST)){
$username = $db->escape($_REQUEST["username"]);
$email = $db->escape($_REQUEST["email"]);
$password = $db->escape($_REQUEST["password"]);
$id = MD5($email);
echo $username;
//$db->query("INSERT INTO user ('id','username','email','password') VALUES ('$id','$username','$email',PASSWORD('$password'))");
$returnValue = $id;
}else{
$returnValue = "No data received";
}
// Send back request in JSON format
echo json_encode($returnValue);
?>
Here is my Swift Code
let request = NSMutableURLRequest(URL: NSURL(string: "http://***************/register.php")!)
let session = NSURLSession.sharedSession()
request.HTTPMethod = "POST"
let data = "username=JoeBloggs&email=joe#bloggs.com&password=12345"
request.HTTPBody = (data as NSString).dataUsingEncoding(NSUTF8StringEncoding)
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
let task = session.dataTaskWithRequest(request) { (data, response, error) -> Void in
print(response)
let strData = NSString(data: data!, encoding: NSUTF8StringEncoding)
print(strData)
print(error)
}
task.resume()
I'm not concerned about getting a result back yet (I have that working fine). I just can't get any data to the server.
Here is the result from the above script.
Optional(<NSHTTPURLResponse: 0x7ff9b3d6ea90> { URL: http://iep.almartin.co.uk/register.php } { status code: 200, headers {
"Cache-Control" = "no-store, no-cache, must-revalidate, post-check=0, pre-check=0";
Connection = close;
"Content-Type" = "text/html; charset=UTF-8";
Date = "Tue, 01 Sep 2015 09:02:46 GMT";
Expires = "Thu, 19 Nov 1981 08:52:00 GMT";
Pragma = "no-cache";
Server = nginx;
"Set-Cookie" = "PHPSESSID=8j2d7oobg9plvdik1dcbqtoq70; path=/";
"Transfer-Encoding" = Identity;
} })
Optional(array(0) {
}
array(0) {
}
<br />
<b>Notice</b>: Undefined index: username in <b>/home/linweb34/i/iep.almartin.co.uk/user/htdocs/register.php</b> on line <b>7</b><br />
<br />
<b>Notice</b>: Undefined index: email in <b>/home/linweb34/i/iep.almartin.co.uk/user/htdocs/register.php</b> on line <b>8</b><br />
<br />
<b>Notice</b>: Undefined index: password in <b>/home/linweb34/i/iep.almartin.co.uk/user/htdocs/register.php</b> on line <b>9</b><br />
"d41d8cd98f00b204e9800998ecf8427e")
nil
As you can see both $_REQUEST and $_POST are returning empty arrays.
What am I doing wrong?
The error clearly says that there is problem with your MySQL usage.
Following are the working code template. It uses PDO for DB connection.
function __construct() {
$this->conn = new PDO('mysql:host=<your hostnam>;dbname=<dbname>', '<user>', '<pass>');
// Generate stack trace on failure.
$this->conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
/*
* Write a function and pass your variables
*/
function get_data_from_db($id,$username,$password,$email) {
$stmt = $this->conn->prepare("INSERT INTO `user`(`id`,`username`,`email`,`password`) VALUES (:id,:username,:email,PASSWORD(:password))");
$stmt->execute(array(':id' => $id, ':username' => $username, ':email' => $email, ':password' => $password));
$data = $stmt->fetchAll(PDO::FETCH_ASSOC);
$stmt->closeCursor();
return $data;
}
Now in your code, just add a function call and you are done:
if(isset($_REQUEST)){
$username = $db->escape($_REQUEST["username"]);
$email = $db->escape($_REQUEST["email"]);
$password = $db->escape($_REQUEST["password"]);
$id = MD5($email);
$result = get_result_from_db($id,$username,$password,$email);
echo json_encode($result);
}
Note : Not tested, but it should work.
Found the problem.
It seems these lines are the culprit in my app.
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
It worked fine when I removed them.
Which brings up another question, how do I set up PHP to accept header type "application/json" ?
To send JSON to a server with POST you have to put the data to be sent into a dictionary and serialize the dictionary with NSJSONSerialization
let request = NSMutableURLRequest(URL: NSURL(string: "http://***************/register.php")!)
let session = NSURLSession.sharedSession()
let postData = ["username" : "JoeBloggs", "email" : "joe#bloggs.com", "password" : "12345"]
do {
let jsonData = try NSJSONSerialization.dataWithJSONObject(postData, options: NSJSONWritingOptions())
request.HTTPMethod = "POST"
request.setValue("\(jsonData.length)", forHTTPHeaderField:"Content-Length")
request.setValue("application/json", forHTTPHeaderField:"Accept")
request.setValue("application/json", forHTTPHeaderField:"Content-Type")
request.HTTPBody = jsonData
let task = session.dataTaskWithRequest(request) { (data, response, error) -> Void in
print(response)
let strData = NSString(data: data!, encoding: NSUTF8StringEncoding)
print(strData)
print(error)
}
task.resume()
} catch let error as NSError {
print(error)
}
So I followed #vadian answer which didn't work initially. I did some research into why PHP wasn't accepting application/json.
I got it to work by using $HTTP_RAW_POST_DATA instead of $_POST or $_REQUEST in the php file.
However! $HTTP_RAW_POST_DATA is now depreciated but the following code works
$json = file_get_contents('php://input');
$obj = json_decode($json);
Seems like a PHP hack to me but at least it works.

How to set Content-Type in AFNetworking?

I want to set "application/x-www-form-urlencoded" with post method
So ,I set request.requestSerializer.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type") But When I set the request to the server the Content-Type is not change what happen?
this is error
{com.alamofire.serialization.response.error.response=<NSHTTPURLResponse: 0x7c166450> { URL: http://test.com } { status code: 404, headers {
Connection = "keep-alive";
"Content-Length" = 434;
"Content-Type" = "text/html";
Date = "Mon, 13 Jul 2015 11:18:18 GMT";
Server = "nginx/1.0.15";
} }, NSErrorFailingURLKey=http://text.com, NSLocalizedDescription=Request failed: not found (404),
this is my code:
var request = AFHTTPRequestOperationManager();
request.requestSerializer = AFHTTPRequestSerializer()
request.requestSerializer.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
request.POST(url, parameters: parameters, success: { (oper,obj) -> Void in
// do something
}) { (oper, error) -> Void in
// do something with error
}
It's exactly what the error says: your server is sending back a webpage (HTML) for a 400 status code, when you were expecting JSON.
A 400 status code is used a bad request, which is probably generated because you're sending URL-form-encoded text as application/json. What you really want is to use AFJSONRequestSerializer for your request serializer.
manager.requestSerializer = [AFJSONRequestSerializer serializer];
I am not doing any code of AFNetworking in Swift so I can't tell you code of that but you can get idea from objective-c code.
I hope it will help you.

Resources