2

I am trying to reduce our server overheads by using persistent HTTP connections via the Apple CFNetwork framework. However there is little documentation about it. The only information I could find suggested that the framework recycles streams on behalf of the developer as long as the appropriate flags are set:

        CFHTTPMessageRef request = CFHTTPMessageCreateRequest(kCFAllocatorDefault, methodString, url, kCFHTTPVersion1_1);
        CFHTTPMessageSetHeaderFieldValue(request, CFSTR("Keep-Alive"), CFSTR("120")); <--- This line

        //Set message body if we're posting
        if (msDetails.eType == HttpRequestDetails::POST)
        {
            CFDataRef bodyRef = CFDataCreate(kCFAllocatorDefault, (const UInt8*)msDetails.strBody.c_str(), msDetails.strBody.length());
            CFHTTPMessageSetBody(request, bodyRef);
            CFRelease(bodyRef); 
        }

        //Create the read stream...
        CFReadStreamRef ReadStream = CFReadStreamCreateForHTTPRequest(kCFAllocatorDefault, request);

        //...use persistent connections..
        CFReadStreamSetProperty(ReadStream, kCFStreamPropertyHTTPAttemptPersistentConnection, kCFBooleanTrue); <--- This line

        //...enable SSL if the URL is https
        if(msDetails.strURL[4] == 's')
        {
            //Hey an https request
            CFMutableDictionaryRef pDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
            CFDictionarySetValue(pDict, kCFStreamSSLValidatesCertificateChain, kCFBooleanFalse);
            CFDictionarySetValue(pDict, kCFStreamPropertySocketSecurityLevel, kCFStreamSocketSecurityLevelSSLv3);
            CFReadStreamSetProperty(ReadStream, kCFStreamPropertySSLSettings, pDict);
            CFRelease(pDict);
        }

        CFReadStreamOpen(ReadStream);

The above code causes a "CFNetwork internal error". If I remove the CFReadStreamSetProperty(ReadStream, kCFStreamPropertyHTTPAttemptPersistentConnection, kCFBooleanTrue) call then I no longer receive the error. It is also worth mentioning that I close the readstream once I have finished reading the data, but maybe I need to manage the stream pool myself?

Does anyone have any documentation, examples or tutorials they can refer me to? I'm keen to keep using the CFNetwork stuff as we have a client that insists we must minimize our use of Obj-C.

Downie
  • 193
  • 1
  • 13
  • I found more information on this subject. Apparently CFNetwork will re-use open connections on an open stream call. If there are no open connections then it will open a new one (makes sense). If you want persistent connections you must hold them open. This means that you must decide whether there is currently a connection open to the domain before opening a new stream (which will re-use the existing connection) and then close the old stream. – Downie Oct 24 '11 at 13:45

2 Answers2

1

I've been struggling with the same thing.

It seems the key is to make sure all the stream settings are exactly the same for the requests. In particular, you have to pass in the EXACT same dictionary object to kCFStreamPropertySSLSettings for all the requests. It isn't enough that they have the same contents, you have to re-use the exact same dictionary.

-1

add CFNetwork.framework

and #import <CFNetwork/CFHTTPStream.h>

Luke
  • 11,426
  • 43
  • 60
  • 69
  • I'm not sure I understand your answer. How does that help to enable persistent connections with CFHTTPStream? – Downie Feb 03 '12 at 11:21