iOS10 NSURLSession HTTP/2 Invalid - ios10

NSURLSession Request HTTP/2.0
working in iOS9.
but invalid in iOS10
my code :
NSURLSession *session = [NSURLSession sharedSession];
request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:#"https://ga.seeyouyima.com/page"]];
[request setHTTPMethod:#"POST"];
[[session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (completedBlock) {
completedBlock(data, response, error);
}
}] resume];

It looks like Charles Proxy 4 will cause iOS 10 to not use HTTP/2. It seems to work fine with iOS 9.
You can demonstrate this by loading the Akamai HTTP/2 demo in Mobile Safari in iOS 10:
https://http2.akamai.com/demo
If you enable Charles Proxy while visiting the site it will report to you that your browser does not support HTTP/2.

Related

how to compress request using ASIFormDataRequest?

I'm trying to to send some post data to a Apache server from iPad application using the ASIHttp library.
actually I need to send huge data to the server and that means I need to compress the request body so I write some code to send the data and compress the request BUT there are no parameters received on the server !!!
the iOS code is :
NSURL * URL = [NSURL URLWithString:myURL];
ASIFormDataRequest *ASIRequest = [ASIFormDataRequest requestWithURL:URL];
ASIRequest.shouldCompressRequestBody=YES;
ASIRequest setPostValue:data forKey:#"data"];
[ASIRequest startSynchronous];
NSError *error = [ASIRequest error];
if (!error) {
NSString *response = [ASIRequest responseString];
NSLog(#"response %#" , response);
}
PS: if I removed the ASIRequest.shouldCompressRequestBody=YES; everything works fine and I can see the data but when use it I see nothing on the server
the request can be seen on the server but with no parameter
noway to send such data over GET method.
the server configuration are fine.
any solution ? any comment or idea can help ?
By default, most web servers do not support compression on POSTs. The accepted answer here does a really good job explainining it: Why can't browser send gzip request?
According to official documentation, this feature has only been tested with Apache servers.
EDIT:
Here is a code snipt that compresses the actual post data:
if ([self shouldCompressRequestBody]) {
NSError *err = nil;
NSData *compressedBody = [ASIDataCompressor compressData:[self postBody] error:&err];
if (err) {
[self failWithError:err];
return;
}
[self setCompressedPostBody:compressedBody];
[self setPostLength:[[self compressedPostBody] length]];
}
Source: http://forums.three20.info/discussion/77/tturlrequest-vs-asihttprequest/p1

why can't my iphone app connect to my server?

i have a weird problem. so i've been working on an iphone app where a user can login, and upon logging in, the app would authorize the user by making an http GET request to the server. if the username and password is correct it return an authorization token (typical stuff).
the weird part is that when i test this locally, pointing the http request url to my local machine, it works fine. everything authorizes correctly and all data is returned correctly.
but today, i got the app stable enough that i decided to deploy rest api to my server, but when changed the http request url to my server url, the requests fails.
i thought maybe the server wasn't deployed correctly so i tested the http endpoints with the firefox rest client and everything seems to be working, authorization works, and data gets returned.
does anyone have any thoughts? i'm lost as to what the problem might be.
i'm using AFNetworking library to make the requests.
here's my code:
self.apiHttpClient = [[TKRHttpClient alloc] initWithBaseURL:[NSURL URLWithString:#"http://mywebsite.com/api"]];
--------------
NSString *username = [usernameField text];
NSString *password = [passwordField text];
TKRHttpClient *httpClient = [TKRHttpClient sharedInstance];
NSMutableURLRequest *request = [httpClient requestWithMethod:#"GET" path:#"/user/auth" parameters:nil];
[request addValue:username forHTTPHeaderField:#"username"];
[request addValue:password forHTTPHeaderField:#"password"];
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
if(response.statusCode == 200){
NSDictionary * headers = [response allHeaderFields];
NSString *token = [headers objectForKey:#"auth_token"];
NSLog(#"token was %#", token);
[[AppController sharedAppController] initializeDataForUserToken:token];
}else{
NSLog(#"upload failed!");
}
} failure:^(NSURLRequest *request , NSHTTPURLResponse *response , NSError *error , id JSON ) {
NSLog(#"code was: %i", response.statusCode);
if(response.statusCode == 401){
[errorMessage setText:#"Incorrect password or username"];
}
}];
[operation start];
i put in break points, and it seems that the request goes straight to the failure block. the line that says "NSLog(#"code was: %i", response.statusCode);" in the failure block prints out 200. but when i tail the logs on my server, no request was received.
any help would be greatly appreciated. can't figure out for the life of my why it would work against my local tomcat, but won't work when deployed to my server.
thanks in advance!
i found the reason for my problem thanks to #Brad's suggestion.
upon inspecting the request in charles, i found that the request was made as "http://mywebsite.com", then for path it was /user/auth. so the "/api" part was missing.
maybe this is the standard, i don't know, but it appears that AFHTTPClient's (my TKRHttpClient extends AFHTTPClient) initWithBaseURL really means the host URL. the "/api" part gets lopped off.
and the reason why it was working locally is because i deployed the app locally as root, so there was no "/api"
so two ways to fix this. 1. redeploy as app to server as root. or 2. change the line of code from:
NSMutableURLRequest *request = [httpClient requestWithMethod:#"GET" path:#"/user/auth" parameters:nil];
TO:
NSMutableURLRequest *request = [httpClient requestWithMethod:#"GET" path:#"api/user/auth" parameters:nil];
hopefully this helps anyone using AFNetworking in the future.

how do I check an http request response status code from iOS?

I am sending an http request from iOS (iPad/iPhone) to my python google app engine server using the NSURLConnection and NSURLRequest classes.
How do I read the response's status, i.e. the value set by app engine using response.set_status(200, message="Success") for instance?
I'm not able to find where I can read these status codes once I receive the NSURLConnection's connectionDidFinishLoading delegate call on the client end.
If you are sending a synchronous request, you could get the response code from NSHTTPURLResponse.
NSHTTPURLResponse *response = nil;
NSError *error = nil;
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:URL_LOGIN]];
NSData *respData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
NSLog(#"~~~~~ Status code: %d", [response statusCode]);
Hope this will help you :)
The connection:didReceiveResponse: delegate method is called when a response is received, which gives you an NSURLResponse to play with.
If you've made an HTTP request, then it'll actually be an NSHTTPURLResponse object, which has a statusCode method.

Why does the activity indicator never finish when using ASIHTTPRequest?

I use ASIHTTPRequest to do http requests in my iPhone app. ASIHTTPRequet comes with that feature that starts the activity indicator when issuing a request and stops it when finished. The problem is, once I started a request the indicator never stops and keeps spinning as long as my app runs.
Here is my code, a little utility method that fetches some content from the web synchroniously (since it gets started in a different thread):
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL: [NSURL URLWithString: url]];
[request startSynchronous];
NSError *error = [request error];
NSString *response = nil;
if (error) {
NSLog(#"error %#", error);
return nil;
}
int statusCode = [request responseStatusCode];
response = [NSString stringWithString: [request responseString]];
NSLog(#"status code: %d response: %#", statusCode, response);
if (statusCode != 200) {
return nil;
}
return response;
The above code works just fine, I get the contents of the given URL as a NSString only the indicator keeps spinning. My question is: Why does the indicator never stop and how to fix it? Do I have to release some resources here?
This is a bug that was fixed very recently in the development version of ASIHTTPRequest:
http://github.com/pokeb/asi-http-request/commit/35ea592084145b3332861344f36b52dbcaafa351
(It only affects synchronous requests started on a secondary thread)
Can you try the same thing with an asynchronous request and see if that changes it? I use ASIHTTPRequest and I've never noticed this behavior, but I also never use synchronous requests.

Having problems with uploading photos to TwitPic using OAuth in Objective C on the iPhone

I have been working on an iPhone app that has a feature of uploading photos to TwitPic. I have it working with basic authentication.
I am trying to get it working with OAuth. I am getting authentication errors. I have studied very carefully the TwitPic documentation.
I am authorising the app by displaying a UI Web View and the it returns a PIN value. I enter the PIN value in the app and request the token.
I am able to upload status updates to Twitter but not photos.
My code is based on some example code from here:
Example iPhone app using OAuth
Here is my code:
NSString *url = #"http://api.twitpic.com/2/upload.json";
NSString *oauth_header = [oAuth oAuthHeaderForMethod:#"POST" andUrl:url andParams:nil];
NSLog(#"OAuth header : %#\n\n", oauth_header);
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:[NSURL URLWithString:url]];
[request addRequestHeader:#"User-Agent" value:#"ASIHTTPRequest"];
request.requestMethod = #"POST";
[request addRequestHeader:#"X-Auth-Service-Provider" value:#"https://api.twitter.com/1/account/verify_credentials.json"];
[request addRequestHeader:#"X-Verify-Credentials-Authorization" value:oauth_header];
NSData *imageRepresentation = UIImageJPEGRepresentation(imageToUpload, 0.8);
[request setData:imageRepresentation forKey:#"media"];
[request setPostValue:#"Some Message" forKey:#"message"];
[request setPostValue:TWITPIC_API_KEY forKey:#"key"];
[request setDelegate:self];
[request setDidFinishSelector:#selector(requestDone:)];
[request setDidFailSelector:#selector(requestFailed:)];
[request start];
Here is the OAuth Header:
OAuth realm="http://api.twitter.com/", oauth_timestamp="1275492425", oauth_nonce="b686f20a18ba6763ac52b689b2ac0c421a9e4013", oauth_signature_method="HMAC-SHA1", oauth_consumer_key="zNbW3Xi3MuS7i9cpz6fw", oauth_version="1.0", oauth_token="147275699-jmrjpwk3B6mO2FX2BCc9Ci9CRBbBKYW1bOni2MYs", oauth_signature="d17HImz6VgygZgbcp845CD2qNnI%3D"
HA! I found it!
We should create the header with https://api.twitter.com/1/account/verify_credentials.json and post to http://api.twitpic.com/2/upload.json! (And use GET)
NSString *fakeurl = #"https://api.twitter.com/1/account/verify_credentials.json";
NSString *oauth_header = [oAuth oAuthHeaderForMethod:#"GET" andUrl:fakeurl andParams:nil];
NSLog(#"OAuth header : %#\n\n", oauth_header);
NSString *url = #"http://api.twitpic.com/2/upload.json";
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:[NSURL URLWithString:url]];
request.delegate = self;
[request addRequestHeader:#"User-Agent" value:#"ASIHTTPRequest"];
request.requestMethod = #"GET";
[request addRequestHeader:#"X-Verify-Credentials-Authorization" value:oauth_header];
[request addRequestHeader:#"X-Auth-Service-Provider" value:#"https://api.twitter.com/1/account/verify_credentials.json"];
NSData *imageRepresentation = UIImageJPEGRepresentation([UIImage imageNamed:#"IMG_0717.jpg"], 0.2);
if (imageRepresentation) {
NSLog(#"Pic not nil");
}
[request setData:imageRepresentation forKey:#"media"];
[request setPostValue:#"twitpic, i hate you. die painfully." forKey:#"message"];
[request setPostValue:twitPicKey forKey:#"key"];
[request setDelegate:self];
[request setDidFinishSelector:#selector(requestDone:)];
[request setDidFailSelector:#selector(requestFailed:)];
[request start];
Use GSTwitPicEngine: https://github.com/Gurpartap/GSTwitPicEngine
Using GSTwitPicEngine:
Initialize the engine with class or as needed:
self.twitpicEngine = (GSTwitPicEngine *)[GSTwitPicEngine twitpicEngineWithDelegate:self];
Find the authorization token and supply to twitpicEngine with:
[twitpicEngine setAccessToken:token];
Then to upload image and attach a text message along with it (does not post to twitter):
[twitpicEngine uploadPicture:[UIImage imageNamed:#"mypic.png"] withMessage:#"Hello world!"]; // This message is supplied back in success delegate call in request's userInfo.
To upload image only:
[twitpicEngine uploadPicture:uploadImageView.image];
Upon end of request, one of the delegate methods is called with appropriate data and information.
GSTwitPicEngineDelegate protocol specifies two delegate methods:
- (void)twitpicDidFinishUpload:(NSDictionary *)response {
NSLog(#"TwitPic finished uploading: %#", response);
// [response objectForKey:#"parsedResponse"] gives an NSDictionary of the response one of the parsing libraries was available.
// Otherwise, use [[response objectForKey:#"request"] objectForKey:#"responseString"] to parse yourself.
if ([[[response objectForKey:#"request"] userInfo] objectForKey:#"message"] > 0 && [[response objectForKey:#"parsedResponse"] count] > 0) {
// Uncomment to update status upon successful upload, using MGTwitterEngine's instance.
// [twitterEngine sendUpdate:[NSString stringWithFormat:#"%# %#", [[[response objectForKey:#"request"] userInfo] objectForKey:#"message"], [[response objectForKey:#"parsedResponse"] objectForKey:#"url"]]];
}
}
and
- (void)twitpicDidFailUpload:(NSDictionary *)error {
NSLog(#"TwitPic failed to upload: %#", error);
if ([[error objectForKey:#"request"] responseStatusCode] == 401) {
// UIAlertViewQuick(#"Authentication failed", [error objectForKey:#"errorDescription"], #"OK");
}
}
All set?
OAuth method to generate a header must be GET. Not POST.
Also url must be https://api.twitter.com/1/account/verify_credentials.json
Thanks, this helped me get it working too :) I also updated http://github.com/jaanus/PlainOAuth with working example code.