Ejemplo n.º 1
0
void Test(const String& ct, const String& val = Null)
{
	MIMEHeader h;
	h.Parse(ct);
	String s = AsString(h);
	LOG(ct);
	LOG("  " << h);
	if(val.GetCount())
		ASSERT(s == val);
	etalon << "Test(" << AsCString(ct) << ",\r\n     " << AsCString(s) << ");\r\n";
}
Ejemplo n.º 2
0
bool MHTMLParser::parseArchiveWithHeader(
    MIMEHeader* header,
    HeapVector<Member<ArchiveResource>>& resources) {
  if (!header) {
    DVLOG(1) << "Failed to parse MHTML part: no header.";
    return false;
  }

  if (!header->isMultipart()) {
    // With IE a page with no resource is not multi-part.
    bool endOfArchiveReached = false;
    ArchiveResource* resource =
        parseNextPart(*header, String(), String(), endOfArchiveReached);
    if (!resource)
      return false;
    resources.append(resource);
    return true;
  }

  // Skip the message content (it's a generic browser specific message).
  skipLinesUntilBoundaryFound(m_lineReader, header->endOfPartBoundary());

  bool endOfArchive = false;
  while (!endOfArchive) {
    MIMEHeader* resourceHeader = MIMEHeader::parseHeader(&m_lineReader);
    if (!resourceHeader) {
      DVLOG(1) << "Failed to parse MHTML, invalid MIME header.";
      return false;
    }
    if (resourceHeader->contentType() == "multipart/alternative") {
      // Ignore IE nesting which makes little sense (IE seems to nest only some
      // of the frames).
      if (!parseArchiveWithHeader(resourceHeader, resources)) {
        DVLOG(1) << "Failed to parse MHTML subframe.";
        return false;
      }
      skipLinesUntilBoundaryFound(m_lineReader, header->endOfPartBoundary());
      continue;
    }

    ArchiveResource* resource =
        parseNextPart(*resourceHeader, header->endOfPartBoundary(),
                      header->endOfDocumentBoundary(), endOfArchive);
    if (!resource) {
      DVLOG(1) << "Failed to parse MHTML part.";
      return false;
    }
    resources.append(resource);
  }
  return true;
}
Ejemplo n.º 3
0
PassRefPtr<ArchiveResource> MHTMLParser::parseNextPart(const MIMEHeader& mimeHeader, const String& endOfPartBoundary, const String& endOfDocumentBoundary, bool& endOfArchiveReached)
{
    ASSERT(endOfPartBoundary.isEmpty() == endOfDocumentBoundary.isEmpty());

    RefPtr<SharedBuffer> content = SharedBuffer::create();
    const bool checkBoundary = !endOfPartBoundary.isEmpty();
    bool endOfPartReached = false;
    String line;
    while (!(line = m_lineReader.nextLine()).isNull()) {
        if (checkBoundary && (line == endOfPartBoundary || line == endOfDocumentBoundary)) {
            endOfArchiveReached = (line == endOfDocumentBoundary);
            endOfPartReached = true;
            break;
        }
        // Note that we use line.utf8() and not line.ascii() as ascii turns special characters (such as tab, line-feed...) into '?'.
        content->append(line.utf8().data(), line.length());
        if (mimeHeader.contentTransferEncoding() == MIMEHeader::QuotedPrintable) {
            // The line reader removes the \r\n, but we need them for the content in this case as the QuotedPrintable decoder expects CR-LF terminated lines.
            content->append("\r\n", 2);
        }
    }
    if (!endOfPartReached && checkBoundary) {
        LOG_ERROR("No bounday found for MHTML part.");
        return 0;
    }

    Vector<char> data;
    switch (mimeHeader.contentTransferEncoding()) {
    case MIMEHeader::Base64:
        if (!base64Decode(content->data(), content->size(), data)) {
            LOG_ERROR("Invalid base64 content for MHTML part.");
            return 0;
        }
        break;
    case MIMEHeader::QuotedPrintable:
        quotedPrintableDecode(content->data(), content->size(), data);
        break;
    case MIMEHeader::SevenBit:
        data.append(content->data(), content->size());
        break;
    default:
        LOG_ERROR("Invalid encoding for MHTML part.");
        return 0;
    }
    RefPtr<SharedBuffer> contentBuffer = SharedBuffer::adoptVector(data);
    // FIXME: the URL in the MIME header could be relative, we should resolve it if it is.
    // The specs mentions 5 ways to resolve a URL: http://tools.ietf.org/html/rfc2557#section-5
    // IE and Firefox (UNMht) seem to generate only absolute URLs.
    KURL location = KURL(KURL(), mimeHeader.contentLocation());
    return ArchiveResource::create(contentBuffer, location, mimeHeader.contentType(), mimeHeader.charset(), String());
}
Ejemplo n.º 4
0
MIMEHeader* MIMEHeader::parseHeader(SharedBufferChunkReader* buffer) {
  MIMEHeader* mimeHeader = MIMEHeader::create();
  KeyValueMap keyValuePairs = retrieveKeyValuePairs(buffer);
  KeyValueMap::iterator mimeParametersIterator =
      keyValuePairs.find("content-type");
  if (mimeParametersIterator != keyValuePairs.end()) {
    ParsedContentType parsedContentType(mimeParametersIterator->value);
    mimeHeader->m_contentType = parsedContentType.mimeType();
    if (!mimeHeader->isMultipart()) {
      mimeHeader->m_charset = parsedContentType.charset().stripWhiteSpace();
    } else {
      mimeHeader->m_multipartType =
          parsedContentType.parameterValueForName("type");
      mimeHeader->m_endOfPartBoundary =
          parsedContentType.parameterValueForName("boundary");
      if (mimeHeader->m_endOfPartBoundary.isNull()) {
        DVLOG(1) << "No boundary found in multipart MIME header.";
        return nullptr;
      }
      mimeHeader->m_endOfPartBoundary.insert("--", 0);
      mimeHeader->m_endOfDocumentBoundary = mimeHeader->m_endOfPartBoundary;
      mimeHeader->m_endOfDocumentBoundary.append("--");
    }
  }

  mimeParametersIterator = keyValuePairs.find("content-transfer-encoding");
  if (mimeParametersIterator != keyValuePairs.end())
    mimeHeader->m_contentTransferEncoding =
        parseContentTransferEncoding(mimeParametersIterator->value);

  mimeParametersIterator = keyValuePairs.find("content-location");
  if (mimeParametersIterator != keyValuePairs.end())
    mimeHeader->m_contentLocation = mimeParametersIterator->value;

  // See rfc2557 - section 8.3 - Use of the Content-ID header and CID URLs.
  mimeParametersIterator = keyValuePairs.find("content-id");
  if (mimeParametersIterator != keyValuePairs.end())
    mimeHeader->m_contentID = mimeParametersIterator->value;

  return mimeHeader;
}
void HTTPPostRequestBodyParserTest::ReadMultiPartPost()
{
	StartTrace(HTTPPostRequestBodyParserTest.ReadMultiPartPost);
	std::iostream *is = coast::system::OpenStream("MultiPartBody.txt", 0);

	t_assertm(is != 0, "expected 'MultiPartBody.txt' to be there");
	if ( is ) {
		MIMEHeader mh;
		t_assertm(mh.ParseHeaders(*is, 4096, 4096), "expected global header parsing to succeed");
		assertEqual(586L, mh.GetParsedHeaderLength());
		HTTPPostRequestBodyParser sm(mh);
		t_assert(sm.Parse(*is));
		Anything expected;
		Anything result = sm.GetContent();

		delete is;

		t_assert(!GetConfig().IsNull());
		assertAnyEqual(GetConfig()["MultiPartResult"], result);
	}
	// This sequence takes advantage of the String::SubString
	// feature to return the whole remainder of the string starting
	// from the first occurrence the substring-pattern has been found.
	// This relieves us from the need to create an expected result file
	// which we would use to verify the results.

	is =  coast::system::OpenStream("MultiPartBody.txt", 0);
	if ( is ) {
		MIMEHeader mh;
		t_assertm(mh.ParseHeaders(*is, 4096, 4096), "expected global header parsing to succeed");
		assertEqual(586L, mh.GetParsedHeaderLength());
		HTTPPostRequestBodyParser sm(mh);
		t_assert(sm.Parse(*is));
		String unparsedContent = sm.GetUnparsedContent();
		delete is;

		is =  coast::system::OpenStream("MultiPartBody.txt", 0);
		if (is) {
			char c;
			String tmp;
			while ((!!(*is).get(c))) {
				tmp.Append(c);
			}
			String final;
			final = tmp.SubString(unparsedContent);
			assertEqual(final, unparsedContent);
			delete is;
		}
	}
Ejemplo n.º 6
0
PassRefPtrWillBeRawPtr<ArchiveResource> MHTMLParser::parseNextPart(const MIMEHeader& mimeHeader, const String& endOfPartBoundary, const String& endOfDocumentBoundary, bool& endOfArchiveReached)
{
    ASSERT(endOfPartBoundary.isEmpty() == endOfDocumentBoundary.isEmpty());

    // If no content transfer encoding is specified, default to binary encoding.
    MIMEHeader::Encoding contentTransferEncoding = mimeHeader.contentTransferEncoding();
    if (contentTransferEncoding == MIMEHeader::Unknown)
        contentTransferEncoding = MIMEHeader::Binary;

    RefPtr<SharedBuffer> content = SharedBuffer::create();
    const bool checkBoundary = !endOfPartBoundary.isEmpty();
    bool endOfPartReached = false;
    if (contentTransferEncoding == MIMEHeader::Binary) {
        if (!checkBoundary) {
            WTF_LOG_ERROR("Binary contents requires end of part");
            return nullptr;
        }
        m_lineReader.setSeparator(endOfPartBoundary.utf8().data());
        Vector<char> part;
        if (!m_lineReader.nextChunk(part)) {
            WTF_LOG_ERROR("Binary contents requires end of part");
            return nullptr;
        }
        content->append(part);
        m_lineReader.setSeparator("\r\n");
        Vector<char> nextChars;
        if (m_lineReader.peek(nextChars, 2) != 2) {
            WTF_LOG_ERROR("Invalid seperator.");
            return nullptr;
        }
        endOfPartReached = true;
        ASSERT(nextChars.size() == 2);
        endOfArchiveReached = (nextChars[0] == '-' && nextChars[1] == '-');
        if (!endOfArchiveReached) {
            String line = m_lineReader.nextChunkAsUTF8StringWithLatin1Fallback();
            if (!line.isEmpty()) {
                WTF_LOG_ERROR("No CRLF at end of binary section.");
                return nullptr;
            }
        }
    } else {
        String line;
        while (!(line = m_lineReader.nextChunkAsUTF8StringWithLatin1Fallback()).isNull()) {
            endOfArchiveReached = (line == endOfDocumentBoundary);
            if (checkBoundary && (line == endOfPartBoundary || endOfArchiveReached)) {
                endOfPartReached = true;
                break;
            }
            // Note that we use line.utf8() and not line.ascii() as ascii turns special characters (such as tab, line-feed...) into '?'.
            content->append(line.utf8().data(), line.length());
            if (contentTransferEncoding == MIMEHeader::QuotedPrintable) {
                // The line reader removes the \r\n, but we need them for the content in this case as the QuotedPrintable decoder expects CR-LF terminated lines.
                content->append("\r\n", 2u);
            }
        }
    }
    if (!endOfPartReached && checkBoundary) {
        WTF_LOG_ERROR("No bounday found for MHTML part.");
        return nullptr;
    }

    Vector<char> data;
    switch (contentTransferEncoding) {
    case MIMEHeader::Base64:
        if (!base64Decode(content->data(), content->size(), data)) {
            WTF_LOG_ERROR("Invalid base64 content for MHTML part.");
            return nullptr;
        }
        break;
    case MIMEHeader::QuotedPrintable:
        quotedPrintableDecode(content->data(), content->size(), data);
        break;
    case MIMEHeader::EightBit:
    case MIMEHeader::SevenBit:
    case MIMEHeader::Binary:
        data.append(content->data(), content->size());
        break;
    default:
        WTF_LOG_ERROR("Invalid encoding for MHTML part.");
        return nullptr;
    }
    RefPtr<SharedBuffer> contentBuffer = SharedBuffer::adoptVector(data);
    // FIXME: the URL in the MIME header could be relative, we should resolve it if it is.
    // The specs mentions 5 ways to resolve a URL: http://tools.ietf.org/html/rfc2557#section-5
    // IE and Firefox (UNMht) seem to generate only absolute URLs.
    KURL location = KURL(KURL(), mimeHeader.contentLocation());
    return ArchiveResource::create(
        contentBuffer, location, mimeHeader.contentID(), AtomicString(mimeHeader.contentType()), AtomicString(mimeHeader.charset()));
}
Ejemplo n.º 7
0
void
CHTTPDemux::DetectHandler(HTTPMessage* pMsg)
{
    INT32 nProxyEnabled = 0;

    if (SUCCEEDED(m_proc->pc->registry->GetInt(REGISTRY_RTSPPROXY_ENABLED, &nProxyEnabled, m_proc)))
    {
        m_pResponse = new HTTPProtocol();
        m_pResponse->AddRef();
        return;
    }

    HTTPMessage::Tag tag = pMsg->tag();
    if (tag == HTTPMessage::T_GET || tag == HTTPMessage::T_POST)
    {
        HTTPRequestMessage* pReq = (HTTPRequestMessage*)pMsg;
        const char* pUrl = pReq->url();
        if (strncmp(pUrl, "/SmpDsBhgRl", 11) == 0)
        {
            if (tag == HTTPMessage::T_GET)
            {
                m_pResponse = new CRN1CloakGETHandler();
                m_pResponse->AddRef();
            }
            else
            {
                m_pResponse = new CRN1CloakPOSTHandler();
                m_pResponse->AddRef();
            }
            return;
        }

#ifdef HELIX_FEATURE_SERVER_CLOAKV2

        CloakV2SignatureEnforcer pEnforcer;

        if (SUCCEEDED(pEnforcer.EnforceCloakSignature(pReq)))
        {
            if (tag == HTTPMessage::T_GET)
            {
                m_pResponse = new CRN1CloakFallbackGETHandler();
                m_pResponse->AddRef();
            }
            else
            {
                m_pResponse = new CRN1CloakFallbackPOSTHandler();
                m_pResponse->AddRef();
            }
            return;
        }

#endif //defined HELIX_FEATURE_SERVER_CLOAKV2

	/*
	 * If the Accept or Content-type header has
	 * application/x-rtsp-tunnelled its a quicktime cloaked connection
	 */
	MIMEHeader* pUserAgentHdr = pMsg->getHeader("User-Agent");
        MIMEHeader* pSessionHdr = pMsg->getHeader("x-sessioncookie");
	if (pSessionHdr)
	{
	    MIMEHeader* pAcceptHdr = pMsg->getHeader("Accept");
	    MIMEHeader* pContentTypeHdr = pMsg->getHeader("Content-type");
	    CHXString strValue;
	    if (pAcceptHdr != NULL)
	    {
		strValue.Empty();
		pAcceptHdr->asString(strValue);
		if (strncmp(strValue, "application/x-rtsp-tunnelled", 28) == 0)
		{
		    if (tag == HTTPMessage::T_GET)
		    {
			m_pResponse = new CQTCloakGETHandler();
			m_pResponse->AddRef();
		    }
		    else 
		    {
			m_pResponse = new CQTCloakPOSTHandler();
			m_pResponse->AddRef();
		    }
		    return;
		}
	    }
	    if (pContentTypeHdr != NULL)
	    {
		strValue.Empty();
		pContentTypeHdr->asString(strValue);
		if (strncmp(strValue, "application/x-rtsp-tunnelled", 28) == 0)
		{
		    if (tag == HTTPMessage::T_POST)
		    {
			m_pResponse = new CQTCloakPOSTHandler();
			m_pResponse->AddRef();
		    }
		    else
		    {
			m_pResponse = new CQTCloakGETHandler();
			m_pResponse->AddRef();
		    }
		    return;
		}
	    }
	    /*
	     * If the User-Agent begins with "QTS " and there is an
	     * x-sessioncookie header, it's a QT cloaking request.
	     */
	    if (pUserAgentHdr != NULL)
	    {
		pUserAgentHdr->asString(strValue);
		if (strncasecmp(strValue, "QTS ", 4) == 0)
		{
		     if (tag == HTTPMessage::T_GET)
		     {
			m_pResponse = new CQTCloakGETHandler();
			m_pResponse->AddRef();
		     }
		     else
		     {
			m_pResponse = new CQTCloakPOSTHandler();
			m_pResponse->AddRef();
		     }
		     return;
		}
	    }
	}
#if defined(HELIX_FEATURE_SERVER_WMT_MMS)
        if (IsWMTHTTP(pUrl, pUserAgentHdr))
        {
            m_pResponse = new WMTHttpProtocol();
            m_pResponse->AddRef();
            return;
        }
#endif
    }
    m_pResponse = new HTTPProtocol();
    m_pResponse->AddRef();
}
Ejemplo n.º 8
0
void
CHTTPDemux::handleInput(IHXBuffer* pBuf)
{
    UINT32 ulBufLen = 0;
    if (pBuf)
    {
	ulBufLen = pBuf->GetSize();
	if (m_ulMsgLen+ulBufLen > MAX_HTTP_MSG_SIZE)
	{
	    if (m_pSock)
	    {
		IHXSockAddr* pAddr = 0;
		m_pSock->GetPeerAddr(&pAddr);
		if (pAddr)
		{
		    IHXBuffer* pAddrBuf = 0;
		    pAddr->GetAddr(&pAddrBuf);
		    if (pAddrBuf)
		    {
			fprintf(stderr, "W: Large HTTP message (greater than 64K) being received from addr <%s>.\n"
			    "   Possible DOS attack!\n", 
			    (const char *)pAddrBuf->GetBuffer());
			pAddrBuf->Release();
		    }
		    pAddr->Release();
		}
	    }
	    Close(HXR_FAIL);
	    return;
	}
    }
    if (m_pFragBuf == NULL)
    {
        pBuf->AddRef();
    }
    else
    {
        IHXBuffer* pNewBuf = new CHXBuffer();
        pNewBuf->AddRef();
        pNewBuf->SetSize(m_pFragBuf->GetSize() + ulBufLen);
        memcpy(pNewBuf->GetBuffer(), m_pFragBuf->GetBuffer(), m_pFragBuf->GetSize());
	memcpy(pNewBuf->GetBuffer()+m_pFragBuf->GetSize(), pBuf->GetBuffer(), ulBufLen);
        HX_RELEASE(m_pFragBuf);
        pBuf = pNewBuf;
    }

    while (pBuf != NULL && !m_bClosed)
    {
        BYTE* pData = pBuf->GetBuffer();
        UINT32 uDataLen = pBuf->GetSize();
        UINT32 uDataUsed = 0;
        IHXBuffer* pNewBuf = NULL;
        IHXBuffer* pContentBuf = NULL;
        BOOL bFirstRun = FALSE;
	BOOL bMsgTooLarge = FALSE;

        if (m_ReadState == DEMUX_READ_MSG)
        {
            HTTPMessage* pMsg = NULL;
            uDataUsed = uDataLen;
            pMsg = m_pParser->parse((const char*)pData, uDataUsed, bMsgTooLarge);
            if (pMsg == NULL)
            {
		if (bMsgTooLarge)
		{
		    if (pBuf)
			pBuf->Release();
		    if (m_pSock)
		    {
			IHXSockAddr* pAddr = 0;
			m_pSock->GetPeerAddr(&pAddr);
			if (pAddr)
			{
			    IHXBuffer* pAddrBuf = 0;
			    pAddr->GetAddr(&pAddrBuf);
			    if (pAddrBuf)
			    {
				fprintf(stderr, "W: Large amount of HTTP data being received from addr <%s>.\n"
				    "   Possible DOS attack!\n", 
				    (const char *)pAddrBuf->GetBuffer());
				pAddrBuf->Release();
			    }
			    pAddr->Release();
			}
		    }
		    Close(HXR_FAIL);
		    return;
		}
                break;
            }

            // Remove used data from the buffer
            if (uDataUsed == uDataLen)
            {
                HX_RELEASE(pBuf);
            }
            else
            {
                pNewBuf = new CHXStaticBuffer(pBuf, uDataUsed,
                                              uDataLen-uDataUsed);
                pNewBuf->AddRef();
                HX_RELEASE(pBuf);
                pBuf = pNewBuf;
            }

            if (m_pResponse == NULL)
            {
                DetectHandler(pMsg);
                HX_ASSERT(m_pResponse != NULL);
                m_pResponse->Init(this);
                bFirstRun = TRUE;
            }

            if (m_pResponse->GetFeatureFlags() & HTTP_FEATURE_IGNORE_CONTENT_LENGTH)
            {
                // Cloaking V2.
                if (m_pResponse->GetFeatureFlags() & ( HTTP_FEATURE_V11_SUPPORT
                                                     | HTTP_FEATURE_CHUNKED_ENCODING_SUPPORT))
                {
                    m_uContentRemain = 0;

                    CHXString strEncoding = pMsg->getHeaderValue("Transfer-Encoding");

                    if (strEncoding == "chunked")
                    {
                        m_ReadState = DEMUX_READ_DATA;
                    }
                }
                else // Far less strict for non-persistent HTTP/1.0 connections.
                {
                    m_uContentRemain = 0;
                    m_ReadState = DEMUX_READ_DATA;                
                }
            }
            else
            {
                MIMEHeader* pHdr = pMsg->getHeader("Content-Length");

                if (!pHdr)
                {
                    m_uContentRemain = 0;
                }
                else
                {
                    CHXString strLen;
                    pHdr->asString(strLen);
                    int iLen = atoi(strLen);
                    if (iLen < 0 || iLen > 0xffff)
                    {
                        DPRINTF(D_ERROR, ("HTTP: Bad content length %d\n", iLen));
			if (pBuf)
			    pBuf->Release();
                        Close(HXR_FAIL);
                        return;
                    }
                    
                    m_uContentRemain = (UINT32)iLen;
                    m_ReadState = DEMUX_READ_DATA;
                }
            }

            if (bFirstRun && m_pResponse->AutoDispatch())
            {
                m_pSavedMessage = pMsg;
                static_cast<CHXServSocket*>(m_pSock)->Dispatch();
                break;
            }

            DispatchMessage(pMsg);
            delete pMsg;
        }
        else if (m_ReadState == DEMUX_READ_DATA)
        {
            BOOL bEnforceContentLength = FALSE;

            if (m_pResponse->GetFeatureFlags() & HTTP_FEATURE_IGNORE_CONTENT_LENGTH)           
            {
                HX_ASSERT(m_uContentRemain == 0); // This value not used.
                pContentBuf = pBuf;
                pBuf = NULL;
            }
            else
            {
                if (m_uContentRemain >= pBuf->GetSize())
                {
                    pContentBuf = pBuf;
                    m_uContentRemain -= pBuf->GetSize();
                    pBuf = NULL;
                }
                else
                {
                    pContentBuf = new CHXStaticBuffer(pBuf, 0, m_uContentRemain);
                    pContentBuf->AddRef();

                    pNewBuf = new CHXStaticBuffer(pBuf, m_uContentRemain, pBuf->GetSize()-m_uContentRemain);
                    pNewBuf->AddRef();
                    HX_RELEASE(pBuf);
                    pBuf = pNewBuf;

                    m_uContentRemain = 0;
                    m_ReadState = DEMUX_READ_MSG;
                }
            }

            m_pResponse->OnData(pContentBuf);
            HX_RELEASE(pContentBuf);
        }
    }

    if (pBuf != NULL)
    {
        m_pFragBuf = pBuf;
        m_pFragBuf->AddRef();
    }

    HX_RELEASE(pBuf);
}
Ejemplo n.º 9
0
HX_RESULT HXCloakedV2TCPSocket::_DoProxyAuthentication(HTTPResponseMessage* pMess)
{
    HX_RESULT                  res              = HXR_FAIL;
    IHXCommonClassFactory*     pCCF             = NULL;
    CHXString                  getStr           = "";
    IHXKeyValueList*           pRespHeaders     = NULL;
    MIMEHeaderValue*           pHeaderValue     = NULL;
    MIMEHeader*                pHeader          = NULL;
    CHXString                  strHeader        = "";
    CHXString                  strTemp          = "";
    IHXBuffer*                 pBuffer          = NULL;
    IHXRequest*                pRequest         = NULL;
    IHXValues*                 pValues          = NULL;             
    IHXClientAuthConversation* pClientAuth      = NULL;
    IUnknown*                  pUnkConfig       = NULL;
    IHXObjectConfiguration*    pConfig          = NULL;


    //////////////////////
    //
    // XXXgfw I really don't think we need all this authentication
    // garbage.  It really seems we only need to TLC to just give us a
    // dialog to do a user/pass request. It sure seems like this code
    // below is way overkill. Just check out ResponseReady(), the only
    // thing is needs from all this is just that one string. Oh well,
    // until I have time to figure out exactly how this all works (all
    // the calls through the core and into the TLC from here) I will
    // just leave it like the original cloaking.
    //
    //////////////////////
    
    res = m_pContext->QueryInterface(IID_IHXCommonClassFactory, (void**)&pCCF);
    if( SUCCEEDED(res) )
    {
        //pRequest will be freed in the ResponseReady() method.
        res = pCCF->CreateInstance(CLSID_IHXRequest, (void**)&pRequest);
        if( SUCCEEDED(res) )
        {
            getStr = _GenerateGetRequest();
            pRequest->SetURL((const char*)getStr); //Always returns HXR_OK;
            
            res = pCCF->CreateInstance(CLSID_IHXKeyValueList, (void**)&pRespHeaders);
            if( SUCCEEDED(res) )
            {
                
                pHeader = pMess->getFirstHeader();
                while (pHeader)
                {
                    pHeaderValue = pHeader->getFirstHeaderValue();
                    strHeader = "";
                    while( pHeaderValue )
                    {
                        pHeaderValue->asString(strTemp);
                        strHeader += strTemp;
                        pHeaderValue = pHeader->getNextHeaderValue();
                        if (pHeaderValue)
                        {
                            strHeader += ", ";
                        }
                    }
                    pBuffer = NULL;
                    CHXBuffer::FromCharArray((const char*)strHeader, &pBuffer);
                    if( pBuffer )
                    {
                        pRespHeaders->AddKeyValue(pHeader->name(), pBuffer);
                    }
                    HX_RELEASE(pBuffer);
                    pHeader = pMess->getNextHeader();
                }

                pValues = NULL;
                if (HXR_OK == pRespHeaders->QueryInterface(IID_IHXValues, (void**)&pValues))
                {
                    pRequest->SetResponseHeaders(pValues);
                }
                HX_RELEASE(pValues);
            }

            HX_RELEASE(pRespHeaders);

            if (HXR_OK == pRequest->GetResponseHeaders(pValues))
            {
                res = pCCF->CreateInstance(CLSID_IHXBuffer, (void**)&pBuffer);
                if (SUCCEEDED(res))
                {
                    pBuffer->Set((UCHAR*)m_pszProxyName, strlen(m_pszProxyName)+1);
                    pValues->SetPropertyCString("_server", pBuffer);
                    HX_RELEASE(pBuffer);
                }

                // Add the protocol to the response headers because TLC needs it
                if (SUCCEEDED(pCCF->CreateInstance(CLSID_IHXBuffer, (void**)&pBuffer)))
                {
                    pBuffer->Set((UCHAR*)"http", strlen("http") + 1);
                    pValues->SetPropertyCString("_protocol", pBuffer);
                    HX_RELEASE(pBuffer);
                }

                HX_RELEASE(pValues);
            }

            //We now need a CCF from the cloaking context, not our core's context.
            HX_RELEASE(pCCF);


            res = m_pCloakContext->QueryInterface(IID_IHXCommonClassFactory, (void**)&pCCF);
            if(SUCCEEDED(res))
            {
                res = pCCF->CreateInstance( CLSID_CHXClientAuthenticator, (void**)&pUnkConfig );
                if(SUCCEEDED(res))
                {
                    res = pUnkConfig->QueryInterface(IID_IHXClientAuthConversation, 
                                                     (void**)&pClientAuth);
                    if (SUCCEEDED(res))
                    {
                        res = pUnkConfig->QueryInterface(IID_IHXObjectConfiguration,
                                                         (void**)&pConfig);
                        if (SUCCEEDED(res))
                        {
                            pConfig->SetContext(m_pCloakContext);
                            HX_RELEASE(pConfig);
                        }

                        if ( pClientAuth && !pClientAuth->IsDone() )
                        {
                            HX_ASSERT(pRequest);
                            //After this if/else, we continue in ResponseReady() after
                            //the TLC calls us back.
                            if (pRequest)
                            {
                                res = pClientAuth->MakeResponse(this, pRequest);
                            }
                            else
                            {
                                // Auth Failed!
                                pClientAuth->Authenticated(FALSE);
                                res = HXR_NOT_AUTHORIZED;
                                res = ResponseReady(res, pRequest);
                            }
                        }
                    }
                    HX_RELEASE(pUnkConfig);
                }
                HX_RELEASE(pCCF);
            }
        }
    }

    //We return this in all cases. the connection will be started over in
    //the ResponseReady() method.
    res = HXR_NOT_AUTHORIZED;
    return res;
}