Converting a Base64 string in an asynchronous call in IOS - session

I have this NSURLSessionDataTask and I'm getting a Base64 string from the completionHandler. I'm having trouble converting it back into plaintext using the NS Encoding libraries even after looking up various posts.
Decode a Base64 string in objective-c ,
Base64 Decoding in iOS 7+ ,
Convert between UIImage and Base64 string
String from completionHandler^(Data) = InsnYWN0aW9uJzondGVzdCcsICdpbnB1dCc6J3Rlc3QnfSI=
Code used to try and decode:
NSString *baseString =[data base64EncodedStringWithOptions:NSDataBase64Encoding76CharacterLineLength];
I was hoping someone could lead me in the right direction. Thanks.
Full Function - inspired by (http://hayageek.com/ios-nsurlsession-example/):
-(void) httpPostWithCustomDelegate
{
NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *defaultSession = [NSURLSession sessionWithConfiguration: defaultConfigObject delegate: nil delegateQueue: [NSOperationQueue mainQueue]];
NSURL * url = [NSURL URLWithString:#"http://XXX.XXX.XXX.XXX"];
NSMutableURLRequest * urlRequest = [NSMutableURLRequest requestWithURL:url];
NSData * params =[#"{'action':'test', 'input':'test'}" dataUsingEncoding:NSUTF8StringEncoding];
NSString * newParams = [params base64EncodedStringWithOptions:0];
[urlRequest setHTTPMethod:#"POST"];
[urlRequest setHTTPBody:[newParams dataUsingEncoding:NSUTF8StringEncoding]];
NSURLSessionDataTask * dataTask =[defaultSession dataTaskWithRequest:urlRequest
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
//NSLog(#"Response:%# %#\n", response, error);
if(error == nil)
{
NSString *baseString =[data base64EncodedStringWithOptions:NSDataBase64Encoding76CharacterLineLength];
//NSString *baseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"Data = %#",baseString);
}
}];
[dataTask resume];
}

data contains the base64 encoded string (which represented data that represented some original object). So you need to convert data to the actual NSData representing whatever it was that was originally encoded.
Basically you need to reverse the original encoding steps.
If you are using iOS 7 or later you can do:
NSURLSessionDataTask *dataTask = [defaultSession dataTaskWithRequest:urlRequest
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
//NSLog(#"Response:%# %#\n", response, error);
if (data) {
NSData *originalData = [[NSData alloc] initWithBase64EncodedData:data options:0];
// Do something with the decoded data
} else {
NSLog(#"error = %#", error);
}
}];

Related

NSURLSession request HTTPBody becomes nil in Custom NSURLProtocol

In my application, I am performing POST using NSURLSession.
Steps followed:
Setting Header
Setting HTTPBody
Making POST request using NSURLSession.
The code is:
NSDictionary *parameters = #{ #"searchTerm": #"shampoo", #"sort": #"Most Reviewed" };
NSError *error = nil;
NSData *postData = [NSJSONSerialization dataWithJSONObject:parameters options:NSJSONWritingPrettyPrinted error:&error];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:#"SomeURL"]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:10.0];
[request setHTTPMethod:#"POST"];
[request setAllHTTPHeaderFields:headers];
request.HTTPBody = postData;
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error) {
NSLog(#"%#", error);
} else {
NSLog(#"Pass");
}
}];
[dataTask resume];
Now in custom NSURLProtocol class:
(BOOL)canInitWithRequest:(NSURLRequest *)request {
if ([request.HTTPMethod isEqualToString:#"POST"]) {
//here request.HTTPMethod is coming nil
//Whereas my requirement is to get request.HTTPMethod which got request parameter.
return YES;
}
return NO;
}
Thanks in advance.
IIRC, body data objects get transparently converted into streaming-style bodies by the URL loading system before they reach you. If you need to read the data:
Open the HTTPBodyStream object
Read the body data from it
There is one caveat: the stream may not be rewindable, so don't pass that request object on to any other code that would need to access the body afterwards. Unfortunately, there is no mechanism for requesting a new body stream, either (see the README file from the CustomHTTPProtocol sample code project on Apple's website for other limitations).

NSURLSessionDownloadTask is not sending cookie in the request

I need to send a cookie in the request. But seems the cookie is not send. What is wrong I am doing here,
// set the cookie for getdoc request url
if (request.cookie)
{
NSDictionary *cookieProperties = #{NSHTTPCookieName : #"GetDoc",
NSHTTPCookieValue : request.cookie,
NSHTTPCookieDomain : [NSURL URLWithString:request.url].host,
// NSHTTPCookieOriginURL: request.url,
NSHTTPCookiePath : #"/",
// NSHTTPCookieVersion : #"1",
NSHTTPCookieExpires : [[NSDate date] dateByAddingTimeInterval:60*60*24*30]
};
NSHTTPCookie *cookie = [NSHTTPCookie cookieWithProperties:cookieProperties];
[[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookie:cookie];
}
NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration];
// NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfig];
NSURLSession *session = [NSURLSession sharedSession];
__block NSData *documentData = nil;
__block NSString *mimeType = nil;
DLog(#"COOKIES: %#", [NSHTTPCookieStorage sharedHTTPCookieStorage].cookies);
// retrieve the doc from url
// block the call to wait for response for kMaxBlockingTimeHttpSeconds
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
NSURLSessionDownloadTask *getDocTask = [session downloadTaskWithURL:[NSURL URLWithString:request.url]
completionHandler:^(NSURL *location,
NSURLResponse *response,
NSError *error)
{
if (error) {
NSLog(#"Error retrieving document from %#, Error: %#",
request.url, error);
res.errorCode = SCPErrorDocumentGetError;
res.errorMessage = [error localizedDescription];
} else {
mimeType = response.MIMEType;
documentData = [NSData dataWithContentsOfURL:location];
}
dispatch_semaphore_signal(sema);
}];
[getDocTask resume];
dispatch_time_t timeout = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(kMaxBlockingTimeHttpSeconds * NSEC_PER_SEC));
dispatch_semaphore_wait(sema, timeout);
if (!documentData) {
DLog(#"Response: %#", [res jsonDict]);
self.data = [NSJSONSerialization dataWithJSONObject:[res jsonDict] options:NSJSONWritingPrettyPrinted error:nil];
return;
}
NSString *str = [[NSString alloc] initWithData:documentData encoding:NSISOLatin1StringEncoding];
DLog(#"%#", str);
The NSLog printout of the cookie is,
"",
But this is not sent in the request header.
Adding the cookie header directly in the sessionConfig worked for me. But why did not the shareCookie work. This is supposed to work according the the documentation.
NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration];
sessionConfig.HTTPAdditionalHeaders = #{#"Cookie" : request.cookie};

Unsupported URL on ios 8

I'm trying to fetch a json from google places with the following code:
NSString *query = [NSString stringWithFormat:#"https://maps.googleapis.com/maps/api/place/search/json?location=%f,%f&radius=%i&types=%#&sensor=true&key=%#", center.latitude, center.longitude, rad, types, kGOOGLE_API_KEY];
NSLog(#"%#",query);
NSURL *googleRequestURL=[NSURL URLWithString:query];
[NSURLConnection sendAsynchronousRequest:[[NSURLRequest alloc] initWithURL:googleRequestURL] queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
if (error) {
NSLog(#"Error fetching data: %#",[error description]);
} else {
//To-do
}
}];
The resulting url is: https://maps.googleapis.com/maps/api/place/search/json?location=37.337566,-122.041202&radius=1000&types=accounting|bowling_alley|doctor&sensor=true&key=MY_KEY
(my key is ommitted for obsious reasons)
Which works fine from my laptop's browser, but return the error:
Error Domain=NSURLErrorDomain Code=-1002 "unsupported URL" UserInfo=0x7fe47bc138f0 {NSLocalizedDescription=unsupported URL, NSUnderlyingError=0x7fe47be9dbe0 "unsupported URL"}
I tried using http instead of https (in the browser it returns a json with some error message, but still returns something) with no success.
What am I doing wrong?
This is how I got it resolved. Good Luck!
NSString *google = #"https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=%f,%f&radius=500&types=%#&key=%#";
NSString *link = [NSString stringWithFormat:google, coordinate.latitude, coordinate.longitude, types, GOOGLE_KEY];
NSURL *url = [NSURL URLWithString:[link stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
NSMutableURLRequest *request =[NSMutableURLRequest requestWithURL:url];

Simple example of NSURLSession with authentication

I have written a REST service that serves up some data. It is passcode protected.
I am trying to write a background process that will grab the data and stuff it into a sqlLite db I have in the app.
I did this initially without authentication using :
- (void) callWebService {
dispatch_sync(kBgQueue, ^{
NSData* data = [NSData dataWithContentsOfURL:
scoularDirectoryURL];
[self performSelectorOnMainThread:#selector(fetchedData:) withObject:data waitUntilDone:YES];
});
}
This worked fine but I don't think I can add authentication to that. If I can I would just use that.
What I am looking for is a nice, simple explanation of NSURLSession using user/password authentication.
I think your question is vague and underspecified. That said, here's one solution, from here:
-(void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)( NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler
{
if (_sessionFailureCount == 0) {
NSURLCredential *cred = [NSURLCredential credentialWithUser:self.userName password:self.password persistence:NSURLCredentialPersistenceNone];
completionHandler(NSURLSessionAuthChallengeUseCredential, cred);
} else {
completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil);
}
_sessionFailureCount++;
}
I strongly recommend that you read and re-read the Apple docs on this.
For me the following code works:
NSString *userName=#"user:";
NSString *userPassword=#"password";
NSString *authStr= [userName stringByAppendingString:userPassword];
NSString *url=#"http://000.00.0.0:0000/service.json";
NSData *authData = [authStr dataUsingEncoding:NSUTF8StringEncoding];
NSString *authValue = [NSString stringWithFormat: #"Basic %#",[authData base64EncodedStringWithOptions:0]];
NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]];
[request setValue:authValue forHTTPHeaderField:#"Authorization"];
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse *response,
NSData *data, NSError *connectionError)
NSDictionary *theDictionary = [NSJSONSerialization JSONObjectWithData:data
options:0
error:NULL];
NSDictionary *host = [theDictionary objectForKey : #"host"];
// json nested
self.label.text = [host objectForKey:#"key1"];
self.label.text = [host objectForKey:#"key2"];
regards

send parameter values and retrieve an xml file Xcode

In my current xcode project, I need to send parameter values to a url and need to retrieve an xml file based on the parameter values sent.
I tried the below code but it's not working:
(IBAction)myButtonClick:(id)sender
{
NSURL *oRequestURL =
[NSURL URLWithString:#"http://xyz .com/air/1.0/search?from=MAA&to=CJB&depart-date=2012-06-30&adults=2&children=2&infants=1&way=one&cabin-type=Economy&sort=asc"];
NSMutableURLRequest *oRequest = [[[NSMutableURLRequest alloc]init]autorelease];
[oRequest setHTTPMethod:#"POST"];
[oRequest setURL: oRequestURL];
NSMutableData *oHttpBody = [NSMutableData data];
[oHttpBody appendData:[#"This is HTTP Request body" dataUsingEncoding:NSUTF8StringEncoding]];
[oRequest setValue:[oHttpBody length] forHTTPHeaderField:#"Content-Length"];
NSError *oError = [[NSError alloc]init];
NSHTTPURLResponse *oResponseCode = nil;
NSData *oResponseData = [NSURLConnection sendSynchronousRequest:oRequest returningResponse:oResponseCode error:oError];
if ([oResponseCode statusCode]> 200) {
NSLog(#"Status code is greater than 200");
}
NSString *strResult=[[NSString alloc]initWithData:oResponseData encoding:NSUTF8StringEncoding];
NSLog(#"The result is %s",strResult);
}
I have searched many sites and books but could not find a solution.
Would be of great help if a link to a tutorial or some other useful resource can be provided. Appreciate your great help.
Thank You.
Hi,
I have found the solution. The code is as below. Hope it helps someone else:)
- (IBAction)myButtonPressed:(id)sender
{
NSString *urlAsString = #"http://api.abc.com/air/1.0/search?from=MAA&to=CJB&depart-date=2012-09-30&adults=2&children=2&infants=1&way=one&cabin-type=Economy&sort=asc";
NSURL *url = [NSURL URLWithString:urlAsString];
NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:url];
[urlRequest setValue:#"2193141de2g7e2a34bb19bc3aa52b3b5" forHTTPHeaderField:#"X-XX-API-KEY"];
[urlRequest setTimeoutInterval:30.0f];
[urlRequest setHTTPMethod:#"GET"];
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
[NSURLConnection
sendAsynchronousRequest:urlRequest queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error)
{
if ([data length]>0 &&
error == nil)
{
NSString *html = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"HTML = %#", html);
}
else if ([data length]== 0 && error==nil) {
NSLog(#"Nothing was downloaded");
}
else if (error!= nil) {
NSLog(#"Error occured = %#", error);
}
}];
}

Resources