Example #1
0
/* static */ void
_HttpContextHandleHasBytesAvailable(HttpContextRef context) {

	UInt8 buffer[2048];
	
	// Try reading the bytes into the buffer.
	CFIndex bytesRead = CFReadStreamRead(context->_inStream, buffer, sizeof(buffer));
	
	// Reset the timeout.
	CFRunLoopTimerSetNextFireDate(context->_timer, CFAbsoluteTimeGetCurrent() + kTimeOutInSeconds);
	
	// If there wasn't an error (-1) and not end (0), process the data.
	if (bytesRead > 0) {
		
		// Add the bytes of data to the receive buffer.
		CFDataAppendBytes(context->_rcvdBytes, buffer, bytesRead);

		// Parse recieved data
        int result = HTTPParseRequest(context);      
        
        if ( result == 1 ) {
            // HTTP message is fully loaded, process it
            HTTPProcessMessage(context);
			
			// Reset the timeout.
			CFRunLoopTimerSetNextFireDate(context->_timer, CFAbsoluteTimeGetCurrent() + kTimeOutInSeconds);
        }
        
        // If the ouput stream can write, try sending the bytes.
		if (result != 0 && CFWriteStreamCanAcceptBytes(context->_outStream))
			_HttpContextHandleCanAcceptBytes(context);
	}
}
static CFIndex formRead(CFReadStreamRef, UInt8* buffer, CFIndex bufferLength, CFStreamError* error, Boolean* atEOF, void* context)
{
    FormStreamFields* form = static_cast<FormStreamFields*>(context);

    while (form->currentStream) {
        CFIndex bytesToRead = bufferLength;
        if (form->currentStreamRangeLength != BlobDataItem::toEndOfFile && form->currentStreamRangeLength < bytesToRead)
            bytesToRead = static_cast<CFIndex>(form->currentStreamRangeLength);
        CFIndex bytesRead = CFReadStreamRead(form->currentStream, buffer, bytesToRead);
        if (bytesRead < 0) {
            *error = CFReadStreamGetError(form->currentStream);
            return -1;
        }
        if (bytesRead > 0) {
            error->error = 0;
            *atEOF = FALSE;
            form->bytesSent += bytesRead;
            if (form->currentStreamRangeLength != BlobDataItem::toEndOfFile)
                form->currentStreamRangeLength -= bytesRead;

            return bytesRead;
        }
        openNextStream(form);
    }

    error->error = 0;
    *atEOF = TRUE;
    return 0;
}
CFDataRef WebApiClientMD5DigestCreateWithFilePath(CFStringRef filePath, size_t bufferSize) {
	
	// Declare needed variables
	CFDataRef result = NULL;
	CFReadStreamRef readStream = NULL;
	
	// Get the file URL
	CFURLRef fileURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, (CFStringRef)filePath, kCFURLPOSIXPathStyle, (Boolean)false);
	if ( fileURL ) {
		// Create and open the read stream
		readStream = CFReadStreamCreateWithFile(kCFAllocatorDefault, fileURL);
		if ( readStream ) {
			Boolean didSucceed = CFReadStreamOpen(readStream);
			if ( didSucceed ) {
				// Initialize the hash object
				CC_MD5_CTX hashObject;
				CC_MD5_Init(&hashObject);
				
				// Make sure chunkSizeForReadingData is valid
				if ( bufferSize < 1 ) {
					bufferSize = FileHashDefaultChunkSizeForReadingData;
				}
				
				// Feed the data to the hash object
				bool hasMoreData = true;
				while ( hasMoreData ) {
					uint8_t buffer[bufferSize];
					CFIndex readBytesCount = CFReadStreamRead(readStream, (UInt8 *)buffer, (CFIndex)sizeof(buffer));
					if ( readBytesCount == -1 ) break;
					if ( readBytesCount == 0 ) {
						hasMoreData = false;
						continue;
					}
					CC_MD5_Update(&hashObject, (const void *)buffer, (CC_LONG)readBytesCount);
				}
				
				// Check if the read operation succeeded
				didSucceed = !hasMoreData;
				
				// Compute the hash digest
				unsigned char digest[CC_MD5_DIGEST_LENGTH];
				CC_MD5_Final(digest, &hashObject);
				
				// Abort if the read operation failed
				if ( didSucceed ) {
					result = CFDataCreate(kCFAllocatorDefault, digest, CC_MD5_DIGEST_LENGTH);
				}
			}
		}
	}
	
	if ( readStream ) {
		CFReadStreamClose(readStream);
		CFRelease(readStream);
	}
	if ( fileURL ) {
		CFRelease(fileURL);
	}
	return result;
}
Example #4
0
void SocketStreamHandle::readStreamCallback(CFStreamEventType type)
{
    switch(type) {
    case kCFStreamEventNone:
        break;
    case kCFStreamEventOpenCompleted:
        break;
    case kCFStreamEventHasBytesAvailable: {
        if (m_connectingSubstate == WaitingForConnect) {
            if (m_connectionType == CONNECTProxy) {
                RetainPtr<CFHTTPMessageRef> proxyResponse(AdoptCF, wkCopyCONNECTProxyResponse(m_readStream.get(), m_httpsURL.get()));
                if (proxyResponse && (407 == CFHTTPMessageGetResponseStatusCode(proxyResponse.get()))) {
                    addCONNECTCredentials(proxyResponse.get());
                    return;
                }
            }
        } else if (m_connectingSubstate == WaitingForCredentials)
            break;

        if (m_connectingSubstate == WaitingForConnect) {
            m_connectingSubstate = Connected;
            m_state = Open;

            RefPtr<SocketStreamHandle> protect(this); // The client can close the handle, potentially removing the last reference.
            m_client->didOpen(this);
            if (m_state == Closed)
                break;
            // Fall through.
        } else if (m_state == Closed)
            break;

        ASSERT(m_state == Open);
        ASSERT(m_connectingSubstate == Connected);

        CFIndex length;
        UInt8 localBuffer[1024]; // Used if CFReadStreamGetBuffer couldn't return anything.
        const UInt8* ptr = CFReadStreamGetBuffer(m_readStream.get(), 0, &length);
        if (!ptr) {
            length = CFReadStreamRead(m_readStream.get(), localBuffer, sizeof(localBuffer));
            ptr = localBuffer;
        }

        m_client->didReceiveData(this, reinterpret_cast<const char*>(ptr), length);

        break;
    }
    case kCFStreamEventCanAcceptBytes:
        ASSERT_NOT_REACHED();
        break;
    case kCFStreamEventErrorOccurred: {
        CFStreamError error = CFReadStreamGetError(m_readStream.get());
        m_client->didFail(this, SocketStreamError(error.error)); // FIXME: Provide a sensible error.
        break;
    }
    case kCFStreamEventEndEncountered:
        platformClose();
        break;
    }
}
static void readDataFromStream(mailstream_low * s)
{
  struct mailstream_cfstream_data * cfstream_data;
  
  cfstream_data = (struct mailstream_cfstream_data *) s->data;
  
  cfstream_data->readResult = CFReadStreamRead(cfstream_data->readStream,
                                               cfstream_data->readBuffer,
                                               cfstream_data->readBufferSize);
  //fprintf(stderr, "data read %i\n", (int) cfstream_data->readResult);
}
void HTTPLoader::readStreamCallback(CFReadStreamRef stream, CFStreamEventType type, void *userData)
{
  HTTPLoader* loader = static_cast<HTTPLoader*>(userData);
  
  CFTypeRef response = CFReadStreamCopyProperty(stream, 
                                                kCFStreamPropertyHTTPResponseHeader);
  if (loader->mFileBytes == 0) {
    CFHTTPMessageRef message = (CFHTTPMessageRef)CFReadStreamCopyProperty(stream, kCFStreamPropertyHTTPResponseHeader);
    CFDictionaryRef headerFields = CFHTTPMessageCopyAllHeaderFields(message);
    CFTypeRef totalByteSize = CFDictionaryGetValue(headerFields, CFSTR("Content-Length"));
    loader->mFileBytes = CFStringGetIntValue((CFStringRef)totalByteSize);
    CFRelease(message);
    CFRelease(headerFields);
  }
  
  CFIndex code = CFHTTPMessageGetResponseStatusCode((CFHTTPMessageRef)response);
  CFRelease(response);
  
  if (code != 200) {
    std::cout << "read stream error : code = " << code << std::endl;
    return;
  }
  
  switch (type) {
    case kCFStreamEventHasBytesAvailable: {
      UInt8 bytes[32768];
      CFIndex length = CFReadStreamRead(stream, bytes, 32768);
      if (length == -1) return;
      loader->mNumberOfReceivedByteSize += length;
      NetworkEvent e(kNetworkEventDataReceived);
      e.setReceivedByteSize(length);
      e.setReceivedData(bytes);
      e.setProgress((float)loader->mNumberOfReceivedByteSize / (float)loader->mFileBytes);
      loader->invoke(e);
      break;
    }
    case kCFStreamEventErrorOccurred: {
      std::cout << "kCFStreamEventErrorOccurred" << std::endl;
      NetworkEvent e(kNetworkEventErrorOccured);
      e.setErrorCode(code);
      loader->invoke(e);
      break;
    }
    case kCFStreamEventEndEncountered: {
      NetworkEvent e(kNetworkEventComplete);
      e.setProgress(1.0);
      loader->invoke(e);
    }
    default:
      break;
  }
}
Example #7
0
    std::vector<UInt8> TCPStream_CFNetwork::readData()
    {
        UInt8 buffer[1024];
        std::vector<UInt8> data;

        while (CFReadStreamHasBytesAvailable(inputStream)) {
            CFIndex bytesRead = CFReadStreamRead(inputStream, buffer, sizeof(buffer) - 1);
            if (bytesRead == -1) {
                break;
            }

            data.reserve((data.size() + bytesRead));
            data.insert(data.end(), buffer, buffer + bytesRead);
        }

        return data;
    }
