Google Analytics HTTP status -1 when sending hit(s) by request [GAIBatchingDispatcher didSendHits:response:data:error:] - objective-c

id<GAITracker> tracker = [[GAI sharedInstance] defaultTracker];
[tracker send:[[GAIDictionaryBuilder createEventWithCategory:#"ui_action"
action:#"button_press"
label:#"play"
value:nil] build]];
When I send the event, I get log:
2017-06-20 11:30:00.541 Right-iOS[28240:626691] INFO: GoogleAnalytics 3.17 -[GAIBatchingDispatcher didSendHits:response:data:error:] (GAIBatchingDispatcher.m:226): Hit(s) dispatched: HTTP status -1

Related

Obj-C gRPC new API receiving RST_STREAM error

Context
Have a Obj-C app that needs to consume some server data. The communication uses gRPC.
Created a Obj-C client using `!ProtoCompiler-gRPCPlugin" and "ProtoCompiler".
Using protoc we generated the client. This client exposes two APIs for the same call: One is called "apiV1" and is deprecated, the other is "apiV2" and is suggested.
Below is an example of both:
/* This method belongs to a set of APIs that have been deprecated. Using the v2 API is recommended.
*/
- (void)someCallWithRequest:(XXXCallRequest *)request handler:(void(^)(XXXCallResponse *_Nullable response, NSError *_Nullable error))handler;
And, now, the new suggested API:
- (GRPCUnaryProtoCall *)callWithMessage:(XXXCallRequest *)message responseHandler:(id<GRPCProtoResponseHandler>)handler callOptions:(GRPCCallOptions *_Nullable)callOptions;
The problem
When we use the suggested v2 API, some of our calls receives the RST_STREAM error:
Error Domain=io.grpc Code=13 "{"created":"#1589553479.630057000","description":"Error received from peer ipv4:x.x.x.x:443","file":"/Users/me/Documents/ourapp/App/Pods/gRPC-Core/src/core/lib/surface/call.cc","file_line":1056,"grpc_message":"Received RST_STREAM with error code 2","grpc_status":13}" UserInfo={io.grpc.HeadersKey={
date = "Fri, 15 May 2020 14:37:58 GMT";
server = "nginx/1.17.8";
"strict-transport-security" = "max-age=15724800; includeSubDomains";
trailer = "Grpc-Status";
}, io.grpc.TrailersKey={
}, NSDebugDescription={"created":"#1589553479.630057000","description":"Error received from peer ipv4:x.x.x.:443","file":"/Users/me/Documents/ourapp/App/Pods/gRPC-Core/src/core/lib/surface/call.cc","file_line":1056,"grpc_message":"Received RST_STREAM with error code 2","grpc_status":13}, NSLocalizedDescription=Received RST_STREAM with error code 2}.
Here's how we are using the new gRPC API:
GRPCMutableCallOptions *callOptions = [self buildCallOptions];
XXXCallService *service = [XXXCallService serviceWithHost:host callOptions:callOptions];
XXXCallRequest *callRequestMessage = [self buildCallRequest];
[[service callWithMessage:callRequestMessage
responseHandler:[[GRPCUnaryResponseHandler alloc] initWithResponseHandler:^(XXXCallResponse* response, NSError *error) {
if (error) NSLog(#"%#.", error);
}
And, the most important: when we use the deprecated V1 API, this error never happens. But, unfortunately, it does not have support for defining the CallOptions/metadata/headers, which we require right now.

Client cannot receive image data from gcdwebserver

I try to create a web server on iPhone to provide urls of images in ablum.
Before sending response to client, I need to do some adjustment on images (something like re-size).
These actions take up to 1 or 1.5 sec per image before response to client. (especially on iPhone 4)
The client side cannot receive data even though messages on xcode console already showed how many bytes has been GET on some sockets.
What options can I use to solve this problem?
Another question is what happens if I increase ConnectedStateCoalescingInterval value up to 2.0 or 3.0 seconds?
Thanks.
========= 2015/08/24 13:05 Updated
Here is my addHandlerForMethod:path:requestClass:asyncProcessBlock:
[_webServer addHandlerForMethod:#"GET" path:[NSString stringWithFormat:#"/image/%#",assetId] requestClass:[GCDWebServerRequest class] asyncProcessBlock:^(GCDWebServerRequest *request, GCDWebServerCompletionBlock completionBlock)
{
__strong typeof(weakself) strongself = weakself;
[strongself requestImageDataByAssetURL:assetURL completionCb:^(NSData *photoData) {
GCDWebServerDataResponse* response = [GCDWebServerDataResponse responseWithData:photoData contentType:#"image/png"];
completionBlock(response);
}];
}];
Here is requestImageDataByAssetURL:completionCb:
- (void)requestImageDataByAssetURL:(NSURL *)assetURL completionCb:(void(^)(NSData *photoData))cbfunc {
__block NSData *photoData;
ALAssetsLibrary* library = [[ALAssetsLibrary alloc] init];
[library assetForURL:assetURL resultBlock:^(ALAsset *asset) {
#autoreleasepool {
uint64_t begin = mach_absolute_time();
// <do some image processing here>
uint64_t end = mach_absolute_time();
NSLog(#"Time taken to imageResize %g s", MachTimeToSecs(end - begin));
cbfunc(photoData);
}
} failureBlock:^(NSError *error) {
NSLog(#"[%#] fail. Error=%#", NSStringFromSelector(_cmd), error.localizedDescription);
cbfunc(nil);
}];
}
Here is the log:
[DEBUG] [2015-08-24 04:48:09 +0000] Did open connection on socket 32
[DEBUG] Connection received 221 bytes on socket 32
[DEBUG] Connection on socket 32 preflighting request "GET /image/9D959040-9FA8-4197-8150-8DC72339955D" with 221 bytes body
[DEBUG] Connection on socket 32 processing request "GET /image/9D959040-9FA8-4197-8150-8DC72339955D" with 221 bytes body
[DEBUG] [2015-08-24 04:48:10 +0000] Did open connection on socket 34
2015-08-24 12:48:10.799 xBoard[2981:3707] Time taken to imageResize 1.52039 s
[DEBUG] Connection received 221 bytes on socket 34
[DEBUG] Connection on socket 34 preflighting request "GET /image/9D959040-9FA8-4197-8150-8DC72339955D" with 221 bytes body
[DEBUG] Connection on socket 34 processing request "GET /image/9D959040-9FA8-4197-8150-8DC72339955D" with 221 bytes body
[DEBUG] Connection sent 171 bytes on socket 32
[DEBUG] Connection sent 123575 bytes on socket 32
[DEBUG] Did close connection on socket 32
[VERBOSE] [172.16.20.174:8080] 172.16.21.97:34450 200 "GET /image/9D959040-9FA8-4197-8150-8DC72339955D" (221 | 123746)
2015-08-24 12:48:12.028 xBoard[2981:4f0b] Time taken to imageResize 1.06382 s
[DEBUG] Connection sent 171 bytes on socket 34
[DEBUG] Connection sent 123575 bytes on socket 34
[DEBUG] Did close connection on socket 34
[VERBOSE] [172.16.20.174:8080] 172.16.21.97:50852 200 "GET /image/9D959040-9FA8-4197-8150-8DC72339955D" (221 | 123746)
We can see it creates the first socket(32).
Then creates the second socket(34) for the same image request immediately.
It seems that GCDWebServer close the first socket immediately. But why?
P.S. By the way, the client side use Android Volley library to download image instead of using web browsers.
There doesn't seem to be anything wrong according to the log: 2 GET requests for the path /image/9D959040-9FA8-4197-8150-8DC72339955D are processed on sockets 32 and 34, and each return 123,575 bytes.
Try using a desktop web browser like Chrome and its web inspector. If everything works correctly, then the problem is with your Android app.

NSURLConnection returning error instead of response for 401

I have a web API that, for a specific request returns status code 200 if everything went ok, and 401 if the user is not logged in based on an Authorization token. Everything works fine if the response status is 200, but doesn't seem to work properly if the response status is 401, returning a connection error with code -1012, while the response is nil.
So, the following code:
[NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
NSLog(#"%#", response);
NSLog(#"%#", connectionError);
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response;
int statusCode = (int)[httpResponse statusCode];
NSLog(#"response status code: %d", statusCode);
will display
2015-04-01 15:58:18.511 MyProject[3618:694604] <NSHTTPURLResponse: 0x155facc0> { URL: *SOME_URL* } { status code: 200, headers {
"Access-Control-Allow-Headers" = "Content-Type, Accept, X-Requested-With";
"Access-Control-Allow-Methods" = "POST, GET, PUT, UPDATE, OPTIONS";
"Access-Control-Allow-Origin" = "*";
Connection = "keep-alive";
"Content-Type" = "application/json";
Date = "Wed, 01 Apr 2015 12:58:14 GMT";
Server = "Wildfly 8";
"Transfer-Encoding" = Identity;
"X-Powered-By" = "Undertow 1";
} }
2015-04-01 15:58:18.513 MyProject[3618:694604] (null)
2015-04-01 15:58:18.513 MyProject[3618:694604] response status code: 200
if the response status is 200, while if the status code is 401, I will get:
2015-04-01 16:05:55.988 MyProject[3633:695836] (null)
2015-04-01 16:05:55.992 MyProject[3633:695836] Error Domain=NSURLErrorDomain Code=-1012 "The operation couldn’t be completed. (NSURLErrorDomain error -1012.)" UserInfo=0x146137c0 {NSErrorFailingURLKey=*SOME_URL*, NSErrorFailingURLStringKey=*SOME_URL*, NSUnderlyingError=0x1459e6d0 "The operation couldn’t be completed. (kCFErrorDomainCFNetwork error -1012.)"}
2015-04-01 16:05:55.992 MyProject[3633:695836] response status code: 0
If I do the same request using Postman or an Android device, I will get status code 401 with the following headers(copied from Postman):
Connection → keep-alive
Content-Length → 30
Content-Type → application/json
Date → Wed, 01 Apr 2015 13:07:34 GMT
Server → Wildfly 8
X-Powered-By → Undertow 1
Is there any fix or maybe a library that could give me some accurate response status? I searched a bit about the -1012 error, but couldn't find much and I don't really want to base on that.
Edit: after a bit of research I found the following statement on Appl's documentation: "If authentication is required in order to download the request, the required credentials must be specified as part of the URL. If authentication fails, or credentials are missing, the connection will attempt to continue without credentials."
But then how can I know if this error will be after a 401 status? Can it appear after another type of request?
to check the 401 error, you can do this:
if (error != nil && error.code == NSURLErrorUserCancelledAuthentication) {
// do something for 401 error
}
hope this help
In order to get the 401 status code, I think you'll need to implement protocol NSURLConnectionDelegate and then connection:didReceiveAuthenticationChallenge:.
So, you'll also need to pass the delegate, maybe using [NSURLConnection connectionWithRequest:request delegate:self].
And, if you aren't trying to implement the authentication challenge, I would rather always return the 200 status code, but with different json content.
Hope it can help.
I have a web API that, for a specific request returns status code 200
if everything went ok, and 401 if the user is not logged in based on
an Authorization token. Everything works fine if the response status
is 200, but doesn't seem to work properly if the response status is
401, returning a connection error with code -1012, while the response
is nil.
I've run exactly into the same problem, REST API call returns 401 in Android and Postman, but status code 0 in iOS with a connection error with code -1012.
You can find more information about this problem in this SO post.
Seems to be an iOS bug (or at least very strange approach) happening both with async and sync requests.
I'm posting this just in case this might be useful for others bumping into the same issue. What I did in the code to manage the 401 status, right after the request, is to call a method that checks each managed http status code.
The method receives (NSError **)error and [(NSHTTPURLResponse *)response statusCode].
This is the 401 part - uses the error details stored inside userInfo structure.
// Auth failed or token problems
if (statusCode == 0 && [error userInfo] != nil) {
// Get error detailed informations
NSDictionary *userInfo = [error userInfo];
NSString *errorString = [[userInfo objectForKey:NSUnderlyingErrorKey] localizedDescription];
// If error message is of type authFailed or returns iOS code -1012 meaning auth failed
if ([errorString containsString:#"kCFErrorDomainCFNetwork"] || [errorString containsString:#"-1012"]) {
NSLog(#"%# - ConnectionError - Code 401 - Cause: authentication failed, token is invalid or expired", type);
} else {
NSLog(#"%# - ConnectionError - Cause: generic auth error", type);
}
// Alert user that auth failed
...
}
The other way is to check directly for this error code (-1012) as suggested by #ThuanDINH above. (edited the answer for objective c).
My code can be changed into:
// Auth failed - token problems
if (statusCode == 0 && [error code] == NSURLErrorUserCancelledAuthentication) {
// If error code is UserCanceledAuthentication
MPLog(MPLogLevelInfo, #"%# - ConnectionError - Cause: authentication failed, token is invalid or expired", type);
// Alert user that auth failed
...
}
But in this way you will not handle all other errors (you need to switch on each NSURLError code).
Here you can find the SO question with the list of all the NSURLError codes.
Based on Apple documentation https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/URLLoadingSystem/NSURLSessionConcepts/NSURLSessionConcepts.html,
Note: NSURLSession does not report server errors through the error parameter. The only errors your delegate receives through the error parameter are client-side errors, such as being unable to resolve the hostname or connect to the host. The error codes are described in URL Loading System Error Codes.
Server-side errors are reported through the HTTP status code in the NSHTTPURLResponse object. For more information, read the documentation for the NSHTTPURLResponse and NSURLResponse classes.
We need to make sure that we do not cancel the session in our code. For example, I was calling NSURLSessionAuthChallengeCancelAuthenticationChallenge in didReceiveChallenge delegate method, when previousFailureCount > 1. This was suppressing 401 response and also call to didReceiveResponse.
When I changed above value to NSURLSessionAuthChallengePerformDefaultHandling, I am receiving 401 Unauthorized response in didReceiveResponse delegate method and works as expected.

RKObjectPaginator did not send GET request to server

I have a RKObjectPaginator and have set the necessary parameters. But my server did not receive any query.
RKURL *patternURL = [[[RKObjectManager sharedManager] baseURL] URLByAppendingResourcePath:ResourcePathPattern];
RKObjectPaginator *paginator = [[RKObjectPaginator alloc] initWithPatternURL:patternURL mappingProvider:[self paginationMappingProvider]];
paginator.delegate = self;
[paginator loadPage:0];
My log console reads:
2012-09-12 20:56:36.975 keytech search ios[1692:c07] Will load page: 0
2012-09-12 20:58:06.613 keytech search ios[1692:c07] D restkit.network:RKRequest.m:436 Sending asynchronous GET request to URL 'http://-MyServerIP-:8080/keytech/GetNextSearchResults?pageSize=25&pageNumber=0.
2012-09-12 20:58:06.613 keytech search ios[1692:c07] T restkit.network:RKRequest.m:402 Prepared GET URLRequest '<NSMutableURLRequest >http://-MyServerIP-:8080/keytech/GetNextSearchResults?pageSize=25&pageNumber=0>'. HTTP Headers: {
"Content-Length" = 0;
}. HTTP Body: .
But no request is send to the server.
Have I done everything right? If I post the URL in my browser, the server responds well. It seems that this query is not send.
I have no clue why this request is not send.
Is there a 'best-practise' example how to use RKObjectPaginator?
You might not be able to load page 0.
try [paginator loadPage:1];
I am also looking for a sample myself on how to do this. In your case I believe that you are missing the PageCount and ObjectCount properties. It seems to me that you have to set that up manually.
BTW: did you ever resolve it?

logout API facebook, twitter, linkedin

I have code for logout for facebook twitter and linkedin
facebook
[facebookObj logout:self];
Twitter
[twitterObj endUserSession];
LinkedIn
static NSString *const kOAuthInvalidateTokenURL = #"https://api.linkedin.com/uas/oauth/invalidateToken";
NSURL* url = [NSURL URLWithString:kOAuthInvalidateTokenURL];
return [self sendAPIRequestWithURL:url HTTPMethod:#"GET" body:nil];
but nothing is logout
I got error for facebook i.e
2011-04-11 19:18:03.820 myApp[2544:207] fbDidLogout
2011-04-11 19:18:07.303 myApp[2544:207] Request 01E3CA03-1671-49B4-95A7-E87081F68333 failed with error: Error Domain=HTTP Code=401 "The operation couldn’t be completed. (HTTP error 401.)"
Please guide me how we logout
Amit Battan
You need to send a request with the token and this url. You wil get status code 200.