AFNetworking POST Request Sending Blank Parameters to Server - objective-c

I am trying to send a POST request to a server using AFNetworking, and everything seems to be working, i.e. the application is successfully pinging the server. However, the parameter values that it is sending are blank when it reaches the server even though after stepping through my code below using the debugger, the values appear to be being passed successfully. Any help on this would be greatly appreciated.
APIClient.m
#import "APIClient.h"
#import "AFJSONRequestOperation.h"
// Removed URL for privacy purposes.
static NSString * const kAPIBaseURLString = #"string goes here";
#implementation APIClient
+ (APIClient *)sharedClient {
static APIClient *_sharedClient;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_sharedClient = [[APIClient alloc] initWithBaseURL:[NSURL URLWithString:kAPIBaseURLString]];
});
return _sharedClient;
}
- (id)initWithBaseURL:(NSURL *)url {
self = [super initWithBaseURL:url];
if (self) {
[self registerHTTPOperationClass:[AFJSONRequestOperation class]];
// Accept HTTP Header; see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1
[self setDefaultHeader:#"Accept" value:#"application/json"];
}
return self;
}
#end
Login Method in LoginBrain.m
- (void)loginUsingEmail:(NSString *)email andPassword:(NSString *)password withBlock:(void (^)(NSDictionary *loginResults))block {
self.email = email;
self.password = password;
// Removed path for privacy purposes
[[APIClient sharedClient] postPath:#"insert path here" parameters:[NSDictionary dictionaryWithObjectsAndKeys:email, #"uname", password, #"pw", nil] success:^(AFHTTPRequestOperation *operation, id responseJSON) {
if (block) {
block(responseJSON);
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
if (block) {
block(nil);
}
}];
// Store user data in app?
}
Login Called Method in LoginViewController.m
- (IBAction)loginPressed {
[self.loginProgressIndicator startAnimating];
NSString *email = self.emailTextField.text;
NSString *password = self.passwordTextField.text;
[self.brain loginUsingEmail:email andPassword:password withBlock:^(NSDictionary *loginResults) {
[self.loginProgressIndicator stopAnimating];
[self.delegate uloopLoginViewController:self didLoginUserWithEmail:email andPassword:password];
}];
}
UPDATE
I tried changing the parameterEncoding as recommended here, but it did not fix the problem.
SECOND UPDATE
Here is the PHP code from the server side that is accessing the POST data. This was written by a co-worker of mine, as I don't do anything on the server side and am very unfamiliar with how it works.
header('Content-type: application/json');
$username = $_POST['uname'];
$pw = $_POST['pw'];
The server code is pretty straight forward. He has some sort of log script that checks to see what the variable values are, and he says that the client is hitting the server, but the variable values are blank.
THIRD UPDATE
This is a dump of the HTTP request by generating a print_r of the $_REQUEST variable:
Array ( [sid] => FwAqvZrfckw )
And here is a dump of the $_POST variable. As you can see, it's completely blank:
Array ( )
FOURTH UPDATE
I used Wireshark to capture the packet before it's being sent to the server, and everything appears to be in order:
Accept: application/json
Content-Type: application/x-www-form-urlencoded; charset=utf-8
And the POST parameters were all there as well. We also created a test file on the server side and just did a test POST to make sure that the code there is working, and it is.

Thank you.
With the same problem, using AFFormURLParameterEncoding was what I needed.
So just to simplify all the thread, you have to use :
[[APIClient sharedClient] setParameterEncoding:AFFormURLParameterEncoding];

I don't see anything in particular that would cause a problem here but I'll start off by giving you the steps I used to solve a similar problem.
To start, checkout the tool, Charles, which is a Debugging Web Proxy that will intercept the response from the server and should give you a more clear idea of what's going wrong. There's a 30 day free trial and it really helped me pick out the little bugs. To use it, press the sequence button and filter the results via your server url. From there you can see the request and response sent and received from the server. If the following doesn't fix your problem, post the request and response that Charles spits out.
Fix wise, try adding [[APIClient sharedClient] setParameterEncoding:AFJSONParameterEncoding] right before you send the POST request. It looks like yall are using JSON as the server-side format.
So in loginUsingEmail:
self.email = email;
self.password = password;
[[APIClient sharedClient] setParameterEncoding:AFJSONParameterEncoding];
[[APIClient sharedClient] postPath:#"insert path here" parameters:[NSDictionary dictionaryWithObjectsAndKeys:email, #"uname", password, #"pw", nil] success:^(AFHTTPRequestOperation *operation, id responseJSON) {
if (block) {
block(responseJSON);
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
if (block) {
block(nil);
}
}];
// Store user data in app?
}

