Пример #1
0
bool HTTPInputSource::Open(CFErrorRef *error)
{
	if(IsOpen()) {
		LOGGER_WARNING("org.sbooth.AudioEngine.InputSource.HTTP", "Open() called on an InputSource that is already open");
		return true;
	}

	// Set up the HTTP request
	mRequest = CFHTTPMessageCreateRequest(kCFAllocatorDefault, CFSTR("GET"), mURL, kCFHTTPVersion1_1);
	if(NULL == mRequest) {
		if(error)
			*error = CFErrorCreate(kCFAllocatorDefault, kCFErrorDomainPOSIX, ENOMEM, NULL);
		return false;
	}

	CFHTTPMessageSetHeaderFieldValue(mRequest, CFSTR("User-Agent"), CFSTR("SFBAudioEngine"));

	// Seek support
	if(0 < mDesiredOffset) {
		CFStringRef byteRange = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("bytes=%ld-"), mDesiredOffset);
		CFHTTPMessageSetHeaderFieldValue(mRequest, CFSTR("Range"), byteRange);
		CFRelease(byteRange), byteRange = NULL;
	}

	mReadStream = CFReadStreamCreateForStreamedHTTPRequest(kCFAllocatorDefault, mRequest, NULL);
	if(NULL == mReadStream) {
		CFRelease(mRequest), mRequest = NULL;
		if(error)
			*error = CFErrorCreate(kCFAllocatorDefault, kCFErrorDomainPOSIX, ENOMEM, NULL);
		return false;
	}

	// Start the HTTP connection
	CFStreamClientContext myContext = { 0, this, NULL, NULL, NULL };

	CFOptionFlags clientFlags = kCFStreamEventOpenCompleted | kCFStreamEventHasBytesAvailable | kCFStreamEventErrorOccurred | kCFStreamEventEndEncountered;
    if(!CFReadStreamSetClient(mReadStream, clientFlags, myCFReadStreamClientCallBack, &myContext)) {
		CFRelease(mRequest), mRequest = NULL;
		CFRelease(mReadStream), mReadStream = NULL;
		if(error)
			*error = CFErrorCreate(kCFAllocatorDefault, kCFErrorDomainPOSIX, ENOMEM, NULL);
		return false;
	}

	CFReadStreamScheduleWithRunLoop(mReadStream, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);

	if(!CFReadStreamOpen(mReadStream)) {
		CFRelease(mRequest), mRequest = NULL;
		CFRelease(mReadStream), mReadStream = NULL;
		if(error)
			*error = CFErrorCreate(kCFAllocatorDefault, kCFErrorDomainPOSIX, ENOMEM, NULL);
		return false;
	}

	while(NULL == mResponseHeaders)
		CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true);

	mIsOpen = true;
	return true;
}
Пример #2
0
static void OnData(CFSocketRef socket, CFSocketCallBackType type, CFDataRef address, const void *value, void *info) {
    switch (type) {
        case kCFSocketDataCallBack:
            CFDataRef data(reinterpret_cast<CFDataRef>(value));
            Client *client(reinterpret_cast<Client *>(info));

            if (client->message_ == NULL)
                client->message_ = CFHTTPMessageCreateEmpty(kCFAllocatorDefault, TRUE);

            if (!CFHTTPMessageAppendBytes(client->message_, CFDataGetBytePtr(data), CFDataGetLength(data)))
                CFLog(kCFLogLevelError, CFSTR("CFHTTPMessageAppendBytes()"));
            else if (CFHTTPMessageIsHeaderComplete(client->message_)) {
                CFURLRef url(CFHTTPMessageCopyRequestURL(client->message_));
                Boolean absolute;
                CFStringRef path(CFURLCopyStrictPath(url, &absolute));
                CFRelease(client->message_);

                CFStringRef code(CFURLCreateStringByReplacingPercentEscapes(kCFAllocatorDefault, path, CFSTR("")));
                CFRelease(path);

                JSStringRef script(JSStringCreateWithCFString(code));
                CFRelease(code);

                JSValueRef result(JSEvaluateScript(CYGetJSContext(), script, NULL, NULL, 0, NULL));
                JSStringRelease(script);

                CFHTTPMessageRef response(CFHTTPMessageCreateResponse(kCFAllocatorDefault, 200, NULL, kCFHTTPVersion1_1));
                CFHTTPMessageSetHeaderFieldValue(response, CFSTR("Content-Type"), CFSTR("application/json; charset=utf-8"));

                CFStringRef json(CYCopyJSONString(CYGetJSContext(), result, NULL));
                CFDataRef body(CFStringCreateExternalRepresentation(kCFAllocatorDefault, json, kCFStringEncodingUTF8, NULL));
                CFRelease(json);

                CFStringRef length(CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%u"), CFDataGetLength(body)));
                CFHTTPMessageSetHeaderFieldValue(response, CFSTR("Content-Length"), length);
                CFRelease(length);

                CFHTTPMessageSetBody(response, body);
                CFRelease(body);

                CFDataRef serialized(CFHTTPMessageCopySerializedMessage(response));
                CFRelease(response);

                CFSocketSendData(socket, NULL, serialized, 0);
                CFRelease(serialized);

                CFRelease(url);
            }
        break;
    }
}
Пример #3
0
CFReadStreamRef HTTP_Stream::createReadStream(CFURLRef url)
{
    CFReadStreamRef readStream = 0;
    CFHTTPMessageRef request = 0;
    CFDictionaryRef proxySettings = 0;
    
    Stream_Configuration *config = Stream_Configuration::configuration();
    
    if (!(request = CFHTTPMessageCreateRequest(kCFAllocatorDefault, httpRequestMethod, url, kCFHTTPVersion1_1))) {
        goto out;
    }
    
    if (config->userAgent) {
        CFHTTPMessageSetHeaderFieldValue(request, httpUserAgentHeader, config->userAgent);
    }
    
    CFHTTPMessageSetHeaderFieldValue(request, icyMetaDataHeader, icyMetaDataValue);
    
    if (m_position.start > 0 && m_position.end > m_position.start) {
        CFStringRef rangeHeaderValue = CFStringCreateWithFormat(NULL,
                                                                NULL,
                                                                CFSTR("bytes=%llu-%llu"),
                                                                m_position.start,
                                                                m_position.end);
        
        CFHTTPMessageSetHeaderFieldValue(request, httpRangeHeader, rangeHeaderValue);
        CFRelease(rangeHeaderValue);
    }
    
    if (!(readStream = CFReadStreamCreateForHTTPRequest(kCFAllocatorDefault, request))) {
        goto out;
    }
    
    CFReadStreamSetProperty(readStream,
                            kCFStreamPropertyHTTPShouldAutoredirect,
                            kCFBooleanTrue);
    
    proxySettings = CFNetworkCopySystemProxySettings();
    if (proxySettings) {
        CFReadStreamSetProperty(readStream, kCFStreamPropertyHTTPProxy, proxySettings);
        CFRelease(proxySettings);
    }
    
out:
    if (request) {
        CFRelease(request);
    }
    
    return readStream;
}
RetainPtr<CFURLResponseRef> ResourceHandleCFURLConnectionDelegate::synthesizeRedirectResponseIfNecessary(CFURLRequestRef newRequest, CFURLResponseRef cfRedirectResponse)
{
    if (cfRedirectResponse)
        return cfRedirectResponse;

    CFURLRef newURL = CFURLRequestGetURL(newRequest);
    RetainPtr<CFStringRef> newScheme = adoptCF(CFURLCopyScheme(newURL));

    // If the protocols of the new request and the current request match, this is not an HSTS redirect and we shouldn't synthesize a redirect response.
    const ResourceRequest& currentRequest = m_handle->currentRequest();
    if (currentRequest.url().protocol() == String(newScheme.get()))
        return nullptr;

    RetainPtr<CFURLRef> currentURL = currentRequest.url().createCFURL();
    RetainPtr<CFHTTPMessageRef> responseMessage = adoptCF(CFHTTPMessageCreateResponse(0, 302, 0, kCFHTTPVersion1_1));
    RetainPtr<CFURLRef> newAbsoluteURL = adoptCF(CFURLCopyAbsoluteURL(newURL));
    CFHTTPMessageSetHeaderFieldValue(responseMessage.get(), CFSTR("Location"), CFURLGetString(newAbsoluteURL.get()));
    CFHTTPMessageSetHeaderFieldValue(responseMessage.get(), CFSTR("Cache-Control"), CFSTR("no-store"));

    RetainPtr<CFURLResponseRef> newResponse = adoptCF(CFURLResponseCreateWithHTTPResponse(0, currentURL.get(), responseMessage.get(), kCFURLCacheStorageNotAllowed));
    return newResponse;
}
bool asyncHttpPost(CFURLRef responder, CFDataRef requestData /* , bool force_nocache */ ,
    asynchttp_t *http) {
    bool result = true; /* True, we didn't schedule any work. */
	/* resources to release on exit */
    CFURLRef getURL = NULL;

/* Interesting tidbit from rfc5019
   When sending requests that are less than or equal to 255 bytes in
   total (after encoding) including the scheme and delimiters (http://),
   server name and base64-encoded OCSPRequest structure, clients MUST
   use the GET method (to enable OCSP response caching).  OCSP requests
   larger than 255 bytes SHOULD be submitted using the POST method.

   Interesting tidbit from rfc2616:
   Note: Servers ought to be cautious about depending on URI lengths
   above 255 bytes, because some older client or proxy
   implementations might not properly support these lengths.

   Given the second note I'm assuming that the note in rfc5019 is about the
   length of the URI, not the length of the entire HTTP request.

   If we need to consider the entire request we need to have 17 bytes less, or
   17 + 25 = 42 if we are appending a "Cache-Control: no-cache CRLF" header
   field.

   The 17 and 42 above are based on the request encoding from rfc2616
   Method SP Request-URI SP HTTP-Version CRLF (header CRLF)* CRLF
   so in our case it's:
   GET SP URI SP HTTP/1.1 CRLF CRLF
   17 + len(URI) bytes
   or
   GET SP URI SP HTTP/1.1 CRLF Cache-Control: SP no-cache CRLF CRLF
   42 + len(URI) bytes
 */

    /* First let's try creating a GET request. */
    getURL = createGetURL(responder, requestData);
    if (getURL && CFURLGetBytes(getURL, NULL, 0) < 256) {
        /* Get URI is less than 256 bytes encoded, making it safe even for
           older proxy or caching servers, so let's use HTTP GET. */
        secdebug("http", "GET[%ld] %@", CFURLGetBytes(getURL, NULL, 0), getURL);
        require_quiet(http->request = CFHTTPMessageCreateRequest(kCFAllocatorDefault,
            CFSTR("GET"), getURL, kCFHTTPVersion1_1), errOut);
    } else {
        /* GET Request too big to ensure error free transmission, let's
           create a HTTP POST http->request instead. */
        secdebug("http", "POST %@ CRLF body", responder);
        require_quiet(http->request = CFHTTPMessageCreateRequest(kCFAllocatorDefault,
            CFSTR("POST"), responder, kCFHTTPVersion1_1), errOut);
        /* Set the body and required header fields. */
        CFHTTPMessageSetBody(http->request, requestData);
        CFHTTPMessageSetHeaderFieldValue(http->request, kContentType,
            kAppOcspRequest);
    }

#if 0
    if (force_nocache) {
        CFHTTPMessageSetHeaderFieldValue(http->request, CFSTR("Cache-Control"),
            CFSTR("no-cache"));
    }
#endif

    result = asynchttp_request(NULL, http);

errOut:
    CFReleaseSafe(getURL);

    return result;
}
Пример #6
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;
}
static void perform_upload_request__string(
    SG_context* pCtx,
    CFHTTPMessageRef myRequest,
    SG_pathname* pPath,
    CFHTTPMessageRef* pmyResponse,
    SG_string** ppstr
)
{
    CFReadStreamRef myReadStream = NULL;
    CFHTTPMessageRef myResponse = NULL;
    SG_string* pstr = NULL;
    CFReadStreamRef upload = NULL;
    CFURLRef upload_file_url = NULL;

    // set the content-length header
    {
        SG_uint64 len = 0;
        SG_ERR_CHECK(  SG_fsobj__length__pathname(pCtx, pPath, &len, NULL)  );

        CFStringRef headerFieldName = CFSTR("Content-Length");
        CFStringRef headerFieldValue = CFStringCreateWithFormat (kCFAllocatorDefault, NULL,  CFSTR("%d"), len);
        CFHTTPMessageSetHeaderFieldValue(myRequest, headerFieldName, headerFieldValue);
        CFRelease(headerFieldValue);
    }

    upload_file_url = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, (UInt8*) SG_pathname__sz(pPath), SG_STRLEN(SG_pathname__sz(pPath)), SG_FALSE);
    upload = CFReadStreamCreateWithFile(kCFAllocatorDefault, upload_file_url);
    CFRelease(upload_file_url);
    if (!CFReadStreamOpen(upload))
    {
        CFStreamError myErr = CFReadStreamGetError(upload);

        if (myErr.domain == kCFStreamErrorDomainPOSIX)
        {
            // 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  );
        }
    }

    SG_ERR_CHECK(  send_upload_request(pCtx, myRequest, upload, &myReadStream)  );
    SG_ERR_CHECK(  read_entire_stream__string(pCtx, myReadStream, &pstr, &myResponse)  );

    *ppstr = pstr;
    pstr = NULL;

    *pmyResponse = myResponse;
    myResponse = NULL;

fail:
    if (upload)
    {
        CFRelease(upload);
    }
    if (myReadStream)
    {
        CFReadStreamClose(myReadStream);
        CFRelease(myReadStream);
        myReadStream = NULL;
    }

    if (myResponse)
    {
        CFRelease(myResponse);
        myResponse = NULL;
    }

    SG_STRING_NULLFREE(pCtx, pstr);
}