Example #8
0
static void IPStreamCallback(CFReadStreamRef stream, CFStreamEventType eventType, void *clientCallBackInfo)
{
	CFMutableDataRef responseData = (CFMutableDataRef)clientCallBackInfo;

	if(eventType & kCFStreamEventHasBytesAvailable)
	{
		UInt8 buffer[1024];
		CFIndex read;

		do {
			read = CFReadStreamRead(stream, buffer, sizeof(buffer));
			if(read > 0)
				CFDataAppendBytes(responseData, buffer, read);

		} while(read > 0);
	}

	if(eventType & (kCFStreamEventEndEncountered | kCFStreamEventErrorOccurred))
	{
		if((eventType & kCFStreamEventEndEncountered) && publicIPState == IPStateFetching)
		{
			if(publicIPData)
				CFRelease(publicIPData);

			publicIPData = CFDataCreateCopy(kCFAllocatorDefault, responseData);
			publicIPState = IPStateFetched;
		}

		if(eventType & kCFStreamEventErrorOccurred)
		{
			if(publicIPData)
				CFRelease(publicIPData);

			publicIPData = NULL;
			publicIPState = IPStateInvalid;
		}

		CFReadStreamClose(stream);
		CFReadStreamSetClient(stream, 0, NULL, NULL);
		CFReadStreamUnscheduleFromRunLoop(stream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
		CFRelease(stream);

		CFRelease(responseData);
	}
}
Example #9
0
SInt64 HTTPInputSource::Read(void *buffer, SInt64 byteCount)
{
	if(!IsOpen())
		return -1;

	CFStreamStatus status = CFReadStreamGetStatus(mReadStream);
		
	if(kCFStreamStatusAtEnd == status)
		return 0;
	else if(kCFStreamStatusNotOpen == status || kCFStreamStatusClosed == status || kCFStreamStatusError == status)
		return -1;

	CFIndex bytesRead = CFReadStreamRead(mReadStream, static_cast<UInt8 *>(buffer), byteCount);

	mOffset += bytesRead;

	return bytesRead;
}
CFDictionaryRef download_file(int socket, CFDictionaryRef dict)
{
    UInt8 buffer[8192];
    CFIndex bytesRead;

    CFStringRef path = CFDictionaryGetValue(dict, CFSTR("Path"));
    if(path == NULL || CFGetTypeID(path) != CFStringGetTypeID())
        return NULL;
    CFMutableDictionaryRef out  = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);	

    CFURLRef fileURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, path, kCFURLPOSIXPathStyle, FALSE);
    CFReadStreamRef stream = CFReadStreamCreateWithFile(kCFAllocatorDefault, fileURL);
    CFRelease(fileURL);
    if(!CFReadStreamOpen(stream))
    {
        CFErrorRef error = CFReadStreamCopyError(stream);
        if (error != NULL)
        {
            CFStringRef errorDesc = CFErrorCopyDescription(error);
            CFDictionaryAddValue(out, CFSTR("Error"), errorDesc);
            CFRelease(errorDesc);
            CFRelease(error);
        }
        CFRelease(stream);
        return out;
    }
    CFMutableDataRef data = CFDataCreateMutable(kCFAllocatorDefault, 0);

    while(CFReadStreamHasBytesAvailable(stream))
    {
        if((bytesRead = CFReadStreamRead(stream, buffer, 8192)) <= 0)
            break;
        CFDataAppendBytes(data, buffer, bytesRead);
    }
    CFReadStreamClose(stream);
    CFRelease(stream);

    CFDictionaryAddValue(out, CFSTR("Data"), data);
    CFRelease(data);

    return out;
}
Example #11
0
void HTTP_Stream::readCallBack(CFReadStreamRef stream, CFStreamEventType eventType, void *clientCallBackInfo)
{
    HTTP_Stream *THIS = static_cast<HTTP_Stream*>(clientCallBackInfo);
    
    if (!THIS->m_delegate) {
        return;
    }
    
    switch (eventType) {
        case kCFStreamEventHasBytesAvailable: {
            if (!THIS->m_httpReadBuffer) {
                THIS->m_httpReadBuffer = new UInt8[STREAM_BUFSIZ];
            }
            
            CFIndex bytesRead = CFReadStreamRead(stream, THIS->m_httpReadBuffer, STREAM_BUFSIZ);
            
            if (bytesRead < 0) {
                THIS->m_delegate->streamErrorOccurred();
                break;
            }
            
            if (bytesRead > 0) {
                THIS->parseHttpHeadersIfNeeded(THIS->m_httpReadBuffer, bytesRead);
                
                if (THIS->m_icyStream) {
                    THIS->parseICYStream(THIS->m_httpReadBuffer, bytesRead);
                } else {
                    THIS->m_delegate->streamHasBytesAvailable(THIS->m_httpReadBuffer, bytesRead);
                }
            } 
            break;
        }
        case kCFStreamEventEndEncountered: {
            THIS->m_delegate->streamEndEncountered();
            break;
        }
        case kCFStreamEventErrorOccurred: {
            THIS->m_delegate->streamErrorOccurred();
            break;
        }
    }
}
Example #12
0
    OSStatus TCPStream_CFNetwork::secureTransportReadCallback (SSLConnectionRef connection,
                                                 void *data,
                                                 size_t *dataLength)
    {
        auto actualStream = reinterpret_cast<TCPStream_CFNetwork const *>(connection);

        if (!CFReadStreamHasBytesAvailable(actualStream->inputStream)) {
            *dataLength = 0;
            return errSSLWouldBlock;
        }

        auto bytesRead = CFReadStreamRead(actualStream->inputStream, reinterpret_cast<UInt8 *>(data), *dataLength);

        if (bytesRead < *dataLength) {
            *dataLength = bytesRead;
            return errSSLWouldBlock;
        }

        return noErr;
    }
