UIWebView clear cache only if necessary - ios

How to delete UIWebView cache only if necessary, e.g. when response status code is 304? I use:
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
from NSURLConnectionDelegate to get status code from the response:
int code = [(NSHTTPURLResponse*)response statusCode];
But the code is always 200 (OK). How to get code 304 (not changed) to know when I need to clear cache?
Thanks in advance.

How to get code 304.but code is always 200 (OK)
I don't understand your question - it is the server that sends http codes, are you asking how to change the server so that it sends 304?
Regardless of that, what is the connection between your UIWebView and the NSURLConnection.
Are you using a NSURLConnection inside of shouldStartLoadWithRequest: for some reason?

Related

AFNetworking -1017 error

I am working on iOS application and facing one strange issue. I am using AFNetworking framework to communicate with server (HTTPS communication). I am retrieving student data from server by using "getStudentData" web service API. It is post request. It works for all user ids except one. It fails when we have a data for more than 450 students. Below are the error details,
Error Domain=NSURLErrorDomain Code=-1017 "cannot parse response" UserInfo=0x7bf9c7d0 {NSErrorFailingURLStringKey=https://www.fdmobileservices.com/mAccountsWeb/services/speedpass/rpc, _kCFStreamErrorCodeKey=-1, NSErrorFailingURLKey=https://www.fdmobileservices.com/mAccountsWeb/services/speedpass/rpc, NSLocalizedDescription=cannot parse response, _kCFStreamErrorDomainKey=4, NSUnderlyingError=0x7bf9a380 "cannot parse response"}
As per error description, It tells "Could Not parse", so I think it may be due to server is returning "nil" or some data other than JSON format.
But I am not able to trace it since from application side it directly goes into below method,
- (void)connection:(NSURLConnection __unused *)connection
didFailWithError:(NSError *)error
Is there any way from application side to trace root cause? This method works for other user login except one.
I tried using web client to access this service by same user login, it works well and return data of 450 students. I think due to some reason iOS network layer rejects this. I am trying to find out.
Thanks in advance.
As you can see here, kCFURLErrorCannotParseResponse = -1017. So probably this is saying that there is something wrong in the parameters.
If You're using AFNetworking 2.0, I suggest You to deep debug your response flow with severals breakpoints.
Specifically try to set a breakpoint on AFURLResponseSerialization.m at the start of the method:
- (id)responseObjectForResponse:(NSURLResponse *)response
data:(NSData *)data
error:(NSError *__autoreleasing *)error;
Inside the method, if the below condition is true, probably there is something wrong (but you can step into validateResponse:data:error: to better understand what's wrong):
if (![self validateResponse:(NSHTTPURLResponse *)response data:data error:error])
If the above condition is false you can then check about the generated responseString:
NSString *responseString = [[NSString alloc] initWithData:data encoding:stringEncoding];
If you're expecting json data, check that responseString is not nil and data data is valid, maybe also the stringEncoding.
Also ensure that the contentType that you're receiving is the one you're expecting.

iOS url response bool

net web service that returns true or false but i don't know how to catch that response in my IOS App.
My service updates data in a database and i know it works the data gets updated it's catch the response that is the problem, i like to know so i can tell the user if something went wrong.
For those of you that know c# its a bool method, just simple try catch and return true or false.
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
//What to write here to catch my true or false
if(response) {
//true
} else {
//false
}
}
Thank you for your help
You should implementconnection:didReceiveData: to get and save NSData and – connectionDidFinishLoading: where you can interpret received data as BOOL.
basically didReceiveResponse: only get to you know about server response to your request not the entire answer.
You should check the response's HTTP status code, e.g.:
NSInteger statusCode = [(NSHTTPURLResponse*)response statusCode];
The status code for a successful request uses the range [200..299].
For example a successful GET request would be indicated with a 200 (OK).
A successful POST request will be indicated with a 201 (Created).
A successful DELET request will be indicated with a 204 (No Content)..
See also: wiki List of HTTP status codes.
Furthermore, you need to check the kind of data the server sent to you:
NSString* mimeType = [response MIMEType];
The mime type has been sent by the server in the Content-Type header of the response.
See also wiki MIME Internet Media Type
What you actually get fully depends on your request AND the server.
For example, the server may always answer with a JSON as content type. In this case, the header Content-Type of the response would be application/json. The actual JSON which represents the answer, will be related to the status code as well.
In order to provide a nice human readable message to the user, you need to consult the web service API and figure out how it is specified. Certain web service APIs may have a considerable large API. Unfortunately, some web services lack a comprehensive documentation.

Read whole html string Asyncsocket iOS

Hi I want to read from a server the whole html not only the request like
"HTTP/1.1 200 OK"
I mean the html code too.
But I dont know how.
I am using the Asyncsocket library from "https://github.com/roustem/AsyncSocket"
have someone an idea how can i handle this?
i used the funktion
- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
but the data is to short and show me only the http request.
Thanks
I would guess that you are calling readDataToData:timeout:tag: using CRLF as the delimiter. That will return you one line of data. What you want is to read enough headers to tell how long the response data ought to be and then call readDataToLength:timeout:tag:, or else wait for the connection to be closed and call unreadData to get everything the server sent up to when it closed the connection.
The HTTP spec describes how to determine the length of the message: https://www.rfc-editor.org/rfc/rfc2616#section-4.4
A better answer might be to use NSURLConnection to make the request and interpret the response for you.

With iOS asynchronous http request, how do you connect the received data to the request?

I'm loading certain images from a certain server asynchronously. I'm firing a number of requests at once using NSURLConnection connectionWithRequest method and receive the data using NSURLConnectionDelegate didReceiveData.
At didReceiveData, how do I know which request this data matches? At didReceiveResponse I can use the URL method of the response given as a parameter, but in didReceiveData I only have the received data.
It seemed like the perfect answer would be to use NSURLConnection sendAsynchronousRequest, as the completion handler has all the required parameters: (NSURLResponse*, NSData*, NSError*). I can use [response URL] to make a match to the original request... except in one case: not all the images I try to download exist. In that case, the request is redirected to a generic error page and the URL of that generic page is received, so I can't match the response to a request I've made. This I could handle with connectionWithRequest, but I can't get the best of both worlds.
In
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
you can use
NSURLRequest *request = [connection originalRequest];
to get the request that the connection was started with.
(This method is available since iOS 5.0, but I could not find it in my Xcode iOS 5.1 Library. You find it in the iOS 6 Library, in the header file NSURLConnection.h or here: http://developer.apple.com/library/ios/#documentation/Cocoa/Reference/Foundation/Classes/NSURLConnection_Class/Reference/Reference.html#//apple_ref/occ/instm/NSURLConnection/originalRequest).
More methods to manage multiple connections can be found in this thread: Managing multiple asynchronous NSURLConnection connections.
If you use sendAsynchronousRequest:queue:completionHandler: then you can just use the request parameter in the completion block.
At connection:didReceiveData: the first parameter is the NSURLConnection instance. So I don't understand where the problem is. You create a connection, then you send a request to that connection and the delegate receive the connection:didReceiveData with the connection value.
If you are using the same delegate for all the request you have to check the connection so you can say which request is associated to.
Perhaps you have to maintain a table of connection/request pairs.

NSURLRequest: How to handle a redirected post?

I have a tried and tested use of NSURLRequest (and accompaniments) implementation, that works great for GETs, and POSTs for a given URL.
However, I want to now move the target of the URL without changing the URL used by the app, so I'm intending to use a webhop redirect via my DNS provider.
This works fine for the GET requests, but the POSTs just hang... no connection response is received.
The relevant iOS method for handling a redirect is,
-(NSURLRequest *)connection:(NSURLConnection *)connection
willSendRequest:(NSURLRequest *)request
redirectResponse:(NSURLResponse *)redirectResponse
According to Apple's documentation for (handling redirects),
If the delegate doesn't implement connection:willSendRequest:redirectResponse:, all canonical changes and server redirects are allowed.
Well, that's not my experience, because leaving this method out does not work for me. The request just hangs without a response.
Apple also suggests an implementation, of willSendRequest (see above linked Apple documentation), again this doesn't work for me. I see the invocations, but the resulting requests just hang.
My current implementation of willSendRequest is as follows (see below). This follows the redirect, but the handles the request as if it was a GET, rather than a POST.
I believe the problem is that the redirection is losing the fact that the HTTP request is a POST (there may be more problems, such as carrying the request Body forward too?).
I'm not sure what I should be doing here. So any advice on how to correctly handle a POST that receives a redirect would be appreciated. Thanks.
-(NSURLRequest *)connection:(NSURLConnection *)connection
willSendRequest:(NSURLRequest *)request
redirectResponse:(NSURLResponse *)redirectResponse
{
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) redirectResponse;
int statusCode = [httpResponse statusCode];
NSLog (#"HTTP status %d", statusCode);
// http statuscodes between 300 & 400 is a redirect ...
if (httpResponse && statusCode >= 300 && statusCode < 400)
{
NSLog(#"willSendRequest (from %# to %#)", redirectResponse.URL, request.URL);
}
if (redirectResponse)
{
NSMutableURLRequest *newRequest = [request mutableCopy]; // original request
[newRequest setURL: [request URL]];
NSLog (#"redirected");
return newRequest;
}
else
{
NSLog (#"original");
return request;
}
}
ADDITIONAL INFORMATION 1
The HTTP code received by willSendRequest is 301 - 'Moved Permanently.
Using allHTTPHeaderFields to extract the header fields, I see that he request I originally submit has the header
HTTP header {
"Content-Length" = 244;
"Content-Type" = "application/json";
}
...and the copied / redirected request has the header,
Redirect HTTP header {
Accept = "*/*";
"Accept-Encoding" = "gzip, deflate";
"Accept-Language" = "en-us";
"Content-Type" = "application/json";
}
...which doesn't look like a copy of the original request, or even a superset.
Keep your original request, then provide your own willSendRequest:redirectResponse: to customize that request, rather than working with the one Apple provides you.
- (NSURLRequest *)connection: (NSURLConnection *)connection
willSendRequest: (NSURLRequest *)request
redirectResponse: (NSURLResponse *)redirectResponse;
{
if (redirectResponse) {
// The request you initialized the connection with should be kept as
// _originalRequest.
// Instead of trying to merge the pieces of _originalRequest into Cocoa
// touch's proposed redirect request, we make a mutable copy of the
// original request, change the URL to match that of the proposed
// request, and return it as the request to use.
//
NSMutableURLRequest *r = [_originalRequest mutableCopy];
[r setURL: [request URL]];
return r;
} else {
return request;
}
}
By doing this, you're explicitly ignoring some aspects of the HTTP spec: Redirects should generally be turned into GET requests (depending on the HTTP status code). But in practice, this behaviour will serve you better when POSTing from an iOS application.
See also:
iOS Developer Library, URL Loading System Programming Guide: Handling Redirects and Other Request Changes
The HTTP specification for handling the 3xx class of status codes is very unfriendly towards protocols other than GET and HEAD. It expects some kind of user interaction for at the intermediary step of the redirection, which has lead to a plethora of incompatible client and server implementations, as well as a serious headache for web service developers.
From an iOS NSURL point of view, one of the things you might want to verify is that the original POST body is included in the new, redirect request.
Based off your comments on my original answer, and the edits to your question, it would appear that the URL you are trying to access has been updated permanently (301 status code). In which case you can actually avoid the redirects altogether by using the new URL.

Resources