Automatic decompresion of gzipped json response data not working - ios

From all I have read gzipped response data should be automatically decompressed by the NS URL loading system. I am using AFNetworking and a AFJSONResponseSerializer to handle requests to a custom backend. I have experimented with adding "Accept-Encoding" = gzip to my request headers, but it has had no effect. My response headers include:
"Content-Encoding" = gzip;
"Content-Length" = 179837;
"Content-Type" = "application/json";
I am making the request like this:
[[AFHTTPRequestOperationManager sharedClient]
GET:#"some/endpoint"
parameters:#{#"foo":#"bar"}
success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"Response data size %u", operation.responseData.length);
NSURL *outputURL = [[APP_DELEGATE applicationDocumentsDirectory] URLByAppendingPathComponent:#"data.gzip"];
[operation.responseData writeToURL:outputURL atomically:NO];
}
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"ERROR [%d] [%#]", error.code, error.localizedDescription );
}];
When this runs the size of operation.responseData.length printed is what I expect. However, responseObject is nil when it should be an NSArray. I added the lines writing operation.responseData to test that the data received is what I expect. I can browse to data.gzip, uncompress it, and see my JSON.
It appears to me that the gzipped data received is not being automatically decompressed before my AFJSONResponseSerializer tries to handle it. Most of what I have found on Stackoverflow has either discussed how the decompression is automatic or suggested adding an "Accept-Encoding" = gzip header. Any suggestions would be appreciated.

Have you checked the output from the "custom backend" — use something like Charles Proxy which will let you see things like your response headers and raw content.
e.g. typical headers as shown in Charles:
HTTP/1.1 200 OK
Date Wed, 26 Nov 2014 22:25:33 GMT
Server Apache/2.2.24 (Unix) mod_hive/4.0 mod_ssl/2.2.24 OpenSSL/1.0.0-fips mod_auth_passthrough/2.1 mod_bwlimited/1.4 FrontPage/5.0.2.2635 mod_fcgid/2.3.6
X-Powered-By PHP/5.3.29
P3P CP="NOI ADM DEV PSAi COM NAV OUR OTRo STP IND DEM"
Cache-Control no-cache
Pragma no-cache
Set-Cookie 4d3750fca133ae462ca26ca5a1cc0104=c7da991b30f53342846fff5ddaf3ea08; path=/
Cache-Control max-age=3600
Expires Wed, 26 Nov 2014 23:25:33 GMT
Host-Header 192fc2e7e50945beb8231a492d6a8024
Keep-Alive timeout=5, max=100
Connection Keep-Alive
Transfer-Encoding chunked
Content-Type text/html; charset=utf-8

Related

NSURLConnection response's expectedContentLength -1