Example #13
0
ssize_t SSLImpl::recv(char *buf, size_t size, int *wouldblock, void *storage)
{
    ssl_data_t *data = (ssl_data_t*)storage;
    
    if (!CFReadStreamHasBytesAvailable(data->readStream)) {
        *wouldblock = 1;
        return -1;
    }
    
    *wouldblock = 0;
    
    CFIndex rc = CFReadStreamRead(data->readStream, (UInt8*)buf, size);
    if (rc < 0) {
        CFStreamError err = CFReadStreamGetError(data->readStream);
        report_error("SSL recv failed", &err);
        return -1;
    }
    
    return rc;
    
}
Example #14
0
CFDataRef createDataFromURL( CFURLRef url )
{
	CFMutableDataRef fileContent = CFDataCreateMutable(kCFAllocatorDefault, 0);
    CFReadStreamRef stream = CFReadStreamCreateWithFile(kCFAllocatorDefault, url);

    if (stream) {
        if (CFReadStreamOpen(stream)) {
            UInt8 buffer[BUFFERSIZE];
            CFIndex bytesRead;
            do {
                bytesRead = CFReadStreamRead(stream, buffer, sizeof(buffer));
                if (bytesRead > 0) {
                    CFDataAppendBytes(fileContent, buffer, bytesRead);
                }
            } while (bytesRead > 0);
            CFReadStreamClose(stream);
        }
        CFRelease(stream);
    }
    
	return fileContent;
}
static CFIndex formRead(CFReadStreamRef stream, UInt8* buffer, CFIndex bufferLength, CFStreamError* error, Boolean* atEOF, void* context)
{
    FormStreamFields* form = static_cast<FormStreamFields*>(context);

    while (form->currentStream) {
        CFIndex bytesRead = CFReadStreamRead(form->currentStream, buffer, bufferLength);
        if (bytesRead < 0) {
            *error = CFReadStreamGetError(form->currentStream);
            return -1;
        }
        if (bytesRead > 0) {
            error->error = 0;
            *atEOF = FALSE;
            return bytesRead;
        }
        openNextStream(form);
    }

    error->error = 0;
    *atEOF = TRUE;
    return 0;
}
Example #16
0
void Caching_Stream::readMetaData()
{
    if (!m_metaDataUrl) {
        return;
    }
    
    CFReadStreamRef readStream = CFReadStreamCreateWithFile(kCFAllocatorDefault, m_metaDataUrl);
    
    if (readStream) {
        if (CFReadStreamOpen(readStream)) {
            
            UInt8 buf[1024];
            
            CFIndex bytesRead = CFReadStreamRead(readStream, buf, 1024);
            
            if (bytesRead > 0) {
                CFStringRef contentType = CFStringCreateWithBytes(kCFAllocatorDefault, buf, bytesRead, kCFStringEncodingUTF8, false);
                
                if (contentType) {
                    if (m_fileStream) {
                        CS_TRACE("Setting the content type of the file stream based on the meta data\n");
                        CS_TRACE_CFSTRING(contentType);
                        
                        m_fileStream->setContentType(contentType);
                    }
                    
                    CFRelease(contentType);
                }
            }
            
            CFReadStreamClose(readStream);
        }
        
        CFRelease(readStream);
    }
}
static void handle_server_response(CFReadStreamRef stream,
    CFStreamEventType type, void *info) {
    asynchttp_t *http = (asynchttp_t *)info;
    if (!http->stream) {
        secerror("Avoiding crash due to CFReadStream invoking us after we called CFReadStreamSetDispatchQueue(stream, NULL) on a different block on our serial queue");
        return;
    }

    switch (type) {
    case kCFStreamEventHasBytesAvailable:
    {
        UInt8 buffer[POST_BUFSIZE];
        CFIndex length;
        do {
#if 1
            length = CFReadStreamRead(stream, buffer, sizeof(buffer));
#else
            const UInt8 *buffer = CFReadStreamGetBuffer(stream, -1, &length);
#endif
            secdebug("http",
                "stream: %@ kCFStreamEventHasBytesAvailable read: %lu bytes",
                stream, length);
            if (length < 0) {
                /* Negative length == error */
                asynchttp_complete(http);
                break;
            } else if (length > 0) {
                //CFHTTPMessageAppendBytes(http->response, buffer, length);
                CFDataAppendBytes(http->data, buffer, length);
            } else {
                /* Read 0 bytes, are we are done or do we wait for
                   kCFStreamEventEndEncountered? */
                asynchttp_complete(http);
                break;
            }
        } while (CFReadStreamHasBytesAvailable(stream));
        break;
    }
    case kCFStreamEventErrorOccurred:
    {
        CFStreamError error = CFReadStreamGetError(stream);

        secdebug("http",
            "stream: %@ kCFStreamEventErrorOccurred domain: %ld error: %ld",
            stream, error.domain, (long) error.error);

        if (error.domain == kCFStreamErrorDomainPOSIX) {
            ocspdErrorLog("CFReadStream posix: %s", strerror(error.error));
        } else if (error.domain == kCFStreamErrorDomainMacOSStatus) {
            ocspdErrorLog("CFReadStream osstatus: %"PRIstatus, error.error);
        } else {
            ocspdErrorLog("CFReadStream domain: %ld error: %"PRIstatus,
                error.domain, error.error);
        }
        asynchttp_complete(http);
        break;
    }
    case kCFStreamEventEndEncountered:
    {
        http->response = (CFHTTPMessageRef)CFReadStreamCopyProperty(
            stream, kCFStreamPropertyHTTPResponseHeader);
        secdebug("http", "stream: %@ kCFStreamEventEndEncountered hdr: %@",
            stream, http->response);
        CFHTTPMessageSetBody(http->response, http->data);
        asynchttp_complete(http);
        break;
    }
    default:
        ocspdErrorLog("handle_server_response unexpected event type: %lu",
            type);
        break;
    }
}
Example #18
0
/* MyUploadCallBack is the stream callback for the CFFTPStream during an upload operation. 
Its main purpose is to wait for space to become available in the FTP stream (the write stream), 
and then read bytes from the file stream (the read stream) and write them to the FTP stream. */
static void
MyUploadCallBack(CFWriteStreamRef writeStream, CFStreamEventType type, void * clientCallBackInfo)
{
    MyStreamInfo     *info = (MyStreamInfo *)clientCallBackInfo;
    CFIndex          bytesRead;
    CFIndex          bytesAvailable;
    CFIndex          bytesWritten;
    CFStreamError    error;
    
    assert(writeStream != NULL);
    assert(info        != NULL);
    assert(info->writeStream == writeStream);

    switch (type) {

        case kCFStreamEventOpenCompleted:
            fprintf(stderr, "Open complete\n");
            break;
        case kCFStreamEventCanAcceptBytes:

            /* The first thing we do is check to see if there's some leftover data that we read
            in a previous callback, which we were unable to upload for whatever reason. */
            if (info->leftOverByteCount > 0) {
                bytesRead = 0;
                bytesAvailable = info->leftOverByteCount;
            } else {
                /* If not, we try to read some more data from the file.  CFReadStreamRead will 
                return the number of bytes read, or -1 if an error occurs preventing 
                any bytes from being read, or 0 if the stream's end was encountered. */
                bytesRead = CFReadStreamRead(info->readStream, info->buffer, kMyBufferSize);
                if (bytesRead < 0) {
                    fprintf(stderr, "CFReadStreamRead returned %ld\n", bytesRead);
                    goto exit;
                }
                bytesAvailable = bytesRead;
            }
//            bytesWritten = 0;
            
            if (bytesAvailable == 0) {
                /* We've hit the end of the file being uploaded.  Shut everything down. 
                Previous versions of this sample would terminate the upload stream 
                by writing zero bytes to the stream.  After discussions with CF engineering, 
                we've decided that it's better to terminate the upload stream by just 
                closing the stream. */
                fprintf(stderr, "\nEnd up uploaded file; closing down\n");
                goto exit;
            } else {

                /* CFWriteStreamWrite returns the number of bytes successfully written, -1 if an error has
                occurred, or 0 if the stream has been filled to capacity (for fixed-length streams).
                If the stream is not full, this call will block until at least one byte is written. 
                However, as we're in the kCFStreamEventCanAcceptBytes callback, we know that at least 
                one byte can be written, so we won't block. */

                bytesWritten = CFWriteStreamWrite(info->writeStream, info->buffer, bytesAvailable);
                if (bytesWritten > 0) {

                    info->totalBytesWritten += bytesWritten;
                    
                    /* If we couldn't upload all the data that we read, we temporarily store the data in our MyStreamInfo
                    context until our CFWriteStream callback is called again with a kCFStreamEventCanAcceptBytes event. 
                    Copying the data down inside the buffer is not the most efficient approach, but it makes the code 
                    significantly easier. */
                    if (bytesWritten < bytesAvailable) {
                        info->leftOverByteCount = bytesAvailable - bytesWritten;
                        memmove(info->buffer, info->buffer + bytesWritten, info->leftOverByteCount);
                    } else {
                        info->leftOverByteCount = 0;
                    }
                } else if (bytesWritten < 0) {
                    fprintf(stderr, "CFWriteStreamWrite returned %ld\n", bytesWritten);
                    /* If CFWriteStreamWrite failed, the write stream is dead.  We will clean up 
                    when we get kCFStreamEventErrorOccurred. */
                }
            }
            
            /* Print a status update if we made any forward progress. */
            if ( (bytesRead > 0) || (bytesWritten > 0) ) {
                fprintf(stderr, "\rRead %7ld bytes; Wrote %8ld bytes", bytesRead, info->totalBytesWritten);
            }
            break;
        case kCFStreamEventErrorOccurred:
            error = CFWriteStreamGetError(info->writeStream);
            fprintf(stderr, "CFReadStreamGetError returned (%ld, %ld)\n", error.domain, error.error);
            goto exit;
        case kCFStreamEventEndEncountered:
            fprintf(stderr, "\nUpload complete\n");
            goto exit;
        default:
            fprintf(stderr, "Received unexpected CFStream event (%ld)", type);
            break;
    }
    return;
    
exit:
    MyStreamInfoDestroy(info);
    CFRunLoopStop(CFRunLoopGetCurrent());
    return;
}
Example #19
0
/* MyDirectoryListingCallBack is the stream callback for the CFFTPStream during a directory 
list operation. Its main purpose is to read bytes off the FTP stream, which is returning bytes 
of the directory listing, parse them, and 'pretty' print the resulting directory entries. */
static void
MyDirectoryListingCallBack(CFReadStreamRef readStream, CFStreamEventType type, void * clientCallBackInfo)
{
    MyStreamInfo     *info = (MyStreamInfo *)clientCallBackInfo;
    CFIndex          bytesRead;
    CFStreamError    error;
    CFDictionaryRef  parsedDict;
    
    assert(readStream != NULL);
    assert(info       != NULL);
    assert(info->readStream == readStream);

    switch (type) {

        case kCFStreamEventOpenCompleted:
            fprintf(stderr, "Open complete\n");
            break;
        case kCFStreamEventHasBytesAvailable:
        
            /* When we get here, there are bytes to be read from the stream.  There are two cases:
            either info->leftOverByteCount is zero, in which case we complete processed the last 
            buffer full of data (or we're at the beginning of the listing), or 
            info->leftOverByteCount is non-zero, in which case there are that many bytes at the 
            start of info->buffer that were left over from the last time that we were called. 
            By definition, any left over bytes were insufficient to form a complete directory 
            entry.
            
            In both cases, we just read the next chunk of data from the directory listing stream 
            and append it to our buffer.  We then process the buffer to see if it now contains 
            any complete directory entries. */

            /* CFReadStreamRead will return the number of bytes read, or -1 if an error occurs
            preventing any bytes from being read, or 0 if the stream's end was encountered. */
            bytesRead = CFReadStreamRead(info->readStream, info->buffer + info->leftOverByteCount, kMyBufferSize - info->leftOverByteCount);
            if (bytesRead > 0) {
                const UInt8 *   nextByte;
                CFIndex         bytesRemaining;
                CFIndex         bytesConsumedThisTime;

                /* Parse directory entries from the buffer until we either run out of bytes 
                or we stop making forward progress (indicating that the buffer does not have 
                enough bytes of valid data to make a complete directory entry). */

                nextByte       = info->buffer;
                bytesRemaining = bytesRead + info->leftOverByteCount;
                do
                {                    

                    /* CFFTPCreateParsedResourceListing parses a line of file or folder listing
                    of Unix format, and stores the extracted result in a CFDictionary. */
                    bytesConsumedThisTime = CFFTPCreateParsedResourceListing(NULL, nextByte, bytesRemaining, &parsedDict);
                    if (bytesConsumedThisTime > 0) {

                        /* It is possible for CFFTPCreateParsedResourceListing to return a positive number 
                        but not create a parse dictionary.  For example, if the end of the listing text 
                        contains stuff that can't be parsed, CFFTPCreateParsedResourceListing returns 
                        a positive number (to tell the calle that it's consumed the data), but doesn't 
                        create a parse dictionary (because it couldn't make sens of the data).
                        So, it's important that we only try to print parseDict if it's not NULL. */
                        
                        if (parsedDict != NULL) {
                            MyPrintDirectoryListing(parsedDict);
                            CFRelease(parsedDict);
                        }

                        nextByte       += bytesConsumedThisTime;
                        bytesRemaining -= bytesConsumedThisTime;

                    } else if (bytesConsumedThisTime == 0) {
                        /* This should never happen because we supply a pretty large buffer. 
                        Still, we handle it by leaving the loop, which leaves the remaining 
                        bytes in the buffer. */
                    } else if (bytesConsumedThisTime == -1) {
                        fprintf(stderr, "CFFTPCreateParsedResourceListing parse failure\n");
                        goto exit;
                    }

                } while ( (bytesRemaining > 0) && (bytesConsumedThisTime > 0) );
                
                /* If any bytes were left over, leave them in the buffer for next time. */
                if (bytesRemaining > 0) {
                    memmove(info->buffer, nextByte, bytesRemaining);                    
                }
                info->leftOverByteCount = bytesRemaining;
            } else {
                /* If bytesRead < 0, we've hit an error.  If bytesRead == 0, we've hit the end of the 
                directory listing.  In either case, we do nothing, and rely on CF to call us with 
                kCFStreamEventErrorOccurred or kCFStreamEventEndEncountered in order for us to do our 
                clean up. */
            }
            break;
        case kCFStreamEventErrorOccurred:
            error = CFReadStreamGetError(info->readStream);
            fprintf(stderr, "CFReadStreamGetError returned (%ld, %ld)\n", error.domain, error.error);
            goto exit;
        case kCFStreamEventEndEncountered:
            fprintf(stderr, "Listing complete\n");
            goto exit;
        default:
            fprintf(stderr, "Received unexpected CFStream event (%ld)", type);
            break;
    }
    return;

exit:
    MyStreamInfoDestroy(info);
    CFRunLoopStop(CFRunLoopGetCurrent());
    return;
}
Example #20
0
void HTTP_Stream::readCallBack(CFReadStreamRef stream, CFStreamEventType eventType, void *clientCallBackInfo)
{
    HTTP_Stream *THIS = static_cast<HTTP_Stream*>(clientCallBackInfo);
    
    Stream_Configuration *config = Stream_Configuration::configuration();
    
    switch (eventType) {
        case kCFStreamEventHasBytesAvailable: {
            if (!THIS->m_httpReadBuffer) {
                THIS->m_httpReadBuffer = new UInt8[config->httpConnectionBufferSize];
            }
            
            while (CFReadStreamHasBytesAvailable(stream)) {
                if (!THIS->m_scheduledInRunLoop) {
                    /*
                     * This is critical - though the stream has data available,
                     * do not try to feed the audio queue with data, if it has
                     * indicated that it doesn't want more data due to buffers
                     * full.
                     */
                    THIS->m_readPending = true;
                    break;
                }
                
                CFIndex bytesRead = CFReadStreamRead(stream, THIS->m_httpReadBuffer, config->httpConnectionBufferSize);
                
                if (CFReadStreamGetStatus(stream) == kCFStreamStatusError ||
                    bytesRead < 0) {
                    
#if defined (HS_DEBUG)
                    CFErrorRef streamError = CFReadStreamCopyError(stream);
                    
                    if (streamError) {
                        CFStringRef errorDesc = CFErrorCopyDescription(streamError);
                        
                        if (errorDesc) {
                            HS_TRACE_CFSTRING(errorDesc);
                            
                            CFRelease(errorDesc);
                        }
                        
                        CFRelease(streamError);
                    }
#endif /* HS_DEBUG */
                    
                    if (THIS->m_delegate) {
                        THIS->m_delegate->streamErrorOccurred();
                    }
                    break;
                }
                
                if (bytesRead > 0) {
                    HS_TRACE("Read %li bytes\n", bytesRead);
                    
                    THIS->parseHttpHeadersIfNeeded(THIS->m_httpReadBuffer, bytesRead);
                    
    #ifdef INCLUDE_ID3TAG_SUPPORT
                    if (!THIS->m_icyStream && THIS->m_id3Parser->wantData()) {
                        THIS->m_id3Parser->feedData(THIS->m_httpReadBuffer, (UInt32)bytesRead);
                    }
    #endif
                    
                    if (THIS->m_icyStream) {
                        HS_TRACE("Parsing ICY stream\n");
                        
                        THIS->parseICYStream(THIS->m_httpReadBuffer, bytesRead);
                    } else {
                        if (THIS->m_delegate) {
                            HS_TRACE("Not an ICY stream; calling the delegate back\n");
                            
                            THIS->m_delegate->streamHasBytesAvailable(THIS->m_httpReadBuffer, (UInt32)bytesRead);
                        }
                    }
                }
            }
                
            break;
        }
        case kCFStreamEventEndEncountered: {
            if (THIS->m_delegate) {
                THIS->m_delegate->streamEndEncountered();
            }
            break;
        }
        case kCFStreamEventErrorOccurred: {
            if (THIS->m_delegate) {
                THIS->m_delegate->streamErrorOccurred();
            }
            break;
        }
    }
}
Example #21
0
CFStringRef FileMD5HashCreateWithPath(CFStringRef filePath, size_t chunkSizeForReadingData)
{
    CFStringRef result = NULL;
    CFReadStreamRef readStream = NULL;
    
    CFURLRef fileURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault,
                                                     (CFStringRef)filePath,
                                                     kCFURLPOSIXPathStyle,
                                                     (Boolean) false);
    
    if (!fileURL) {
        goto done;
    }
    
    readStream = CFReadStreamCreateWithFile(kCFAllocatorDefault,
                                            (CFURLRef)fileURL);
    
    if (!readStream) {
        goto done;
    }
    
    bool didSucceed = (bool)CFReadStreamOpen(readStream);
    
    if (!didSucceed) {
        goto done;
    }
    
    // Initialize the hash object
    CC_MD5_CTX hashObject;
    CC_MD5_Init(&hashObject);
    
    // Make sure the chunkSizeForReadindData is valid
    if (!chunkSizeForReadingData) {
        chunkSizeForReadingData = FileHashDefaultChunksSizeForReadingData;
    }
    
    // Feed the data to the hash object
    bool hasMoreData = true;
    while (hasMoreData) {
        uint8_t buffer[chunkSizeForReadingData];
        CFIndex readBytesCount = CFReadStreamRead(readStream,
                                                  (UInt8 *)buffer,
                                                  (CFIndex)sizeof(buffer));
        
        if (readBytesCount == -1) {
            break;
        }
        
        if (readBytesCount == 0) {
            hasMoreData = false;
            continue;
        }
        
        CC_MD5_Update(&hashObject, (const void *)buffer, (CC_LONG)readBytesCount);
    }
    
    // Check if the read operation has succeded
    didSucceed = !hasMoreData;
    
    // Compute the hash digest
    unsigned char digest[CC_MD5_DIGEST_LENGTH];
    CC_MD5_Final(digest, &hashObject);
    
    // Abort if the read operation fails
    if (!didSucceed) {
        goto done;
    }
    
    // Compute the string result
    char hash[2 * sizeof(digest) + 1];
    for (size_t i = 0; i < sizeof(digest); ++i) {
        snprintf(hash + (2 * i), 3, "%02x", (int)(digest[i]));
    }
    
    result = CFStringCreateWithCString(kCFAllocatorDefault, (const char *)hash, kCFStringEncodingUTF8);
    
    
    
