My app behaves like this:
Client: sent a request (using a NSURLConnection) to server asking server to generate a file and
download that file.
Server: generate the file and send the file's data
back to client (using chunked encoding)
After generating the file, server will update the file's header, so after downloading
file, client needs to make second request to get the updated header. During
file generating and updating, if server detects that connection from client is
closed, it will delete the generated file, so the connection need to
be kept alive.
Client: sent a second request (another NSURLConnection) to get updated header
The problem is after first request (i use NSURLConnection) server detects connection closed and delete the generated file, so the second request fails.
I suspect the reason is that i use two different instance of NSURLConnection, so I look into the document for something like NSMutableURLConnection. It doesn't exist!.
My question: Is there a way to keep connection alive between to request ( by reusing NSURLConnection, or using NSMutableRequest and re-request with the same NSURLConnection)?
You can use :
NSURLConnection *currentConnection = [NSURLConnection alloc];
[currentConnection initWithRequest:request1 delegate:self];
[currentConnection initWithRequest:request2 delegate:self];
You can verify the Original and Current NSURLRequest using :
- (NSURLRequest *)originalRequest NS_AVAILABLE_IOS(5_0);
- (NSURLRequest *)currentRequest NS_AVAILABLE_IOS(5_0);
Related
I'm using mapbox-gl-native SDK. It can be used with custom servers to provide map tilesets. I'm working with a server which needs an API key in the HTTP request header. I want to edit the header for every request and add the API key.
can anyone help me with this?
I'm using mapbox-gl-native iOS v5.0 (latest untill now)
there is a file named http_file_source.mm in platform/darwin/src/ which is responsible for making HTTP requests. there is a method in this file:
HTTPFileSource::request(const Resource& resource, Callback callback) {
in this mehtod you can see this line:
NSMutableURLRequest* req = [NSMutableURLRequest requestWithURL:url];
this line makes a http request you can add your own header to it, like so: (value for header field)
[req addValue:(NSString *)value forHTTPHeaderField:(NSString *)field]
I am using the TIdHTTP component and it's GET function.
The GET function sends a complete request, which is fine.
However I would like to spare/save some traffic from a GET response and only want to receive the Responsecode which is in the first "line" of a HTTP response.
Is there a possibility of disconnecting the connection in order to save traffic from any further content?
As mentioned, I only need the responsecode from a website.
I alternatively thought about using Indy's TCP component (with SSL IOHandler) and craft an own HTTP Request Header and then receive the responsecode and disconnect on success - but I don't know how to do that.
TIdHTTP has an OnHeadersAvailable event that is intended for this very task. It is triggered after the response headers have been read and before the body content is read, if any. It has a VContinue output parameter that you can set to False to cancel any further reading.
Update: Something I just discovered: When setting VContinue=False in the OnHeadersAvailable event, TIdHTTP will set Response.KeepAlive=False and skip reading the response body (OK so far), but after the response is done being processed, TIdHTTP checks the KeepAlive value, and the property getter returns True if the socket hasn't been closed on the server's end (HTTP 1.1 uses keep-alives by default). This causes TIdHTTP to not close its end of the socket, and will leave any response body unread. If you then re-use the same TIdHTTP object for a new HTTP request, it will end up processing any unread body data from the previous response before it sees thee response headers of the new request.
You can work around this issue by setting the Request.Connection property to 'close' before calling TIdHTTP.Get(). That tells the server to close its end of the socket connection after sending the response (although, I just found that when requesting an HTTPS url, especially after an HTTP request directs to HTTPS, TIdHTTP clears the Request.Connection value!). Or, simply call TIdHTTP.Disconnect() after TIdHTTP.Get() exits.
I have now updated TIdHTTP to:
no longer clear the Request.Connection when preparing an HTTPS request.
close its end of the socket connection if either:
OnHeadersAvailable returns VContinue=False
the Request.Connection property (or, if connected to a proxy, the Request.ProxyConnection property) has been set to 'close', regardless of the server's response.
Usually you would use TIdHttp.Head, because HEAD requests are intended for doing just that.
If the server does not accept HEAD requests like in OP's case, you can assign the OnWorkBegin event of your TIdHttp instance, and call TIdHttp(Sender).Disconnect; there. This immediately closes the connection, the download does not continue, but you still have the meta data like response code, content length etc.
I am developing an iPhone App (using iOS 9 beta). I am using Socket connections for which I am using SocketRocket client library. But when I try to establish a wss connection with some invalid host name, I don't get any error on opening socket, connection or even on sending data, so whenever I try to run program it seems like information about host is correct and data is being sent.
I am using current version of SocketRocket library, I have added SRWebSocket.h, SRWebSocket.m and SocketRocket-Prefix.pch files in my project. Following is the part of code I have:
NSString* url = [NSString stringWithFormat:#"wss://%#/myproject/stream?data=%d", webSocketHost, dummyData];
SRWebSocket *webSocket = [[SRWebSocket alloc] initWithURLRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:url]]];
webSocket.delegate = self;
// open websocket
[webSocket open];
// send message to websocket
[webSocket send:[self getJSONString:parameters]];
// close websocket
[webSocket close];
webSocket = nil;
If I pass some random host name like "abc.def" for the variable webSocketHost, it will still run smoothly (I have try-catch blocks surrounding above code, and I also tried to put break points in between and debugged it line by line).
And even when I don't have any internet connection to my phone, there aren't any errors thrown.
Does anyone know what could be the problem?
Thanks!
Are you implementing this delegate method? The library won't throw an error when you call [webSocket open], it will call this method if it can't connect to the endpoint sometime in the future since establishing a connection is an asynchronous operation.
- (void)webSocket:(SRWebSocket *)webSocket didFailWithError:(NSError *)error;
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.
I am trying to connect my iOS app to a GET data from my web service everytime something changes. My current implementation is to use NSTimer and do a ASIHttpRequest but I don't like that polling implementation. Is there a better way to do it?
I am considering starting the request and lets it keep trying until the web service status code turns to OK (status 200) or perhaps a status code of "modified". How would I do this in a view controller?
Here is what I have so far:
self.asiRequest = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:self.barcodeUrl]];
[self.asiRequest setDelegate:self];
[self.asiRequest startAsynchronous];
[self.asiRequest addRequestHeader:#"Accept" value:#"application/json"];
[self.asiRequest addRequestHeader:#"Content-Type" value:#"application/json"];
int statusCode = [self.asiRequest responseStatusCode];
I know that if the request is successful, the delegate method - (void)requestFinished:(ASIHTTPRequest *)request
I guess my question is, how do I keep an open ASIHttpRequest such that when the web service returns "modified", it calls a GET request and then keep an open connection again? This has to be asynchronous and not running on a UI thread as I don't want to keep my app hanging.
Thanks much!
The easiest way to do this without having to do much on the client-side is to get your web service to send a Location: header through when it returns "modified", pointing to the URL you want to GET with the new content. If the URL to monitor is different depending on e.g. user ID or the area of the app you are in, make a monitor script where you can pass in GET params to configure what exact URL should be returned to you when "modified" is returned.
The ASIHTTPRequest will then automatically GET the content at the new Location: and you can reschedule it in requestFinished: to the monitor URL again, knowing that the response (if not empty/"Not Modified") will ALWAYS be new data since the redirect to new data happens behind-the-scenes.