Related

How can I check if my OS X application can connect to a specific server-- assuming there is internet connection?

I currently am using AFNetworking to determine if my application has network reachability.
NSNumber *s = notification.userInfo[AFNetworkingReachabilityNotificationStatusItem];
AFNetworkReachabilityStatus status = [s integerValue];
if (status == AFNetworkReachabilityStatusReachableViaWWAN || status == AFNetworkReachabilityStatusReachableViaWiFi) {
But, now I also need to know if my application can reach a specific server. More specifically, the server I am connecting to may be down and I need a way to determine if this is the case, from the client side, so I can notify my users appropriately.
It's a very tough google because all searches I do just point me to "How to determine network reachability". Has anybody dealt with this before, and have a solution in mind?
EDIT: #AvT recommended a promising looking solution, so I tried it like this:
self.testTSCReachabilityManager = [AFNetworkReachabilityManager managerForDomain:#"www.asdasfjsldfkjslefjslkjslfs.com"];
__weak MyObject *weakSelf = self;
[self.testReachabilityManager setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
if (weakSelf.testReachabilityManager.reachable) {
NSLog(#"YES");
}
else
{
NSLog(#"NO");
}
}];
But unfortunately, it is logging out "YES" for me, even after I have confirmed it is most definitely not reachable.
Instantiate AFNetworkReachabilityManager with class method
+ (instancetype)managerForDomain:(NSString *)domain;
and pass string with the required domain. AFNetworkReachabilityManager will check reachability of this domain.
If serverURL is an url of your server you should use it the following way:
[AFNetworkReachabilityManager managerForDomain:serverURL.host]
Update
Following code works as expected:
static AFNetworkReachabilityManager *testTSCReachabilityManager;
testTSCReachabilityManager = [AFNetworkReachabilityManager managerForDomain:#"www.asdasfjsldfkjslefjslkjslfs.com"];
[testTSCReachabilityManager setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
if (testTSCReachabilityManager.reachable) {
NSLog(#"YES");
}
else
{
NSLog(#"NO");
}
}];
[testTSCReachabilityManager startMonitoring];
Update: I actually ended up going w/ a different implementation than what Avt recommended, and did what matt recommended in the comments instead
I created an NSURLRequest and make a request to my server, then used the delegate callbacks to determine if the server was reachable. Works like a charm
-(void)checkConnectionToServers
{
NSMutableURLRequest* request = [NSMutableURLRequest new];
request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:#"www.myserver.com"] cachePolicy:0 timeoutInterval:(NSTimeInterval)5.0];
[request setHTTPMethod:#"GET"];
[NSURLConnection connectionWithRequest:request delegate:self];
}
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
NSLog(#"SUCCESS");
}
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
NSLog(#"FAIL");
}

NSURLCache: inconsistent behaviour

I was observirng some strange behaviour of my app sometime caching responses and sometime not caching them (all the responses have Cache-Control: max-age=600).
The test is simple: I did a test.php script that was just setting the headers and returning a simple JSON:
<?php
header('Content-Type: application/json');
header('Cache-Control: max-age=600');
?>
{
"result": {
"employeeId": "<?php echo $_GET['eId']; ?>",
"dateTime": "<?php echo date('Y-m-d H:i:s'); ?>'" }
}
This is the response I get from the PHP page:
HTTP/1.1 200 OK
Date: Thu, 28 Nov 2013 11:41:55 GMT
Server: Apache
X-Powered-By: PHP/5.3.17
Cache-Control: max-age=600
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: application/json
{
"result": {
"employeeId": "",
"dateTime": "2013-11-28 11:41:55'"
}
}
Then I've created a simple app and added AFNetworking library.
When I call the script with few parameters, the cache works properly:
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
NSDictionary *params = #{
#"oId": #"4011",
#"eId": self.firstTest ? #"1" : #"0",
#"status": #"2031",
};
[manager GET:#"http://www.mydomain.co.uk/test.php" parameters:params success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"JSON: %#", responseObject);
NSLog(#"Cache current memory usage (after call): %d", [cache currentMemoryUsage]);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
But when I increase the number of parameters, like:
NSDictionary *params = #{
#"organizationId": #"4011",
#"organizationId2": #"4012",
#"organizationId3": #"4013",
#"organizationId4": #"4014",
#"organizationId5": #"4015",
#"organizationId6": #"4016",
#"eId": self.firstTest ? #"1" : #"0",
#"status": #"2031",
};
it doesn't work anymore and it execute a new request each time it is called.
I've done many tests and it seems to me that it is related to the length of the URL, because if I includes this set of params:
NSDictionary *params = #{
#"oId": #"4011",
#"oId2": #"4012",
#"oId3": #"4013",
#"oId4": #"4014",
#"oId5": #"4015",
#"oId6": #"4016",
#"eId": self.firstTest ? #"1" : #"0",
#"status": #"2031",
};
It works!!
I've done many tests and that's the only pattern I've found...
To exclude AFNetworking from the equation, I've created another test program that uses NSURLConnection only and I can see the same behaviour so it's not AFNetworking and definitely NSURLCache. This is the other test:
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"http://www.mydomain.co.uk/test.php?eId=%#&organizationId=4011&organizationId2=4012&organizationId3=4013&organizationId4=4014&organizationId5=4015&organizationId6=4016", self.firstTest ? #"1" : #"0"]]; // doesn't work
//NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"http://www.mydomain.co.uk/test.php?eId=%#&oId=4011&oId2=4012&oId3=4013&oId4=4014&oId5=4015&oId6=4016", self.firstTest ? #"1" : #"0"]]; // work
//NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"http://www.mydomain.co.uk/test.php?eId=%#", self.firstTest ? #"1" : #"0"]]; // work
NSURLRequest *request = [NSURLRequest requestWithURL:url];
NSURLResponse *response = nil;
NSError *error = nil;
NSData *data = [NSURLConnection sendSynchronousRequest:request
returningResponse:&response
error:&error];
if (error == nil) {
// Parse data here
NSString *responseDataStr = [NSString stringWithUTF8String:[data bytes]];
NSLog(#"Response data: %#", responseDataStr);
}
I've also tried to establish how many characters in the URL will trigger the problem but even in this case I've got strange results:
This one is 112 characters long and it doesn't work:
http://www.mydomain.co.uk/test.php?eId=1&organizationId=4011&organizationId2=4012&organizationId3=4013&orgaId4=4
This one is 111 characters long and it works:
http://www.mydomain.co.uk/test.php?eId=1&organizationId=4011&organizationId2=4012&organizationId3=4013&orgId4=4
Ive renamed the PHP script to see if the first part of the URL would matter and I've got a strange behaviour again:
This one is 106 characters long and it doesn't work:
http://www.mydomain.co.uk/t.php?eId=1&organizationId=4011&organizationId2=4012&organizationId3=4013&org=40
This one is 105 characters long and it works:
http://www.mydomain.co.uk/t.php?eId=1&organizationId=4011&organizationId2=4012&organizationId3=4013&org=4
So I've removed 3 characters from the page name and I've got a working threshold 6 characters lower.
Any suggestion?
Thanks,
Dem
I am witnessing something similar with certain responses not being cached by NSURLCache and I have come up with another possible reason:
In my case I have been able to ascertain that the responses not being cached are the ones that are returned using Chunked transfer-encoding. I've read elsewhere that NSURLCache should cache those after iOS 6 but for some reason it doesn't in my case (iOS 7.1 and 8.1).
I see that your example response shown here, also has the Transfer-Encoding: chunked header.
Could it be that some of your responses are returned with chunked encoding (those that are not cached) and some are not (those that are cached)?
My back-end is also running PHP on Apache and I still can't figure out why it does that...
Probably some Apache extension...
Anyway, I think it sounds more plausible than the request URL length scenario.
EDIT:
It's been a while, but I can finally confirm that in our case, it is the chunked transfer encoding that causes the response not to be cached. I have tested that with iOS 7.1, 8.1, 8.3 and 8.4.
Since I understand that it is not always easy to change that setting on your server, I have a solution to suggest, for people who are using AFNetworking 2 and subclassing AFHTTPSessionManager.
You could add your sub-class as an observer for AFNetworking's AFNetworkingTaskDidCompleteNotification, which contains all the things you will need to cache the responses yourself. That means: the session data task, the response object and the response data before it has been processed by the response serializer.
If your server uses chunked encoding for only a few of its responses, you could add code in -(void)didCompleteTask: to only cache responses selectively. So for example you could check for the transfer-encoding response header, or cache the response based on other criteria.
The example HTTPSessionManager sub-class below caches all responses that return any data:
MyHTTPSessionManager.h
#interface MyHTTPSessionManager : AFHTTPSessionManager
#end
MyHTTPSessionManager.m
#import "MyHTTPSessionManager.h"
#implementation MyHTTPSessionManager
+ (instancetype)sharedClient {
static MyHTTPClient *_sharedClient = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[[NSNotificationCenter defaultCenter] addObserver:_sharedClient selector:#selector(didCompleteTask:) name:AFNetworkingTaskDidCompleteNotification object:nil];
});
return _sharedClient;
}
- (void)didCompleteTask:(NSNotification *)notification {
NSURLSessionDataTask *task = notification.object;
NSHTTPURLResponse *response = (NSHTTPURLResponse *)task.response;
NSData *responseData = notification.userInfo[AFNetworkingTaskDidCompleteResponseDataKey];
if (!responseData.length) {
// Do not cache empty responses.
// You could place additional checks above to cache responses selectively.
return;
}
NSCachedURLResponse *cachedResponse = [[NSCachedURLResponse alloc] initWithResponse:response data:responseData];
[[NSURLCache sharedURLCache] storeCachedResponse:cachedResponse forRequest:task.currentRequest];
}
I tried to come up with some sort of cleaner solution, but it seems that AFNetworking does not provide a callback or a delegate method that returns everything we need early enough - that is, before it has been serialized by the response serializer.
Hope people will find this helpful :)
Did you try to configure
NSURLRequestCachePolicy
for NSURLRequest
+ (id)requestWithURL:(NSURL *)theURL cachePolicy:(NSURLRequestCachePolicy)cachePolicy timeoutInterval:(NSTimeInterval)timeoutInterval
These constants are used to specify interaction with the cached responses.
enum
{
NSURLRequestUseProtocolCachePolicy = 0,
NSURLRequestReloadIgnoringLocalCacheData = 1,
NSURLRequestReloadIgnoringLocalAndRemoteCacheData =4,
NSURLRequestReloadIgnoringCacheData = NSURLRequestReloadIgnoringLocalCacheData,
NSURLRequestReturnCacheDataElseLoad = 2,
NSURLRequestReturnCacheDataDontLoad = 3,
NSURLRequestReloadRevalidatingCacheData = 5
};
typedef NSUInteger NSURLRequestCachePolicy;
You could investigate what your cached response is from the sharedURLCache by subclassing NSURLProtocol and overriding startLoading:
add in AppDelegate application:didFinishLaunchingWithOptions:
[NSURLProtocol registerClass:[CustomURLProtocol class]];
Then create a subclass of NSURLProtocol (CustomURLProtol) and override startLoading
- (void)startLoading
{
self.cachedResponse = [[NSURLCache sharedURLCache] cachedResponseForRequest:self.request];
if (self.cachedResponse) {
[self.client URLProtocol:self
didReceiveResponse:[self.cachedResponse response]
cacheStoragePolicy:[self.cachedResponse storagePolicy]];
[self.client URLProtocol:self didLoadData:[self.cachedResponse data]];
}
[self.client URLProtocolDidFinishLoading:self];
}
self.cachedResponse is a property NSCachedURLResponse i've added. You can see if anything is wrong with any cachedResponse here.

ConnectionKit and SFTP: How to authenticate CK2FileManager

For my Mac OS X Cocoa app, I am trying to
connect to a SFTP server that only accepts username/password credentials
get the contents of a remote directory
upload files
and find it surprisingly complicated.
After trying ConnectionKit (nearly no documentation), NMSSH (crashed once too often with simultaneous uploads), rsync (not supported by the server), sftp (needs key authentication if scripted, doesn't work with username/password), I am now back to ConnectionKit: https://github.com/karelia/ConnectionKit
However, I am struggling with the authentication challenge, as I don’t know what to do with my credential in the delegate method.
I downloaded and compiled ConnectionKit (apparently version 2).
I am trying to use CK2FileManager as the Readme indicates (is this the right approach at all? Or should I use the libssh2_sftp-Cocoa-wrapper instead?… however I had troubles with libssh2 blocking methods in NMSSH before)
I am successfully setting up my connection URL and
my delegates' -didReceiveAuthenticationChallenge is called
But this is where I struggle: I know how to create a NSURLCredential, however, I can’t figure out what to do with it =>
- (void)fileManager:(CK2FileManager *)manager
didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
NSURLCredential *credentials = [NSURLCredential
credentialWithUser:self.username
password:[self getPassword]
persistence:NSURLCredentialPersistenceForSession];
// what to do now?
// [manager useCredential:] doesn’t exist, nor is there a manager.connection?
// ...
}
I already read the header, I searched the archives of this list, but all answers seem to be outdated.
I also searched Google, Bing and StackOverflow and found one promising example from 2011 using CKFTPConnection, which doesn’t seem to be included in the current framework anymore.
Thanks so much for any pointer to the right direction.
tl;dr
I don't know how to respond to ConnectionKit's CK2FileManager authenticationChallenge:
see the comment in the code example
For CK2:
- (void)listDirectoryAtPath:(NSString *)path
{
// path is here #"download"
NSURL *ftpServer = [NSURL URLWithString:#"sftp://companyname.topLevelDomain"];
NSURL *directory = [CK2FileManager URLWithPath:path isDirectory:YES hostURL:ftpServer];
CK2FileManager *fileManager = [[CK2FileManager alloc] init];
fileManager.delegate = self;
[fileManager contentsOfDirectoryAtURL:directory
includingPropertiesForKeys:nil
options:NSDirectoryEnumerationSkipsHiddenFiles
completionHandler:^(NSArray *contents, NSError *error) {
if (!error) {
NSLog(#"%#", contents);
} else {
NSLog(#"ERROR: %#", error.localizedDescription);
}
}];
}
and than you have to implement the following protocol
- (void)fileManager:(CK2FileManager *)manager operation:(CK2FileOperation *)operation
didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
completionHandler:(void (^)(CK2AuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler
{
if (![challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodDefault]) {
completionHandler(CK2AuthChallengePerformDefaultHandling, nil);
return;
}
NSString * username = #"<username>";
NSString * pathToPrivateSSHKey = #"</Users/myNameOnLocalMaschine/.ssh/id_rsa>"
NSURLCredential *cred = [NSURLCredential ck2_credentialWithUser:username
publicKeyURL:nil
privateKeyURL:[NSURL fileURLWithPath:pathToPrivateSSHKey]
password:nil
persistence:NSURLCredentialPersistenceForSession];
completionHandler(CK2AuthChallengeUseCredential, cred);
}
That's it.
Call -listDirectoryAtPath: and then you will get in the Completion Handler Block in contents array all the files located on the given path :)
Okay, that was easy and I could have found out that on my own; just for the reference: [[challenge sender] useCredential:credentials forAuthenticationChallenge:challenge];
Sorry to reward myself for my own question, but maybe this code snippet helps filling the missing docs, this is how I connect to my SFTP server with ConnectionKit:
- (void)connectWithCompletionBlock:(void (^)(void))completionBlock {
if(!self.cFileManager) {
self.cFileManager = [[CK2FileManager alloc] init];
self.cFileManager.delegate = self;
}
NSURL *sftpServer = [NSURL URLWithString:[#"sftp://" stringByAppendingString:self.server]];
self.remoteFolder = [CK2FileManager URLWithPath:self.remotePath relativeToURL:sftpServer];
// try to get the contents of the current directory
[self.cFileManager contentsOfDirectoryAtURL:self.remoteFolder
includingPropertiesForKeys:nil
options:NSDirectoryEnumerationSkipsHiddenFiles
completionHandler:^(NSArray *contents, NSError *error)
{
NSLog(#"remote folder contents: \n%#", contents);
// invoke completion block
completionBlock();
}];
}
- (void)fileManager:(CK2FileManager *)manager
didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
NSURLCredential *credentials = [NSURLCredential
credentialWithUser:self.username
password:[self getPassword]
persistence:NSURLCredentialPersistenceForSession];
[[challenge sender] useCredential:credentials forAuthenticationChallenge:challenge]
}

POST request with AFNetworking 2.0 - AFHTTPSessionManager

Hej,
I am struggling with doing a POST request to the parse REST API. I am using AFNetworking 2.0. My code for the AFHTTPSessionManager Subclass looks as follows:
+ (ParseAPISession *)sharedSession {
static ParseAPISession *sharedSession = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedSession = [[ParseAPISession alloc] initWithBaseURL:[NSURL URLWithString:kSDFParseAPIBaseURLString]];
});
return sharedSession;
}
And:
- (id)initWithBaseURL:(NSURL *)url {
self = [super initWithBaseURL:url];
if (self) {
[self.requestSerializer setValue:kSDFParseAPIApplicationId forHTTPHeaderField:#"X-Parse-Application-Id"];
[self.requestSerializer setValue:kSDFParseAPIKey forHTTPHeaderField:#"X-Parse-REST-API-Key"];
}
return self;
}
I am doing the request like this:
[[ParseAPISession sharedSession] POST:#"ClassName" parameters: [NSDictionary dictionaryWithObjectsAndKeys:#"name", #"name", nil]
success:^(NSURLSessionDataTask *task, id abc) {
NSLog(#"%#", abc);
} failure:^(NSURLSessionDataTask *task, NSError *error) {
NSLog(#"%#", error);
}];
Doing this I always get this kind of error:
Error Domain=NSCocoaErrorDomain Code=3840 "The operation couldn’t be completed. (Cocoa error 3840.)" (JSON text did not start with array or object and option to allow fragments not set.) UserInfo=0x8c72420 {NSDebugDescription=JSON text did not start with array or object and option to allow fragments not set.}
Since the GET Request works like a charm I am quite confused why I can’t POST something. Can anybody halp me with this problem?
Best regards!
UPDATE
Happily after testing around a lot this Error message isn't displayed anymore, unfortuatelly another appeared:
<NSHTTPURLResponse: 0x8b96d40>
{ URL: https://api.parse.com/1/users }
{ status code: 400,
headers {
"Access-Control-Allow-Origin" = "*";
"Access-Control-Request-Method" = "*";
"Cache-Control" = "no-cache";
Connection = "keep-alive";
"Content-Length" = 130;
"Content-Type" = "application/json; charset=utf-8";
Date = "Wed, 30 Oct 2013 20:01:58 GMT";
Server = "nginx/1.4.2";
"Set-Cookie" = "_parse_session=BAh7BkkiD3Nlc3Npb25faWQGOgZFRiIlNjIxZjUxMzY3NWVhZWJmMDYyYWYwMGJiZTQ3MThmMWE%3D--851bd31b07e7dba2c5f83bb13a8d801ecbea42c4; domain=.parse.com; path=/; expires=Fri, 29-Nov-2013 20:01:58 GMT; secure; HttpOnly";
Status = "400 Bad Request";
"X-Runtime" = "0.060910";
"X-UA-Compatible" = "IE=Edge,chrome=1";
} }
Can anyone tell me what the Status: 400 Bad Request is telling me and how I can get rid of it?
This error means that your POST request went through, the server is successfully returning you some data, which NSJSONSerialization is having trouble parsing.
You probably need to set your AFJSONResponseSerializer to allow JSON fragments.
In the init method of your AFHTTPSessionManager subclass:
AFJSONResponseSerializer *responseSerializer = [AFJSONResponseSerializer serializerWithReadingOptions:NSJSONReadingAllowFragments];
[self setResponseSerializer:responseSerializer];
If this doesn't work, you probably have an encoding issue. From the NSJSONSerialization class reference:
The data must be in one of the 5 supported encodings listed in the JSON specification: UTF-8, UTF-16LE, UTF-16BE, UTF-32LE, UTF-32BE. The data may or may not have a BOM. The most efficient encoding to use for parsing is UTF-8, so if you have a choice in encoding the data passed to this method, use UTF-8.
Check the encoding type sent by your server.
Finally, you can either set breakpoints inside of AFNetworking, or set up AFNetworkActivityLogger, which will log requests as they are sent and received to your console. This tool is incredibly helpful for debugging this type of issue.
This worked for me :
in the AFHTTPSessionManager subclass initialise it with the following serialisers:
[self setRequestSerializer:[AFHTTPRequestSerializer serializer]];
[self setResponseSerializer:[AFJSONResponseSerializer serializer]];

Download file (using NSURLDownload) after Login (using POST Request)

I am trying to download a file using NDURL Download. For that, I have to log in to a site.
I do this using a NSMutableURLRequest that I send using sendSynchronousRequest of NSURLConnection
The data that I receive from that message call is indeed the html page confirming my successful login.
To download the file I use the following code:
NSURLRequest *theRequest = [NSURLRequest requestWithURL:[NSURL URLWithString: #"http://www.domain.com/getfile.php?file=1"]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
// Create the connection with the request and start loading the data.
NSURLDownload *theDownload = [[NSURLDownload alloc] initWithRequest:theRequest
delegate:self];
if (theDownload) {
// Set the destination file.
NSLog(#"Starting Download...");
NSLog(#"%#", [theDownload description]);
[theDownload setDestination:destinationFilename allowOverwrite:YES];
pathToZipFile = destinationFilename;
} else {
NSLog(#"Download failed...");
return nil;
}
But the data I receive is the HTML page telling me I have to be logged in to download the file.
Any idea on this one?
Does the NSURLDownload have an different session than the NSURLConnection?
Thanks in advance!
Okey, so you have logged in and then you trying to download a file. But how the server knows you are the same user that has logged in before?
There are different ways how it can know it. Some cookie, some request parameter, some HTTP header. But you have to add something to the request, that says "I am the user that has logged in a minute ago".
I feel you have to implement delegates for NSURLDownload, like this :
- (void)downloadDidBegin:(NSURLDownload *)download{
}
- (void)download:(NSURLDownload *)download didReceiveResponse:(NSURLResponse *)response{
_totalLength = response.expectedContentLength;
}
- (void)download:(NSURLDownload *)download willResumeWithResponse:(NSURLResponse *)response fromByte:(long long)startingByte{
}
- (void)download:(NSURLDownload *)download didReceiveDataOfLength:(NSUInteger)length{
_recievedLength = _recievedLength + length;
}
- (void)downloadDidFinish:(NSURLDownload *)download{
//Completed//
}
- (void)download:(NSURLDownload *)download didFailWithError:(NSError *)error{
//Error
}