In my current project I am using, +(void)postJSONFromURLWithString:(NSString*)urlString params:(NSDictionary*)params completion:(JSONObjectBlock)completeBlock; method to create account and log in my application for the very first time . For second time and onwards, log in call is not there, application directly opens the user's profile screen. But when I am updating user profile (name, contact number etc.), I am getting response status code 403 from by the statement
NSLog(#"Response status code = %i", (int)response.statusCode);
added in implementation of method
+(NSData*)syncRequestDataFromURL:(NSURL*)url method:(NSString*)method requestBody:(NSData*)bodyData headers:(NSDictionary*)headers etag:(NSString**)etag error:(JSONModelError**)err
403 is generally invoked due to authorization failure in server side.
Is there any way to see what are the cookies are going to server side while I am making an API call with
+(void)postJSONFromURLWithString:(NSString*)urlString params:(NSDictionary*)params completion:(JSONObjectBlock)completeBlock;?
JSONModel's built-in networking support is intentionally very basic/primitive/limited. It does not support custom authentication, cookies, etc.
You'd be best making a request with NSURLSession to get the data, then use JSONModel just for the deserialization - rather than for the whole request.
e.g.:
NSURLSession *session = [NSURLSession sharedSession];
NSURL *url = [NSURL URLWithString:#"https://example.com/mydata.json"];
NSURLSessionDataTask *task = [session dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
MyModel *obj = [[MyModel alloc] initWithData:data error:nil];
}];
[task resume];
Related
I try to download a zip-archive using NSURLSessionDataTask.
I am aware that there is a NSURLSessionDownloadTask, but the point is I want a didReceiveData callback (to show the progress).
The code is:
NSURLRequest *request = [NSURLRequest requestWithURL:#"..."
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
NSURLSessionConfiguration* config = [NSURLSessionConfiguration defaultSessionConfiguration];
NSOperationQueue *myQueue = [NSOperationQueue new];
myQueue.underlyingQueue = dispatch_get_main_queue();
NSURLSession *session = [NSURLSession sessionWithConfiguration:config
delegate:self
delegateQueue:myQueue];
NSURLSessionDataTask* task = [session dataTaskWithRequest:request
completionHandler:^( NSData *data, NSURLResponse *response, NSError *error){ ... }
[task resume];
My class conforms to NSURLSessionDataDelegate.
When I call the method, after several seconds debugger goes to completionHandler with nil data and nil error.
What am I doing wrong?
I also tried:
calling without completionHandler, then debugger goes to didReceiveResponse callback with 200 response and that's all.
using [NSOperationQueue new] for the queue
using [NSURLSession sharedSession] - didn't get any response
using [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier: #"..."] - falls saying that I can't use a completionHandler, but without it - also no response.
So I have found the answer and it's not quite obvious from documentation:
I had several callbacks, and among them didReceiveResponse.
Turns out I have to call completion handler in order for the future callbacks to work, i.e:
completionHandler(NSURLSessionResponseAllow);
And one more thing: didCompleteWithError is actually the delegate that tells about successful finish, too, although the name implies that this is the error handler.
What it means: when a download is successfully finished, this function is called with error = nil.
Hope this will be useful for somebody someday.
I have a very strange problem, in Android, the API calls take 300-500 ms while in iOS it takes 1.5-2.5 sec. I have removed dependencies like my server, device specific issue, internet connectivity etc. I have a very simple sample code hitting a sample URL and for me, it takes about 2 sec, even on the simulator.
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSLog(#"start");
// 1
NSURL *url = [NSURL URLWithString:#"https://httpbin.org/get"];
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:config];
// 2
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
[request setValue:#"" forHTTPHeaderField:#"Accept-Encoding"];
request.HTTPMethod = #"GET";
[[session dataTaskWithRequest:request
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
// Handle response here
NSLog(#"end - %ld", (long)[(NSHTTPURLResponse*)response statusCode]);
}] resume];
});
I also have tried using AFNetworking and ASSIHTTP libraries, but there is no difference. I also have checked the headers and they are the same in both Android and iOS. What am I doing something wrong here?
I think your problem is not in the network but in this line:
dispatch_async(dispatch_get_global_queue(0, 0), ^{
Can you remove it and check again?
Data task is async so you don't need to wrap it in another async block.
Also you don't need to create instance of NSURLSession for every request
You can log out the timestamp (NSLog already did) when the request generate, send, callback to analyse it.
Does the server side code do any processing based on 'user-agent'?
Is there a time difference if you open the url in iOS safari and within the app ?
You can try calling the api from postman (or another REST API test tool like firefox RESTClient) and override the user-agent to use iOS values (http://www.enterpriseios.com/wiki/UserAgent). If the time difference is still the same, theres nothing you can do in your mobile code to fix this lag.
P.S. :
1. Overriding user-agent in postman needs some tweaking : https://github.com/postmanlabs/postman-app-support/wiki/Postman-Proxy
I have implemented a program to communicate http2 using NSURLSession of iOS9, And it can communicate with my server in http2.
However, I'm having a problem with receive server_push.
I found ENABLE_PUSH value is 0 in their settings and there's no delegate in receive server push in NSURLSession...
・I think NSURLSession doesn't support server_push. Is this right?
・If it support server_push,how to use?
/**
It WORKS for post data and get response.
I don't know the code should be added here
in order to get the server_push.
I suspect that NSURLSession itself cannot receive the server_push(;_;)
**/
- (void) postData
{
NSString *urlstr = self.urlArea.text;
NSURL * url = [NSURL URLWithString:urlstr];
NSDictionary *params = #{#"data":#""};
//json to query
NSData *query = [self buildQueryWithDictionary: params];
//make request
NSMutableURLRequest *request = [NSMutableURLRequest
requestWithURL:url
cachePolicy: NSURLRequestReloadIgnoringCacheData
timeoutInterval: 10.0];
[request setHTTPMethod: #"POST"];
[request setHTTPBody: query];
//prepare session
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];
//resume
[[session dataTaskWithRequest: request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error)
{
if (response && ! error) {
NSLog(#"Data: %#", [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding]);
}else {
NSLog(#"ERR: %#", error);
}
}] resume];
}
I read this here:
The HTTP2 push mechanism is not a generic server push mechanism like
websocket or server sent events.
It is designed for a specific optimisation of HTTP conversations.
Specifically when a client asks for a resource (eg index.html) the
server can guess that it is going to next ask for a bunch of
associated resources (eg theme.css, jquery.js, logo.png, etc. etc.)
Typically a webpage can have 10s of such associated requests.
With HTTP/1.1, the server had to wait until the client actually sends
request for these associated resources, and then the client is limited
by connections to only ask for approx 6 at a time. Thus it can take
many round trips before all the associated resources that are needed
by a webpage are actually sent.
With HTTP/2, the server can send in the response to the index.html GET
push promises to tell the client that it is going to also send
theme.css, jquery.js, logo.png, etc. as if the client had requested
them. The client can then cancel those pushes or just wait for them to
be sent without incurring the extra latency of multiple round trips.
ere is a blog about the push API for HTTP2 and SPDY in jetty:
https://webtide.com/http2-push-with-experimental-servlet-api/
Solved
I received following reply from support.
iOS does not currently support this.
update
(#vin25 comment)
ios10 supports it.
I'm pretty new with security topic and I have question about it. I create application under iOS. I need to connect with some server via HTTP and then get its public key (SSL certificate). Then I need to use this public key to encrypt some of data and send them to the same server. My problem is I have no idea how to do that. Can anyone explain to me how can I obtain the public key under iOS and then use it to encrypt data?
As an example, when you use a https-prefixed url (https==http over ssl), NSURLSession will handle this for you. A simple GET will look like the code below.All the handshake, public key stuff will be handled for you.
If you use post and send data to the server, the encryption will also be handled for you if a https url is used.
// use default session configuration
NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration];
// create session without a delegate, use global operation queue
NSURLSession *session = [NSURLSession sessionWithConfiguration: defaultConfigObject delegate: nil delegateQueue: [NSOperationQueue mainQueue]];
// create a data task printing the response payload to NSLog
NSURLSessionDataTask *dataTask = [session dataTaskWithURL:[NSURL URLWithString:#"https://developer.apple.com"] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSString *responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"Response: %#", responseString);
}];
// run
[dataTask resume];
My organization has a number of different authentication methods used. One that I have been struggling with has been our apps that use Oath2 that will be expecting the Authorization header to have the token information to be stored in the HTTP Headers. I can manually put the Authorization header information for each request, but I would like this information to be automatically populated instead of manually adding it for every NSURLSession, NSURLConnection, UIWebView or [UIImage: imageFromUrl]. In Apples documentation for NSURLConnection class and NSURLSession it says that it will handle are designed to handle various aspects >of the HTTP protocol for you, including the Authentication header and they recommend not to alter this property, but it does not seem to get set for me. At a minimum I would expect that for the NSURLSession object I should only need to set it once by accessing the sharedSession and adding the header info via a setHTTPAdditionalHeaders call, but it does not seem to hold the info on the next time I access the sharedSession.
I there something I am missing here or do I need to manually populate the HTTP Header on all calls?
EDIT:
Below is a code snippet showing how I try to set the header for the session.
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
id jSONObj = [defaults objectForKey: kTokenInformation];
[config setHTTPAdditionalHeaders:#{#"Authorization": [NSString stringWithFormat:#"Bearer %#",[jSONObj valueForKeyPath:#"access_token"]]}];
session = [NSURLSession sessionWithConfiguration:config];
However, it doesn't appear that the token is present the next time I call [NSURLSession sharedSession]. So right now I have to do that every time I call the shared session. I also am unsure from the documentation how you would handle apps that maintain multiple sessions which may each require separate Auth tokens. Any thoughts what I am missing hear.
Have a look at NSURLSessionConfiguration.
For example, you could set up a singleton class that provides an NSURLSession:
// Session setup
NSString *tokenString = ...;
NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];
[sessionConfiguration setHTTPAdditionalHeaders:#{ #"X-Auth-Token" : tokenString" }];
self.session = [NSURLSession sessionWithConfiguration:sessionConfiguration];
Now, every time you need to make a request you use your session:
// Send Request
NSURLSession *session = [[SessionManager sharedManager] session];
[[session dataTaskWithURL:url
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
}] resume];
Here's a great tutorial: http://code.tutsplus.com/tutorials/networking-with-nsurlsession-part-1--mobile-21394