AFNetworking 2.0 and HTTP Basic Authentication - ios7

Can't find AFHTTPClient on AFNetworking 2.0, to use:
AFHTTPClient *client = [AFHTTPClient clientWithBaseURL:[NSURL URLWithString:#"http://examplewebsite.com]];
[client setAuthorizationHeaderWithUsername:#"username" password:#"password"];
How it needs to be manage on AFNetworking 2.0?

AFNetworking 2.0 new architecture use serializers for creating requests and parsing responses.
In order to set the authorization header, you should first initialize a request operation manager that replaces the AFHTTPClient, create a serializer and then call the dedicated method to set the header.
For example you code would become:
AFHTTPRequestOperationManager *manager = [[AFHTTPRequestOperationManager alloc] initWithBaseURL:[NSURL URLWithString:#"http://examplewebsite.com"]];
manager.requestSerializer = [AFHTTPRequestSerializer serializer];
[manager.requestSerializer setAuthorizationHeaderFieldWithUsername:#"userName" password:#"password"];
You should read the documentation and the migration guide to understand the new concepts that come with the version 2.0 of AFNetworking.

Here is an example of performing basic HTTP authentication with AFNetworking 2.0 using NSURLCredential. The advantage of this approach over using the AFHTTPRequestSerializer setAuthorizationHeaderFieldWithUsername:password: method is that you can automatically store the username and password in the keychain by changing the persistence: parameter of NSURLCredential. (See this answer.)
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
NSURLCredential *credential = [NSURLCredential credentialWithUser:#"user" password:#"passwd" persistence:NSURLCredentialPersistenceNone];
NSMutableURLRequest *request = [manager.requestSerializer requestWithMethod:#"GET" URLString:#"https://httpbin.org/basic-auth/user/passwd" parameters:nil];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
[operation setCredential:credential];
[operation setResponseSerializer:[AFJSONResponseSerializer alloc]];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"Success: %#", responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Failure: %#", error);
}];
[manager.operationQueue addOperation:operation];

As #gimenete mentions multipart requests will fail when using #titaniumdecoy credential approach as this is applied in the challenge block and the current version of AFNetworking has an issue with this. Instead of using the credential approach you can embed the authentication in the NSMutableRequest header
NSMutableURLRequest *request = [[AFHTTPRequestSerializer serializer] multipartFormRequestWithMethod:#"PUT" URLString:path parameters:myParams constructingBodyWithBlock: ^(id <AFMultipartFormData>formData) {
[formData appendPartWithFileData:imageData name:imageName fileName:imageName mimeType:#"image/jpeg"];
} error:&error];
NSString *authStr = [NSString stringWithFormat:#"%#:%#", [self username], [self password]];
NSData *authData = [authStr dataUsingEncoding:NSUTF8StringEncoding];
NSString *authValue = [NSString stringWithFormat:#"Basic %#", [authData base64EncodedString]];
[request setValue:authValue forHTTPHeaderField:#"Authorization"];
Where you will need to use a third party BASE64 encoding library such as NSData+Base64.h and .m File from Matt Gallaghers pre ARC BASE64 solution

Related

Can the file:///path/to/local/file/data.json URL be used with AFHTTPRequestOperation

Is there a way to use AFHTTPRequestOperation to retrieve the contents of a local JSON test data file? The execution of following code snippet follows the failure code block. I suspect the problem is occurring because I'm using a URL with the file:/// construct. Is this assumption correct?
/** Get JSON from the local file **/
// Create an URL object set to the JSON endpoint.
NSURL *url = [[NSURL alloc] initWithString:#"file:///Users/charlie/Desktop/Xcode%20Projects/Assets/MyProfile.json"];
// Create a URL Load Request using the NSURL.
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url];
// Create an AFHTTPRequestOperation to perform the Internet call.
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operation.responseSerializer = [AFJSONResponseSerializer serializer];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id jsonObject) {
// If the request succeeds:
NSLog(#"JSON is: %#", jsonObject);
}
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
// If the request fails:
NSLog(#"%%ViewController-E-DEBUG, JSON request failed.");
}];
// Start the request operation.
[operation start];
You can't use AFNetworking for local file data because AFNetworking is used for network task as this is not a network task so you can pick that file and parse that file locally using NSJsonSerialization.
As it is assumed that local file is in your project directory.
NSString *filePath = [[NSBundle mainBundle] pathForResource:jsonFileName ofType:#"json"];//jsonfilename is the name of your file
NSData *JSONData = [NSData dataWithContentsOfFile:filePath options:NSDataReadingMappedIfSafe error:nil];
NSDictionary *jsonObject = [NSJSONSerialization JSONObjectWithData:JSONData options:NSJSONReadingMutableContainers error:nil];

Upload PowerPoint via AFNetworking gets corrupt

I receive a successfully response when uploading a PowerPoint via the below code. It does get upload but the file is corrupt. When opening the corrupt file on the server via PowerPoint I get this message:
"PowerPoint found a problem with content in filename.pptx. PowerPoint can attempt to repair the presentation."
- (void)updateDocument:(NSString *) path parameters:(FileUploadParameters*)para success:(void (^)(void))success failure:(void (^)(NSError *error))failure
{
_postData = nil;
AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:[NSURL URLWithString:[ConfigurationUtil objectForKey:#"baseURL"]]];
_postData = [NSMutableData dataWithContentsOfFile:[path stringByStandardizingPath]];
_postData = [NSMutableData dataWithContentsOfFile:[path stringByStandardizingPath] options:NSDataReadingMapped error:nil];
NSMutableURLRequest *request = [httpClient multipartFormRequestWithMethod:HTTP_METHOD_POST
path:[self getQueryString:path parameter:para]
parameters:nil
constructingBodyWithBlock: ^(id <AFMultipartFormData>formData)
{
[formData appendPartWithFileData:_postData
name:[[path lastPathComponent] stringByDeletingPathExtension]
fileName:[[path lastPathComponent] stringByDeletingPathExtension] mimeType:#"application/powerpoint"];
}];
[request addValue:[NSString stringWithFormat:#"WRAP access_token=%#",[Tenant loadSharedTenantInstance].authToken] forHTTPHeaderField:#"Authorization"];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
if (success)
success();
}
failure:^(AFHTTPRequestOperation* operation, NSError* error)
{
if (failure)
failure(error);
}
];
[operation start];
}
Your AFNetworking code looks fine. I don't think that's the culprit.
You can use the cmp command line tool to compare the two files (the original and the upload) byte-for-byte and see if there's a difference. I think there won't be.
More likely: it's a misleading error message, and it's actually a permissions issue on the computer with Powerpoint installed, as outlined in this Microsoft Knowledge Base article.
The below code corrects the problem. It appears that appendPartWithFileData was causing the issue. It changes the filesize and that seemed to register the file as corrupt.
_postData = nil;
_postData = [NSMutableData dataWithContentsOfFile:[path stringByStandardizingPath]];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc]init];
NSString *queryString =[self getQueryString:path parameter:nil];
[request setURL:[NSURL URLWithString:queryString]];
[request setHTTPMethod:#"POST"];
[request setHTTPBody:_postData];
[request addValue:[NSString stringWithFormat:#"WRAP access_token=%#",[Tenant loadSharedTenantInstance].authToken] forHTTPHeaderField:#"Authorization"];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
if (success)
success();
}
failure:^(AFHTTPRequestOperation* operation, NSError* error)
{
if (failure)
failure(error);
}
];
[operation start];

Http Header Authentication on post request AFNetworking

I am trying to create a multipartFormRequestWithMethod using AFNetworking's AFHttpClient. It must authenticate with a ASP.NET REST service using Http Authorization Header. Therefore I pass username and password to the Http Authorization Header using setAuthorizationHeaderWithUsername:password:. In the body of the request I am passing a large file, several MBs. If the Header authentication fails, I want the request to get block and go in failure state before finishing the file send. There should be something that prevents the database send in case of authentication failure, but I cannot figure out what. In the current situation the AFHttpRequestOperation starts to send the file and notifies of the error only at the end of the file send.
This is the code:
AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:[NSURL URLWithString:#"http://v-moxdevelop/MOX.UploadDBService/UploadDB/"]];
NSString *psw = #"psw";
NSString *userName = #"username";
[httpClient setAuthorizationHeaderWithUsername:selectedLoginItem.user password:#"psw"];
NSMutableURLRequest *request = [httpClient multipartFormRequestWithMethod:#"POST" path: [NSString stringWithFormat:#"Upload/%#/%#/%#", UDID, [selectedLoginItem.firm stringByReplacingOccurrencesOfString:#"." withString:#""], [selectedLoginItem.user stringByReplacingOccurrencesOfString:#"." withString:#""]] parameters:nil constructingBodyWithBlock: ^(id <AFMultipartFormData>formData) {
[formData appendPartWithFileData:fileData name:zipFilePath fileName:[zipFilePath lastPathComponent] mimeType:#"application/zip"];
}];
[request setTimeoutInterval:INT32_MAX];
[request setCachePolicy:NSURLRequestReloadIgnoringLocalCacheData];
operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
__weak typeof(self) weakSelf = self;
[operation setUploadProgressBlock:^(NSUInteger bytesWritten, long long totalBytesWritten, long long totalBytesExpectedToWrite) {
}];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *locOperation, id responseObject) {
}failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
}];
[httpClient enqueueHTTPRequestOperation:operation];

objective-c post data & image

I am new to objective-c and I have been searching for a way to send a post request to my server (based on Rest URL) but also include an image with it... I have found many methods to post data... and methods to post just an image, but nothing that combines the two...
I am searching for a wrapper, class or library because it seems to be a tedious task to write all this from scratch. I found the "ASIHTTPRequest" but this is no longer supported, although Ic an turn off ARC, I would prefer to find something still supported...
I also found AFNetworking, which seems to still be supported but I could be wrong, I just cannot find a solution to combine VERY simply data and a profile image...
Any help is appreciated?
Should I just use the ASIHTTPRequest library... ?? Or does anyone have any sample code for the AFNetworking library?
Here is the code I am using for AFnetworking library...
NSDictionary *params = [NSDictionary dictionaryWithObjectsAndKeys:
_emailAddressField.text, #"email",
_usernameField.text, #"username",
_passwordField.text, #"password",
nil];
AFHTTPClient *client = [[AFHTTPClient alloc] initWithBaseURL:%"http://url.com/api/whatever/"];
[client postPath:#"/" parameters:params success:^(AFHTTPRequestOperation *operation, id responseObject)
{
NSString *text = [[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding];
NSLog(#"Response: %#", text);
} failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
NSLog(#"%#", [error localizedDescription]);
}];
If you're using AFNetworking, you can use multipartFormRequestWithMethod to upload an image:
// Create the http client
AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseUrl:url];
// Set parameters
NSDictionary *parameters = [NSDictionary dictionaryWithObjectsAndKeys: #"param1", #"key1", nil];
// Create the request with the image data and file name, mime type, etc.
NSMutableURLRequest *request = [httpClient multipartFormRequestWithMethod:method path:#"url/to/" parameters:parameters constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
[formData appendPartWithFileData:data name:nameData fileName:fileName mimeType:mimeType];
}];
And then you can add the upload progress block to get feedback of the upload process:
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
[operation setUploadProgressBlock:^(NSUInteger bytesWritten, long long totalBytesWritten, long long totalBytesExpectedToWrite) {
//Manage upload percentage
}];
Also, you can add setCompletionBlockWithSuccess to catch success and failure in your operation. More info can be found here. At last but not least important, add the request to the operation queue:
[httpClient enqueueHTTPRequestOperation:operation];

AFNetworking POSTing malformed JSON - single quotes and [Object] refs

I am using AFNetworking and I am trying to POST a JSON structure. The problem is that instead of something like {"my_property":"my value"}, it's formatting it as {my_property:'my_value'}. I guess the loss of the first set of quotes is OK in most cases, but I'm not sure what to do with the non-JSON single quotes and am pretty confused as to why it would generate single quotes at all given that it knows it's creating JSON from an NSDictionary. Additionally, it's including [Object] refs where I would just expect a "{". This is what the server is getting:
...
num_matches: 32,
view_instance: properties_in_view: [Object],
[ { view_instance_ctr: 0, view_id: '4e5bb37258200ed9aa000011' },
...
The target is iOS 5.0, so I'm assuming it's using NSJSONSerialization to create JSON (although I haven't tried to verify this yet). The dictionary I send validates to JSON with isValidJSONObject. If I print out the serialized version, it looks great. The simplified version of the code looks like:
NSDictionary *params = myDictionaryThatValidatesToJSON;
httpClient.parameterEncoding = AFJSONParameterEncoding;
NSMutableURLRequest *request = [httpClient
requestWithMethod:#"POST" path:#"" parameters:params];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
[operation start];
I'm hoping there's a bigDummy = NO flag I'm missing.
I think your issue is on the server side - ie. the debug you've quoted in your question is not the raw JSON text received by the server, but some reinterpretation of this that some component on the server has done.
Michael is correct. By using his code of data i'm using this to perform POST request with JSOn parameter :
// dataDictionary is your parameter dictionary
NSError *error = nil;
NSData* jsonData = [NSJSONSerialization dataWithJSONObject:dataDictionary options:NSJSONWritingPrettyPrinted error:&error];
//NSString *jsonOut = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:[NSURL URLWithString:webURL]];
[httpClient setParameterEncoding:AFFormURLParameterEncoding];
NSMutableURLRequest *request = [httpClient requestWithMethod:#"POST"
path:#"Webservice URL"
parameters:nil];
NSMutableData *body = [NSMutableData data];
[body appendData:jsonData];
[request setHTTPBody:body];
[request setHTTPMethod:#"POST"];
[request setValue:#"application/json" forHTTPHeaderField:#"Accept"];
[request setValue:#"application/json" forHTTPHeaderField:#"content-type"];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
[httpClient registerHTTPOperationClass:[AFHTTPRequestOperation class]];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
// Print the response body in text
NSLog(#"Response: %#", [[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding]);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
[operation start];