*
Note: There are several links on this topic but it didn't work for me,
So I have to post the new one here.
*
Basically I'm trying to show the UIProgressView to show the data being fetched from the web service. Now problem is that I'm getting the expectedContentLength for almost all the service that I call from my application and the response headers contains the Content-Length. But for one of the web service's response it doesn't return the expectedContentLength, instead always returns -1.
Following are the response headers that I get for two different web service response :
- Response header for which I get the content length.(Data from service is not huge)
{
Connection = "Keep-Alive";
"Content-Length" = 2689;
"Content-Type" = "application/json";
Date = "Tue, 23 Jun 2015 08:19:04 GMT";
"Keep-Alive" = "timeout=5, max=98";
Server = "Apache/2.4.10 (Win32) OpenSSL/1.0.1i PHP/5.5.15";
"X-Powered-By" = "PHP/5.5.15";
}
- Response header for which I don't get the content length. (Response contains the huge data, no files to be downloaded just JSON data)
{
Connection = "Keep-Alive";
"Content-Type" = "application/json";
Date = "Tue, 23 Jun 2015 08:12:34 GMT";
"Keep-Alive" = "timeout=5, max=97";
Server = "Apache/2.4.10 (Win32) OpenSSL/1.0.1i PHP/5.5.15";
"Transfer-Encoding" = Identity;
"X-Powered-By" = "PHP/5.5.15";
}
The Above service response contains huge data. When tested the response on Advanced rest client chrome's extension It gives following response header with "Transfer-Encoding" = chunked;.
Date: Tue, 23 Jun 2015 12:01:20 GMT
Server: Apache/2.4.10 (Win32) OpenSSL/1.0.1i PHP/5.5.15
X-Powered-By: PHP/5.5.15
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: application/json
I used following links, but none of them helped me:
Link1 , Link2 , Link3
Please help me.
Thanks!
Updated code:
After setting the Content-Lenth header on server side I got the valid response with Content-Length header on Advanced rest client chrome's extension.
Date: Wed, 24 Jun 2015 05:25:48 GMT
Server: Apache/2.4.10 (Win32) OpenSSL/1.0.1i PHP/5.5.15
X-Powered-By: PHP/5.5.15
Content-Length: 1272347
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: application/json
But on client side (i.e in iOS Application) I still didn't get the Content-Lenth header so that I can get the expectedContentLength value.
I still get "Transfer-Encoding" = Identity; in the response header on my side.
I have also set the Accept-Encoding header in the request as follows :
[req setValue:#"identity;q=0" forHTTPHeaderField:#"Accept-Encoding"];
Is there anything more to be done on either side(server/client).
I don't know how one gets the content length added at the server side - I had problems with this before, and in one case I had a similar situation as yours - the content length was visible by dumping all headers, but iOS didn't hand it to me in the delegate method. The standard way to get it is via:
- (void)connection:(NSURLConnection *)conn didReceiveResponse:(NSURLResponse *)response
{
...
NSUInteger responseLength = response.expectedContentLength == NSURLResponseUnknownLength ? 1024 : (NSUInteger)response.expectedContentLength;
I actually entered a bug on this: rdar://15605995 "HTTP Get response is 200 but response.expectedContentLength = -1 even when a Content-Length is found in the headers"
2014-01-08 18:49:36.966 DB_Lookup[36824:3f07] YIKES:LEN=22162 {
"Cache-Control" = "must-revalidate";
Connection = "keep-alive";
"Content-Encoding" = gzip;
"Content-Length" = 22162;
"Content-Type" = "text/html; charset=UTF-8";
Date = "Wed, 08 Jan 2014 23:49:09 GMT";
Expires = 0;
"Front-End-Https" = on;
Pragma = "no-cache";
Server = "nginx/1.2.4";
"Strict-Transport-Security" = "max-age=2592000";
Vary = "Accept-Encoding";
"X-Content-Type-Options" = nosniff;
"X-Frame-Options" = SAMEORIGIN;
"X-Powered-By" = <Company>;
"X-<Company>-Server" = "<private>";
"X-XSS-Protection" = "1; mode=block";
}
for this code:
if(response.expectedContentLength == NSURLResponseUnknownLength) {
id len = httpResponse.allHeaderFields[#"Content-Length"];
if(len) {
responseLength = [len integerValue];
}
NSLog(#"YIKES:LEN=%# %#", len, httpResponse.allHeaderFields);
}
This is going to be really hard for me to special case. I'm accessing an internal company data base, I have to use name/password first, then get a code to my phone (which I later enter) to get in. Is there other info I could grab to help you? How can it be that the content length is clearly there in the header, but you don't see it and return it to me?
Apple closed my bug, saying "Works as Expected". Really!?!?!?!?!?!?!
[I don't know if NSURLSession fixed it or not.]
EDIT: I should have added that in the past, other sites I connected to DID result in a properly set 'expectedContentLength'.

AFNetworking POST get 403 forbidden, but Curl works

I want to use AFNetworking to POST to sinatra project to get json data. AFNetwroking always get back 403 status code. But curl works as expect. Why?
Here is the error on Xcode:
<AFHTTPRequestOperation: 0x7ffd5da42780, state: isFinished, cancelled: NO request: <NSMutableURLRequest: 0x7ffd5d9591b0> { URL: http://127.0.0.1:9292/api/v1/events/new }, response: <NSHTTPURLResponse: 0x7ffd5b7b7030> { URL: http://127.0.0.1:9292/api/v1/events/new } { status code: 403, headers {
Connection = "Keep-Alive";
"Content-Length" = 69;
"Content-Type" = "application/json";
Date = "Fri, 23 Jan 2015 08:42:32 GMT";
Server = "WEBrick/1.3.1 (Ruby/2.1.5/2014-11-13)";
"X-Content-Type-Options" = nosniff;
} }>
Curl on terminal:
curl http://127.0.0.1:9292/api/v1/events/new
{"error_code":10001,"error_message":"need token or token is illegal"}%
IOS code doesn't work:
AFHTTPRequestOperationManager *manager = [[AFHTTPRequestOperationManager alloc] initWithBaseURL:
[NSURL URLWithString:#"http://127.0.0.1:9292/"]];
[manager POST:#"api/v1/events/new"
parameters:nil
success:nil
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{DLog(#"%#",operation);}];
rackup log:
[2015-01-23 16:58:20] INFO WEBrick 1.3.1
[2015-01-23 16:58:20] INFO ruby 2.1.5 (2014-11-13) [x86_64-darwin14.0]
[2015-01-23 16:58:20] INFO WEBrick::HTTPServer#start: pid=14445 port=9292
127.0.0.1 - - [23/Jan/2015:16:58:36 +0800] "POST /api/v1/events/new HTTP/1.1" 403 69 0.0179
Actually it works right, my server side make a path filter, but here provide a way, sometime not only just print operation but also operation.responseObject which i got what i want.
{
"error_code" = 10001;
"error_message" = "need token or token is illegal";
}

getting boolean or string from ASP.NET Web API via IOS

I can get the value in JSON format with the function:
NSMutableArray *jsonArrayClass = [NSJSONSerialization JSONObjectWithData:data
options:kNilOptions
error:&error];
But i really have no idea how to get the string value or boolean value. we have some validation will return this data type. not JSON.
The raw value shown on Flidder looks like (ID00001 is the return string):
HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/json; charset=utf-8
Expires: -1
Server: Microsoft-IIS/7.5
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Mon, 07 Apr 2014 17:15:28 GMT
Content-Length: 9
"ID00001"
Try this
[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];

MGTwitterEngine statusesReceived not firing

A few time ago I've developed an iOS app with MGTwitterEngine and XML parsing option.
Since Twitter updated the API to 1.1, seems to be that all messages must be called with JSON format.
After a long nightmare to integrate YAJL library with MGTwitterEngine, my program makes a Succeeded Request but the statusesReceived delegate method is not fired.
I've checked if the delegated is properly assigned, and everything is correct. After launch the HTTP request I get the response OK but not any message.
Here an example of the call I made:
INFO -> Twitter URL: https://api.twitter.com/1.1/statuses/user_timeline.json?since_id=1&screen_name=CFarmaceutico&count=50
And here the response:
MGTwitterEngine: (200) [no error]:
{
"Cache-Control" = "no-cache, no-store, must-revalidate, pre-check=0, post-check=0";
"Content-Encoding" = gzip;
"Content-Length" = 10778;
"Content-Type" = "application/json;charset=utf-8";
Date = "Thu, 28 Nov 2013 11:57:33 GMT";
Expires = "Tue, 31 Mar 1981 05:00:00 GMT";
"Last-Modified" = "Thu, 28 Nov 2013 11:57:33 GMT";
Pragma = "no-cache";
Server = tfe;
"Set-Cookie" = "lang=es, guest_id=v1%3A138563985309026395; Domain=.twitter.com; Path=/; Expires=Sat, 28-Nov-2015 11:57:33 UTC";
Status = "200 OK";
"Strict-Transport-Security" = "max-age=631138519";
"x-access-level" = "read-write-directmessages";
"x-frame-options" = SAMEORIGIN;
"x-rate-limit-limit" = 180;
"x-rate-limit-remaining" = 166;
"x-rate-limit-reset" = 1385639983;
"x-transaction" = da0b638eef7ffe43;
"x-xss-protection" = "1; mode=block";
}
2013-11-28 12:57:34.025 Otsuka On[60073:a0b] Request Suceeded: 59CA5086-8AA9-4632-978B-2B9F2334D704
But the statusesReceived method is not called anymore.
Any idea?
Thanks.
no idea - but MGTwitterEngine does not support API 1.1, and when API 1.1 was released, we tried hard to get MGTwitterEngine working - and failed. Eventually we converted our app to FHSTwitterEngine - and it works fine since then. It was relatively straightforward process so I would strongly recommend you to do the same. It will take you less time than fixing bugs in MGTwitterEngine.

iOS, RESTKit and oAuth - simple sample not working

I am writing a simple application on iOS and I am trying to consume a RESTFull webservice
To have some tips and get some knowledge I first start with twitter without using ios integrated libs, but I always get stocked on Auth.
Any working sample or link will be appreciated, as reminder twitter is not my final goal
For instance this is one of my code, based on RestKit and AFOAuth1Client :
NSURL *url = [NSURL URLWithString:#"https://api.twitter.com"];
AFOAuth1Client * twitterClient = [[AFOAuth1Client alloc] initWithBaseURL:url key:kCLIENTID secret:kCLIENTSECRET];
[twitterClient authorizeUsingOAuthWithRequestTokenPath:#"oauth/request_token"
userAuthorizationPath:#"oauth/authorize"
callbackURL:[NSURL URLWithString:#"af-twitter://success"]
accessTokenPath:#"oauth/access_token"
accessMethod:#"POST"
scope:#""
success:^(AFOAuth1Token *token, id responseObject) {
}
failure:^(NSError *error) {
}];
as you can see it does not work :
2013-06-17 16:59:01.389 restKitTest[14490:c07] I restkit:RKLog.m:34 RestKit logging initialized...
2013-06-17 16:59:02.653 restKitTest[14490:c07] I restkit.network:RKObjectRequestOperation.m:174 POST 'http://api.twitter.com/oauth/request_token'
2013-06-17 16:59:03.051 restKitTest[14490:c07] E restkit.network:RKObjectRequestOperation.m:203 POST 'http://api.twitter.com/oauth/request_token' (401 Unauthorized) [0.3980 s]: Error Domain=AFNetworkingErrorDomain Code=-1011 "Expected status code in (200-299), got 401" UserInfo=0x9c96640 {NSLocalizedRecoverySuggestion=Failed to validate oauth signature and token, AFNetworkingOperationFailingURLRequestErrorKey=<NSMutableURLRequest: 0x9877e20> { URL: http://api.twitter.com/oauth/request_token }, NSErrorFailingURLKey=http://api.twitter.com/oauth/request_token, NSLocalizedDescription=Expected status code in (200-299), got 401, AFNetworkingOperationFailingURLResponseErrorKey=<NSHTTPURLResponse: 0x9aac910> { URL: http://api.twitter.com/oauth/request_token } { status code: 401, headers {
"Cache-Control" = "no-cache, no-store, must-revalidate, pre-check=0, post-check=0";
"Content-Encoding" = gzip;
"Content-Length" = 62;
"Content-Type" = "text/html; charset=utf-8";
Date = "Mon, 17 Jun 2013 14:59:03 GMT";
Expires = "Tue, 31 Mar 1981 05:00:00 GMT";
"Last-Modified" = "Mon, 17 Jun 2013 14:59:03 GMT";
Pragma = "no-cache";
Server = tfe;
"Set-Cookie" = "_twitter_sess=BAh7CDoPY3JlYXRlZF9hdGwrCOJ3pVI%252FAToHaWQiJTIyYzUxN2UwNmUwYTI4%250AYzU1NmU0OTYxZDA5MDcwMmI3IgpmbGFzaElDOidBY3Rpb25Db250cm9sbGVy%250AOjpGbGFzaDo6Rmxhc2hIYXNoewAGOgpAdXNlZHsA--3291687666d367b6ccddc74513532bf56ea144d9; domain=.twitter.com; path=/; HttpOnly, guest_id=v1%3A137148114312677519; Domain=.twitter.com; Path=/; Expires=Wed, 17-Jun-2015 14:59:03 UTC";
Status = "401 Unauthorized";
Vary = "Accept-Encoding";
"x-frame-options" = SAMEORIGIN;
"x-mid" = af106773611449e1226d5dd5d531b64d91e4f3f8;
"x-runtime" = "0.01153";
"x-transaction" = 24e58d8eb3b7cdb5;
"x-ua-compatible" = "IE=10,chrome=1";
"x-xss-protection" = "1; mode=block";
} }}
"401 Unauthorized" indicates that your credentials are incorrect. So check your API keys.
try this:
[twitterClient authorizeUsingOAuthWithRequestTokenPath:#"/oauth/request_token"
userAuthorizationPath:#"/oauth/authorize"
callbackURL:[NSURL URLWithString:#"instantshare-twitter://success"]
accessTokenPath:#"/oauth/access_token"
accessMethod:#"POST"
scope:nil
success:^(AFOAuth1Token *accessToken, id responseObject) {
[twitterClient registerHTTPOperationClass:[AFJSONRequestOperation class]];
} failure:^(NSError *error) {
NSLog(#"Error: %#", error);
}];
Note the line scope:nil, for some reason it doesn't work with empty string.
Among other things, check your application settings in twitter. I'm not sure if this is the case, but I enabled Allow this application to be used to Sign in with Twitter and set Callback URL to some random valid url

Resources