done:
    if (readStream) {
        CFReadStreamClose(readStream);
        CFRelease(readStream);
    }
    
    if (fileURL) {
        CFRelease(fileURL);
    }
    
    return result;
}
Example #22
0
void HTTP_Stream::readCallBack(CFReadStreamRef stream, CFStreamEventType eventType, void *clientCallBackInfo)
{
    HTTP_Stream *THIS = static_cast<HTTP_Stream*>(clientCallBackInfo);
    
    switch (eventType) {
        case kCFStreamEventHasBytesAvailable: {
            if (!THIS->m_httpReadBuffer) {
                THIS->m_httpReadBuffer = new UInt8[STREAM_BUFSIZ];
            }
            
            while (CFReadStreamHasBytesAvailable(stream)) {
                if (!THIS->m_scheduledInRunLoop) {
                    /*
                     * This is critical - though the stream has data available,
                     * do not try to feed the audio queue with data, if it has
                     * indicated that it doesn't want more data due to buffers
                     * full.
                     */
                    THIS->m_readPending = true;
                    break;
                }
                
                CFIndex bytesRead = CFReadStreamRead(stream, THIS->m_httpReadBuffer, STREAM_BUFSIZ);
                
                if (CFReadStreamGetStatus(stream) == kCFStreamStatusError ||
                    bytesRead < 0) {
                    if (THIS->m_delegate) {
                        THIS->m_delegate->streamErrorOccurred();
                    }
                    break;
                }
                
                if (bytesRead > 0) {
                    THIS->parseHttpHeadersIfNeeded(THIS->m_httpReadBuffer, bytesRead);
                    
    #ifdef INCLUDE_ID3TAG_SUPPORT
                    if (THIS->m_id3Parser->wantData()) {
                        THIS->m_id3Parser->feedData(THIS->m_httpReadBuffer, (UInt32)bytesRead);
                    }
    #endif
                    
                    if (THIS->m_icyStream) {
                        THIS->parseICYStream(THIS->m_httpReadBuffer, bytesRead);
                    } else {
                        if (THIS->m_delegate) {
                            THIS->m_delegate->streamHasBytesAvailable(THIS->m_httpReadBuffer, (UInt32)bytesRead);
                        }
                    }
                }
            }
                
            break;
        }
        case kCFStreamEventEndEncountered: {
            if (THIS->m_delegate) {
                THIS->m_delegate->streamEndEncountered();
            }
            break;
        }
        case kCFStreamEventErrorOccurred: {
            if (THIS->m_delegate) {
                THIS->m_delegate->streamErrorOccurred();
            }
            break;
        }
    }
}
char* DotMacQuery::ReadStream (CFURLRef url, size_t &responseLength)
{
	SInt32 ito;
	CFNumberRef cfnTo = NULL;
	CFDictionaryRef proxyDict = NULL;
	
	// make a connection to the provided URL
	CFHTTPMessageRef httpRequestRef = CFHTTPMessageCreateRequest (kCFAllocatorDefault, CFSTR("GET"), url, kCFHTTPVersion1_1);
	if (httpRequestRef == NULL)
	{
		CSSMError::ThrowCSSMError (CSSMERR_DL_RECORD_NOT_FOUND);
	}
	
	// open the stream
	CFReadStreamRef httpStreamRef = CFReadStreamCreateForHTTPRequest (kCFAllocatorDefault, httpRequestRef);
	if (httpStreamRef == NULL)
	{
		CSSMError::ThrowCSSMError (CSSMERR_DL_RECORD_NOT_FOUND);
	}

	// set a reasonable timeout
	ito = READ_STREAM_TIMEOUT;
	cfnTo = CFNumberCreate(NULL, kCFNumberSInt32Type, &ito);
    if(!CFReadStreamSetProperty(httpStreamRef, _kCFStreamPropertyReadTimeout, cfnTo)) {
		// oh well - keep going 
	}
	
	/* set up possible proxy info */
	proxyDict = SCDynamicStoreCopyProxies(NULL);
	if(proxyDict) {
		CFReadStreamSetProperty(httpStreamRef, kCFStreamPropertyHTTPProxy, proxyDict);
	}

	if (CFReadStreamOpen (httpStreamRef) == false)
	{
		CFRelease(httpRequestRef);
		CFRelease(httpStreamRef);
		CFRelease(cfnTo);
		if(proxyDict) {
			CFRelease(proxyDict);
		}
		CSSMError::ThrowCSSMError (CSSMERR_DL_RECORD_NOT_FOUND);
	}
	
	char* response = (char*) malloc (kResponseIncrement);
	size_t responseBufferLength = kResponseIncrement;
	responseLength = 0;

	// read data from the stream
	CFIndex bytesRead = CFReadStreamRead (httpStreamRef, (UInt8*) response + responseLength, kResponseIncrement);
	while (bytesRead > 0)
	{
		responseLength += bytesRead;
		responseBufferLength = responseLength + kResponseIncrement;
		response = (char*) realloc (response, responseBufferLength);
		
		bytesRead = CFReadStreamRead (httpStreamRef, (UInt8*) response + responseLength, kResponseIncrement);
	}
	
	CFRelease (httpRequestRef);
	CFRelease (httpStreamRef);
	CFRelease(cfnTo);
	if(proxyDict) {
		CFRelease(proxyDict);
	}

	// check for error
	if (bytesRead < 0)
	{
		CSSMError::ThrowCSSMError (CSSMERR_DL_RECORD_NOT_FOUND);
	}
	
	return response;
}
CFDataRef
TSystemUtils::ReadDataFromURL ( CFURLRef url )
{

    CFMutableDataRef    data            = NULL;
    Boolean				result			= false;
	CFNumberRef         fileSizeNumber  = NULL;
    CFIndex             fileSize        = 0;
    UInt8 *             dataPtr         = NULL;
    UInt8 *             endPtr          = NULL;
    CFReadStreamRef     readStream      = NULL;
    CFIndex             bytesRead       = 0;
    
    result = CFURLCopyResourcePropertyForKey ( url, kCFURLFileSizeKey, &fileSizeNumber, NULL );
    require ( result, ErrorExit );
    
    result = CFNumberGetValue ( fileSizeNumber, kCFNumberCFIndexType, &fileSize );
    require ( result, ReleaseNumber );
    
    data = CFDataCreateMutable ( kCFAllocatorDefault, fileSize );
    require ( data, ReleaseNumber );
    
    CFDataSetLength ( data, fileSize );
    
    dataPtr = CFDataGetMutableBytePtr ( data );
    require ( dataPtr, ReleaseNumber );
    
    readStream = CFReadStreamCreateWithFile ( kCFAllocatorDefault, url );
    require ( readStream, ErrorExit );
    
    result = CFReadStreamOpen ( readStream );
    require ( result, ReleaseStream );
    
    endPtr  = ( UInt8 * ) dataPtr + fileSize;
    
    while ( dataPtr < endPtr )
    {

        bytesRead = CFReadStreamRead ( readStream, dataPtr, endPtr - dataPtr );

        if ( bytesRead > 0 )
        {
            
            dataPtr += bytesRead;
            
        }
        
    }
    
    CFReadStreamClose ( readStream );
    
    
ReleaseStream:
    
    
    CFRelease ( readStream );
    readStream = NULL;
    
    
ReleaseNumber:
    
    
    CFRelease ( fileSizeNumber );
    fileSizeNumber = NULL;
    
    
ErrorExit:
    
    
    return data;
    
}
CFStringRef GCCreateMD5HashWithPath(CFStringRef filePath)
{
    
    CFStringRef result = NULL;
    CFReadStreamRef readStream = NULL;
    
    CFURLRef fileURL =
    CFURLCreateWithFileSystemPath(kCFAllocatorDefault,
                                  (CFStringRef)filePath,
                                  kCFURLPOSIXPathStyle,
                                  (Boolean)false);
    if (!fileURL) goto done;
    
    readStream = CFReadStreamCreateWithFile(kCFAllocatorDefault,
                                            (CFURLRef)fileURL);
    if (!readStream) goto done;
    bool didSucceed = (bool)CFReadStreamOpen(readStream);
    if (!didSucceed) goto done;
    
    CC_MD5_CTX hashObject;
    CC_MD5_Init(&hashObject);
    
    bool hasMoreData = true;
    while (hasMoreData) {
        uint8_t buffer[GCFileChunkSize];
        CFIndex readBytesCount = CFReadStreamRead(readStream,
                                                  (UInt8 *)buffer,
                                                  (CFIndex)sizeof(buffer));
        if (readBytesCount == -1) break;
        if (readBytesCount == 0) {
            hasMoreData = false;
            continue;
        }
        CC_MD5_Update(&hashObject,
                      (const void *)buffer,
                      (CC_LONG)readBytesCount);
    }
    
    didSucceed = !hasMoreData;
    
    unsigned char digest[CC_MD5_DIGEST_LENGTH];
    CC_MD5_Final(digest, &hashObject);
    
    if (!didSucceed) goto done;
    
    char hash[2 * sizeof(digest) + 1];
    for (size_t i = 0; i < sizeof(digest); ++i) {
        snprintf(hash + (2 * i), 3, "%02x", (int)(digest[i]));
    }
    result = CFStringCreateWithCString(kCFAllocatorDefault,
                                       (const char *)hash,
                                       kCFStringEncodingUTF8);
    
done:
    
    if (readStream) {
        CFReadStreamClose(readStream);
        CFRelease(readStream);
    }
    if (fileURL) {
        CFRelease(fileURL);
    }
    return result;
}
void __CFReadStreamClientCallBack(CFReadStreamRef stream, CFStreamEventType eventType, void *clientCallBackInfo) {
    // Extract the context
    tnet_transport_t *transport = (tnet_transport_t *) clientCallBackInfo;
	transport_context_t *context = transport->context;
    
    /* lock context */
    tsk_safeobj_lock(context);
    
    // Extract the native socket
    CFDataRef data = CFReadStreamCopyProperty(stream, kCFStreamPropertySocketNativeHandle);
    CFSocketNativeHandle fd;
    CFDataGetBytes(data, CFRangeMake(0, sizeof(CFSocketNativeHandle)), (UInt8*) &fd);
    CFRelease(data);
    transport_socket_t *sock = (transport_socket_t *) getSocket(context, fd);
    
    switch(eventType) {
        case kCFStreamEventOpenCompleted:
        {
            TSK_DEBUG_INFO("__CFReadStreamClientCallBack --> kCFStreamEventOpenCompleted");
            break;
        }
        case kCFStreamEventHasBytesAvailable:
        {
            tsk_size_t len = 0;
            void *buffer = 0;
            tnet_transport_event_t* e;
            
            // Allocate a standard buffer
            len = TNET_BUFFER_SIZE;
            if (!(buffer = tsk_calloc(len, sizeof(uint8_t)))) {
                TSK_DEBUG_ERROR("TSK_CALLOC FAILED.");
                break;
            }
            
            // Process to read data
            CFIndex index = CFReadStreamRead(stream, buffer, TNET_BUFFER_SIZE);
            len = index;
            
            TSK_DEBUG_INFO("__CFReadStreamClientCallBack --> %u bytes read", len);
            
            e = tnet_transport_event_create(event_data, transport->callback_data, sock->fd);
            e->data = buffer;
            e->size = len;
            
            TSK_RUNNABLE_ENQUEUE_OBJECT(TSK_RUNNABLE(transport), e);
            
            break;
        }
        case kCFStreamEventEndEncountered:
        case kCFStreamEventErrorOccurred:
        {
            // Get the error code
            CFErrorRef error = CFReadStreamCopyError(stream);
            CFIndex index = CFErrorGetCode(error);
            CFRelease(error);
                        
            TSK_DEBUG_INFO("__CFReadStreamClientCallBack --> Error %lu", index);
            
            TSK_RUNNABLE_ENQUEUE(transport, event_error, transport->callback_data, sock->fd);
            removeSocket(sock, context);
            break;
        }
        default:
        {
            // Not Implemented
            assert(42 == 0);
            break;
        }
    }
    
    /* unlock context */
    tsk_safeobj_unlock(context);
}
Example #27
0
nuiHTTPResponse* nuiHTTPRequest::SendRequest()
{
  char* pUrl = mUrl.Export();
	
  CFStringRef originalURLString = CFStringCreateWithCString(kCFAllocatorDefault, pUrl, kCFStringEncodingUTF8);
	
  CFStringRef preprocessedString =
  CFURLCreateStringByReplacingPercentEscapesUsingEncoding(kCFAllocatorDefault, originalURLString, CFSTR(""), kCFStringEncodingUTF8);
  CFStringRef urlString =
  CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, preprocessedString, NULL, NULL, kCFStringEncodingUTF8);
	
  free(pUrl);
  CFURLRef url = CFURLCreateWithString(kCFAllocatorDefault, urlString, NULL);
  CFRelease(urlString);
  
  char* pMeth = mMethod.Export(); 
  CFStringRef method = CFStringCreateWithCString(kCFAllocatorDefault, pMeth, kCFStringEncodingUTF8);
  free(pMeth);
  
  CFHTTPMessageRef req = CFHTTPMessageCreateRequest(kCFAllocatorDefault, method, url, kCFHTTPVersion1_1);
  
  CFStringRef userAgentField = CFSTR("User-Agent");
  CFStringRef userAgentName = CFSTR("nuiHTTP/2.0");
  CFHTTPMessageSetHeaderFieldValue(req, userAgentField, userAgentName);
  CFRelease(userAgentField);
  CFRelease(userAgentName);
  
  nuiHTTPHeaderMap::const_iterator end = mHeaders.end();
  for (nuiHTTPHeaderMap::const_iterator it = mHeaders.begin(); it != end; ++it)
  {
    char* pName = it->first.Export();
    char* pVal = it->second.Export();
    CFStringRef fieldName = CFStringCreateWithCString(kCFAllocatorDefault, pName, kCFStringEncodingUTF8);
    CFStringRef fieldValue = CFStringCreateWithCString(kCFAllocatorDefault, pVal, kCFStringEncodingUTF8);
    
    CFHTTPMessageSetHeaderFieldValue(req, fieldName, fieldValue);
    
    CFRelease(fieldName);
    CFRelease(fieldValue);
    delete pName;
    delete pVal;
  }
  
  CFDataRef body = NULL;
  if (mBody.size())
  {
    body = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, (UInt8*)&mBody[0], mBody.size(), kCFAllocatorNull);
    CFHTTPMessageSetBody(req, body);
  }
  
  CFReadStreamRef readStream = CFReadStreamCreateForHTTPRequest(kCFAllocatorDefault, req);
  CFReadStreamOpen(readStream);
  
  std::vector<char> buf;
  CFIndex pos = 0;
  CFIndex size = 0;
  bool cont = true;
  do
  {
    buf.resize(pos + 1024);
    size = CFReadStreamRead(readStream, (UInt8*)&buf[pos], 1024);
    if (size == -1)
    {
      return NULL;
    }
    else if (size == 0)
    {
      if (CFReadStreamGetStatus(readStream) == kCFStreamStatusAtEnd)
        cont = false;
      else
        nglThread::MsSleep(10);
    }
    
    pos += size;
  }
  while (cont);
  
  CFHTTPMessageRef responseHeader = (CFHTTPMessageRef)CFReadStreamCopyProperty(readStream, kCFStreamPropertyHTTPResponseHeader);
  
  CFStringRef statusLine = CFHTTPMessageCopyResponseStatusLine(responseHeader);
  CFIndex strSize = CFStringGetLength(statusLine)+1;
  char* pStatus = new char[strSize];
  CFStringGetCString(statusLine, pStatus, strSize, kCFStringEncodingUTF8);
  nglString status(pStatus);
  
  UInt32 statusCode = CFHTTPMessageGetResponseStatusCode(responseHeader);
  
  nuiHTTPResponse* pResponse = new nuiHTTPResponse(statusCode, status);
  pResponse->SetBody(&buf[0], pos);
  
  delete[] pStatus;
  
  CFDictionaryRef dict = CFHTTPMessageCopyAllHeaderFields(responseHeader);
  CFIndex valueCount = CFDictionaryGetCount(dict);
  const CFStringRef* pNames = new CFStringRef[valueCount];
  const CFStringRef* pValues = new CFStringRef[valueCount];
  CFDictionaryGetKeysAndValues(dict, (const void**)pNames, (const void**)pValues);
  for (CFIndex i = 0; i< valueCount; i++)
  {
    strSize = CFStringGetLength(pNames[i])+1;
    char* pName = new char[strSize];
    CFStringGetCString(pNames[i], pName, strSize, kCFStringEncodingUTF8);
    
    strSize = CFStringGetLength(pValues[i])+1;
    char* pVal = new char[strSize];
    CFStringGetCString(pValues[i], pVal, strSize, kCFStringEncodingUTF8);
    
    nglString name(pName);
    nglString val(pVal);
    pResponse->AddHeader(name, val);
    
    delete[] pName;
    delete[] pVal;
  }
  delete[] pNames;
  delete[] pValues;
  
  CFRelease(responseHeader);
  CFRelease(url);
  CFRelease(method);
  CFRelease(req);
  CFRelease(readStream);
  CFRelease(dict);
  CFRelease(statusLine);
  if (body)
    CFRelease(body);
  
  return pResponse;
}
void SocketStreamHandle::readStreamCallback(CFStreamEventType type)
{
    switch(type) {
    case kCFStreamEventNone:
        break;
    case kCFStreamEventOpenCompleted:
        break;
    case kCFStreamEventHasBytesAvailable: {
        if (m_connectingSubstate == WaitingForConnect) {
            if (m_connectionType == CONNECTProxy) {
                RetainPtr<CFHTTPMessageRef> proxyResponse(AdoptCF, wkCopyCONNECTProxyResponse(m_readStream.get(), m_httpsURL.get()));
                if (proxyResponse) {
                    CFIndex proxyResponseCode = CFHTTPMessageGetResponseStatusCode(proxyResponse.get());
                    switch (proxyResponseCode) {
                    case 200:
                        // Successful connection.
                        break;
                    case 407:
                        addCONNECTCredentials(proxyResponse.get());
                        return;
                    default:
                        m_client->didFailSocketStream(this, SocketStreamError(static_cast<int>(proxyResponseCode), m_url.string(), "Proxy connection could not be established"));
                        platformClose();
                        return;
                    }
                }
            }
        } else if (m_connectingSubstate == WaitingForCredentials)
            break;

        if (m_connectingSubstate == WaitingForConnect) {
            m_connectingSubstate = Connected;
            m_state = Open;
            m_client->didOpenSocketStream(this);
            if (m_state == Closed)
                break;
            // Fall through.
        } else if (m_state == Closed)
            break;

        ASSERT(m_state == Open);
        ASSERT(m_connectingSubstate == Connected);

        CFIndex length;
        UInt8 localBuffer[1024]; // Used if CFReadStreamGetBuffer couldn't return anything.
        const UInt8* ptr = CFReadStreamGetBuffer(m_readStream.get(), 0, &length);
        if (!ptr) {
            length = CFReadStreamRead(m_readStream.get(), localBuffer, sizeof(localBuffer));
            ptr = localBuffer;
        }

        m_client->didReceiveSocketStreamData(this, reinterpret_cast<const char*>(ptr), length);

        break;
    }
    case kCFStreamEventCanAcceptBytes:
        ASSERT_NOT_REACHED();
        break;
    case kCFStreamEventErrorOccurred: {
        RetainPtr<CFErrorRef> error(AdoptCF, CFReadStreamCopyError(m_readStream.get()));
        reportErrorToClient(error.get());
        break;
    }
    case kCFStreamEventEndEncountered:
        platformClose();
        break;
    }
}
static void read_entire_stream__file(
    SG_context* pCtx,
    CFReadStreamRef myReadStream,
    SG_pathname* pPath,
    CFHTTPMessageRef* pp,
    SG_bool b_progress
)
{
    CFHTTPMessageRef myResponse = NULL;
    CFIndex numBytesRead = 0;
    SG_file* pFile = NULL;
    SG_int64 content_length = 0;
    SG_int64 so_far = 0;

    SG_ERR_CHECK(  SG_file__open__pathname(pCtx, pPath, SG_FILE_CREATE_NEW | SG_FILE_WRONLY, 0644, &pFile)  );
    do
    {
        UInt8 buf[8192]; // TODO
        numBytesRead = CFReadStreamRead(myReadStream, buf, sizeof(buf));
        if( numBytesRead > 0 )
        {
            SG_ERR_CHECK(  SG_file__write(pCtx, pFile, numBytesRead, buf, NULL)  );
            if (!myResponse)
            {
                myResponse = (CFHTTPMessageRef)CFReadStreamCopyProperty(myReadStream, kCFStreamPropertyHTTPResponseHeader);
                CFStringRef contentLengthString = CFHTTPMessageCopyHeaderFieldValue(myResponse, CFSTR("Content-Length"));
                if (contentLengthString)
                {
                    // TODO 32 bit limit problem here
                    content_length = CFStringGetIntValue(contentLengthString);
                    CFRelease(contentLengthString);
                }
                if (b_progress)
                {
                    SG_ERR_CHECK(  SG_log__set_steps(pCtx, content_length / 1024, "KB")  );
                }
            }
            so_far += (SG_uint32) numBytesRead;
            if (b_progress)
            {
                SG_ERR_CHECK(  SG_log__set_finished(pCtx, so_far / 1024)  );
            }
        }
        else if( numBytesRead < 0 )
        {
            CFStreamError myErr = CFReadStreamGetError(myReadStream);
            // TODO clean this up
            if (myErr.domain == kCFStreamErrorDomainPOSIX)
            {
                if (ETIMEDOUT == myErr.error)
                {
                    usleep(5000);
                    numBytesRead = 0;
                }
                else
                {
                    // Interpret myErr.error as a UNIX errno.
                    SG_ERR_THROW(  SG_ERR_ERRNO(myErr.error)  );
                }
            }
            else if (myErr.domain == kCFStreamErrorDomainMacOSStatus)
            {
                // Interpret myErr.error as a MacOS error code.
                // TODO SG_ERR_THROW(  SG_ERR_MAC((OSStatus) myErr.error)  );
                SG_ERR_THROW(  SG_ERR_UNSPECIFIED  );
            }
        }
    } while( numBytesRead > 0 );

    SG_ERR_CHECK(  SG_file__close(pCtx, &pFile)  );

    if (!myResponse)
    {
        myResponse = (CFHTTPMessageRef)CFReadStreamCopyProperty(myReadStream, kCFStreamPropertyHTTPResponseHeader);
    }

    *pp = myResponse;
    myResponse = NULL;

fail:
    if (pFile)
    {
        SG_ERR_CHECK(  SG_file__close(pCtx, &pFile)  );
        // TODO delete it too
    }
    if (myResponse)
    {
        CFRelease(myResponse);
    }
}
static void read_entire_stream__string(
    SG_context* pCtx,
    CFReadStreamRef myReadStream,
    SG_string** ppstr,
    CFHTTPMessageRef* pp
)
{
    SG_string* pstr = NULL;
    CFHTTPMessageRef myResponse = NULL;
    CFIndex numBytesRead = 0;

    SG_ERR_CHECK(  SG_string__alloc__sz(pCtx, &pstr, "")  );
    do
    {
        UInt8 buf[8192]; // TODO
        numBytesRead = CFReadStreamRead(myReadStream, buf, sizeof(buf));
        if( numBytesRead > 0 )
        {
            SG_ERR_CHECK(  SG_string__append__buf_len(pCtx, pstr, buf, numBytesRead)  );

            if (!myResponse)
            {
                myResponse = (CFHTTPMessageRef)CFReadStreamCopyProperty(myReadStream, kCFStreamPropertyHTTPResponseHeader);
            }
        }
        else if( numBytesRead < 0 )
        {
            CFStreamError myErr = CFReadStreamGetError(myReadStream);
            // TODO clean this up
            if (myErr.domain == kCFStreamErrorDomainPOSIX)
            {
                if (ETIMEDOUT == myErr.error)
                {
                    usleep(5000);
                    numBytesRead = 0;
                }
                else
                {
                    // Interpret myErr.error as a UNIX errno.
                    SG_ERR_THROW(  SG_ERR_ERRNO(myErr.error)  );
                }
            }
            else if (myErr.domain == kCFStreamErrorDomainMacOSStatus)
            {
                // Interpret myErr.error as a MacOS error code.
                // TODO SG_ERR_THROW(  SG_ERR_MAC((OSStatus) myErr.error)  );
                SG_ERR_THROW(  SG_ERR_UNSPECIFIED  );
            }
        }
    } while( numBytesRead > 0 );

    if (!myResponse)
    {
        myResponse = (CFHTTPMessageRef)CFReadStreamCopyProperty(myReadStream, kCFStreamPropertyHTTPResponseHeader);
    }

    *pp = myResponse;
    myResponse = NULL;

    *ppstr = pstr;
    pstr = NULL;

fail:
    if (myResponse)
    {
        CFRelease(myResponse);
    }
    SG_STRING_NULLFREE(pCtx, pstr);
}