webengine/osswebengine/WebCore/platform/network/symbian/HttpConnection.cpp
changeset 0 dd21522fd290
child 5 10e98eab6f85
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/webengine/osswebengine/WebCore/platform/network/symbian/HttpConnection.cpp	Mon Mar 30 12:54:55 2009 +0300
@@ -0,0 +1,1326 @@
+/*
+* Copyright (c) 2007 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of the License "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:  
+*
+*/
+
+#include <Uri8.h>
+#include <EscapeUtils.h>
+#include <http/rhttpheaders.h>
+#include <http/mhttpdatasupplier.h>
+#include <thttpfields.h>
+#include "ResourceHandle.h"
+#include "ResourceHandleInternal.h"
+#include "ResourceRequest.h"
+#include "HttpConnection.h"
+#include "ResourceHandleManagerSymbian.h"
+#include "StaticObjectsContainer.h"
+#include "ResourceLoaderDelegate.h"
+#include "HttpCacheSupply.h"
+#include "HttpPostDataSupplier.h"
+#include <HttpFilterCommonStringsExt.h>
+#include <BrCtlDefs.h>
+#include "BrCtl.h"
+#include "BrCtlSpecialLoadObserver.h"
+#include "Frame.h"
+#include "FrameLoader.h"
+#include "DocumentLoader.h"
+#include "HttpUiCallbacks.h"
+#include "HttpRequestHeaderManager.h"
+#include "HttpConnUtils.h"
+#include "MultipartContentHandler.h"
+#include "UnknownContentHandler.h"
+#include <wtf/Vector.h>
+
+_LIT8(KHttps, "https");
+_LIT8( KAppUid, "Appuid" );
+
+using namespace WebCore;
+
+DefersData::DefersData(void* ctx, DefersDataCallback callback) : CActive(CActive::EPriorityStandard)
+{
+    m_ctx = ctx;
+    m_callback = callback;
+    CActiveScheduler::Add(this);
+}
+
+DefersData::~DefersData()
+{
+    Cancel();
+    delete m_response;
+
+    Vector<HBufC8*>::const_iterator it = m_bodyParts.begin();
+    Vector<HBufC8*>::const_iterator end = m_bodyParts.end();
+    while (it != end) {
+        HBufC8* buf = m_bodyParts.first();
+        m_bodyParts.remove(0);
+        delete buf;
+        it = m_bodyParts.begin();
+        end = m_bodyParts.end();
+    }
+}
+
+void DefersData::RunL()
+{
+    m_callback(m_ctx);
+}
+
+TInt DefersData::RunError(TInt aError)
+{
+    return KErrNone;
+}
+
+void DefersData::Activate()
+{
+    SetActive();
+    iStatus = KRequestPending;
+    TRequestStatus* status = &iStatus;
+    User::RequestComplete( status, KErrNone );
+}
+
+
+ReceivedFinished::ReceivedFinished(void* ctx, ReceivedFinishedCallback callback) : CActive(CActive::EPriorityStandard)
+{
+    m_ctx = ctx;
+    m_callback = callback;
+    m_done = true;
+    m_error = KErrNone;
+    CActiveScheduler::Add(this);
+}
+
+ReceivedFinished::~ReceivedFinished()
+{
+    Cancel();
+}
+
+void ReceivedFinished::RunL()
+{
+    m_callback(m_ctx, m_error);
+    m_done = true;
+}
+
+TInt ReceivedFinished::RunError(TInt aError)
+{
+    return KErrNone;
+}
+
+void ReceivedFinished::Activate(TInt errorCode)
+{
+    m_done = false;
+    m_error = errorCode;
+    SetActive();
+    iStatus = KRequestPending;
+    TRequestStatus* status = &iStatus;
+    User::RequestComplete( status, KErrNone );
+}
+
+void ReceivedFinished::done(bool status)
+{
+    m_done = status;
+}
+
+HttpConnection::HttpConnection(ResourceHandle* _handle, Frame* _frame) : MUrlConnection(_handle)
+{
+    HttpSessionManager* httpSessionMgr = StaticObjectsContainer::instance()->resourceLoaderDelegate()->httpSessionManager();
+    httpSessionMgr->addRequest(this, m_handle);
+    m_frag = NULL;
+    m_transaction = NULL;
+    m_urlResponse = NULL;
+    m_contentType = NULL;
+    m_encoding = NULL;
+    m_cacheSupply = NULL;
+    m_postDataSupplier = NULL;
+    m_maxSize = 0;
+    m_frame = _frame;
+    m_IsMultipart = false;
+    m_isDone = false;
+    m_certInfo = NULL;
+    m_accumulatedSize = 0;
+    m_defersData = NULL; // requests will not be propagated if loading is blocked
+    m_receivedFinished = NULL;
+    m_unknownContentHandler = NULL;
+}
+
+HttpConnection::~HttpConnection()
+{
+    HttpSessionManager* httpSessionMgr = StaticObjectsContainer::instance()->resourceLoaderDelegate()->httpSessionManager();
+    if (m_transaction) {
+        RHTTPSession& session = httpSessionMgr->httpSession();
+        // remove own address from transaction properties
+        m_transaction->PropertySet().RemoveProperty( session.StringPool().StringF(HttpFilterCommonStringsExt::ESelfPtr,
+            HttpFilterCommonStringsExt::GetTable()));
+    }
+    httpSessionMgr->removeRequest(this);
+    delete m_frag;
+    delete m_urlResponse;
+    delete m_contentType;
+    delete m_encoding;
+    delete m_defersData;
+    delete m_receivedFinished;
+    delete m_unknownContentHandler;
+    delete m_cacheSupply;
+    delete m_postDataSupplier;
+    delete m_transaction;
+}
+
+HttpConnection* HttpConnection::connectionFromTransaction(RHTTPTransaction& transaction)
+{
+    RHTTPTransactionPropertySet propSet = transaction.PropertySet();
+    THTTPHdrVal propRetVal;
+    // Get the name of the property
+    HttpSessionManager* httpSessionMgr = StaticObjectsContainer::instance()->resourceLoaderDelegate()->httpSessionManager();
+    RHTTPSession& session = httpSessionMgr->httpSession();
+    RStringF propName = session.StringPool().StringF( HttpFilterCommonStringsExt::ESelfPtr, HttpFilterCommonStringsExt::GetTable() );
+    // if it is set . .
+    if( propSet.Property( propName, propRetVal ) ){
+        return (HttpConnection*)(TInt(propRetVal));
+    }
+    return NULL;
+}
+
+int HttpConnection::submit()
+{
+    TRAPD(error, submitL());
+    return error;
+}
+
+void HttpConnection::submitL()
+{
+    __ASSERT_DEBUG( !m_transaction, THttpConnUtils::PanicLoader( KErrArgument ) );
+
+    HttpSessionManager* httpSessionMgr = StaticObjectsContainer::instance()->resourceLoaderDelegate()->httpSessionManager();
+    User::LeaveIfNull(httpSessionMgr);
+    httpSessionMgr->openHttpSessionIfNeededL();
+    TPtrC8 urlPtr( m_handle->request().url().des() );
+    m_transaction = new (ELeave) RHTTPTransaction;
+    RHTTPSession& session = httpSessionMgr->httpSession();
+    RStringPool stringPool = session.StringPool();
+    const TStringTable& stringTable = RHTTPSession::GetTable();
+    TUriParser8 uriParser;
+    uriParser.Parse(urlPtr);
+    // fragment
+    if(uriParser.IsPresent(EUriFragment)) {
+        m_frag = uriParser.Extract(EUriFragment).AllocL();
+        // url without frag
+        uriParser.UriWithoutFragment(urlPtr);
+        // and reparse url
+        uriParser.Parse(urlPtr);
+        }
+
+    // open transaction
+    RStringF method;
+    if (m_handle->request().httpMethod() == "GET") {
+        method = stringPool.StringF( HTTP::EGET, stringTable );
+    }
+    else if (m_handle->request().httpMethod() == "POST") {
+        method = stringPool.StringF( HTTP::EPOST, stringTable );
+    }
+    else if (m_handle->request().httpMethod() == "PUT") {
+        method = stringPool.StringF( HTTP::EPUT, stringTable );
+    }
+    else if (m_handle->request().httpMethod() == "DELETE") {
+        method = stringPool.StringF( HTTP::EDELETE, stringTable );
+    }
+    else {
+        User::Leave(KErrArgument);
+    }
+    *m_transaction = session.OpenTransactionL( uriParser, *(httpSessionMgr->transactionCallback()), method );
+    // add transaction attributes such as default headers, cache properties
+    addRequestHeadersL();
+    RHTTPTransactionPropertySet propSet = m_transaction->PropertySet();
+    
+    RStringF appuid = stringPool.OpenFStringL( KAppUid );
+    
+    TUint appuidValue = control(m_frame)->webView()->getWidgetId();
+    if(appuidValue){
+        propSet.SetPropertyL(appuid,THTTPHdrVal(appuidValue));
+    }
+    
+    appuid.Close();
+    // Add IMEI Notify property to the transaction
+    // It is not needed, as it is done in UA-Prof filter
+    // addIMEINotifyPropertiesL();
+
+    // add http request headers
+    RHTTPHeaders httpHeaders = m_transaction->Request().GetHeaderCollection();
+    httpSessionMgr->requestHeaderManager()->AddAllHeadersL(httpHeaders, m_handle->request());
+    // Create a dataSupplier object to supply the request body to http stack.
+    if ((m_handle->request().httpMethod() == "POST" ||
+        m_handle->request().httpMethod() == "PUT") && m_handle->request().httpBody()){
+        // 2 steps constructor
+        m_postDataSupplier = new(ELeave)HttpPostDataSupplier( m_transaction, control(m_frame));
+        m_postDataSupplier->initL(m_handle->request().httpBody());
+        m_transaction->Request().SetBody( *m_postDataSupplier);
+    }
+    // create cache supplier
+    m_cacheSupply = CHttpCacheSupply::NewL( this );
+    TBrCtlDefs::TBrCtlCacheMode cacheMode;
+    switch (m_handle->request().cachePolicy())
+    {
+    default:
+    case UseProtocolCachePolicy:
+        cacheMode = TBrCtlDefs::ECacheModeNormal;
+        break;
+    case ReloadIgnoringCacheData:
+        cacheMode = TBrCtlDefs::ECacheModeNoCache;
+        break;
+    case ReturnCacheDataElseLoad:
+        cacheMode = TBrCtlDefs::ECacheModeHistory;
+        break;
+    case ReturnCacheDataDontLoad:
+        cacheMode = TBrCtlDefs::ECacheModeOnlyCache;
+        break;
+    };
+	IsUrlInCacheL(m_transaction->Request().URI().UriDes() );
+    if( m_cacheSupply->StartRequestL( cacheMode ) != KErrNone ) {
+        // check if the response must come from the cache
+        if( cacheMode != TBrCtlDefs::ECacheModeOnlyCache ) {
+            m_transaction->SubmitL();
+        }
+        else {
+            // cache failed
+            complete( KErrGeneral );
+        }
+    }
+}
+
+void HttpConnection::cancel()
+{
+    complete( KErrCancel );
+}
+
+void HttpConnection::download(WebCore::ResourceHandle* handle,
+                              const WebCore::ResourceRequest& request,
+                              const WebCore::ResourceResponse& response)
+{
+    StaticObjectsContainer::instance()->resourceLoaderDelegate()->httpSessionManager()->download(handle,
+        request, response, this);
+}
+
+void HttpConnection::setDefersLoading(bool defers)
+{
+    if (m_receivedFinished && !m_receivedFinished->isDone()) {
+        // Don't set defer loading when in ReceivedFinished process
+        return;
+    }
+
+    if (defers) {
+        if (m_defersData) {
+            m_defersData ->Cancel(); // This would happen if we did not finish sending the accumulated content, and a second JavaScript dialog is displayed.
+        } else {
+            m_defersData = new DefersData(this, processDefersData);
+        }
+        if (m_cacheSupply) {
+            m_cacheSupply->PauseSupply();
+        }
+    }
+    else {
+        if (m_defersData) {
+            m_defersData->Activate();
+        }
+        if (m_cacheSupply) {
+            m_cacheSupply->ResumeSupply();
+        }
+    }
+}
+
+void HttpConnection::handleError(int error)
+{
+    complete(error);
+}
+
+void HttpConnection::MHFRunL(const THTTPEvent &aEvent)
+    {
+    if (m_cancelled) {
+        return;
+        }
+
+    __ASSERT_DEBUG( m_transaction, THttpConnUtils::PanicLoader( KErrArgument ) );
+
+    // Using this flag to prevent caching of secure items
+    TBool nonsecure = ETrue;
+    TUriParser8 requestedParser;
+    if(requestedParser.Parse(m_transaction->Request().URI().UriDes()) == KErrNone) {
+        if( requestedParser.Extract( EUriScheme ).Compare(KHttps) == 0 ) {
+            nonsecure = EFalse;
+            }
+        }
+    switch( aEvent.iStatus )
+        {
+        case THTTPEvent::EGotResponseHeaders:
+            {
+            if ( nonsecure ) {
+                // pass headers to the cache first
+                TRAP_IGNORE(m_cacheSupply->HeadersReceivedL());
+                }
+            int httpStatus( m_transaction->Response().StatusCode() );
+            if (httpStatus == KErrCompletion) {
+                return;
+            }
+
+            // Add certificate only if https, and top level request
+            if( m_handle->request().mainLoad() ) {
+                if ( m_transaction->Request().URI().Extract( EUriScheme ).FindF( KHttps ) == 0 && !m_isInCache ) {
+                    m_certInfo = new(ELeave)TCertInfo;
+                    m_transaction->ServerCert( *m_certInfo );
+                    }
+                // certinfo will be set/overwritten only if top load request
+                control(m_frame)->setCertInfo( m_certInfo );
+            }
+
+            // authentication
+            bool handled( EFalse );
+            //in case of bad Auth Header(aError = -7276), transaction is cancelled already in the filter,
+            //should be passed to Error Handler, otherwise handle Auth request normally.
+            if( ( httpStatus == 401 /*EHttpUnauthorized*/ ) ||
+                ( httpStatus == 407 /*EHttpProxyAuthenticationRequired*/ ) )
+                {
+                // Move the transaction to the Auth queue,
+                // and wait for Authentication callback
+                // This is proventing the transaction from being deleted
+                // in case the network dropped automatically for example
+                // during the data call connection.
+                m_transaction->Cancel();
+                HttpSessionManager* httpSessionMgr = StaticObjectsContainer::instance()->resourceLoaderDelegate()->httpSessionManager();
+                httpSessionMgr->removeRequest(this);
+                httpSessionMgr->addAuthRequest(this, m_handle);
+                TInt authRet = handleAuthRequestL( httpStatus );
+                handled = (authRet == KErrNone);
+                // trans is cancelled at this point. if
+                // authentication is failed (not handled) then
+                // just complete this transaction
+                if( !handled )
+                    {
+                    //
+                    complete( authRet );
+                    return;
+                    }
+                }
+            if ( !handled )
+                {
+                // url
+                m_urlResponse = NULL;
+                if(m_frag) {
+                    m_urlResponse = HBufC8::NewL(m_transaction->Request().URI().UriDes().Length() + m_frag->Length() + 1);
+                    TPtr8 responsePtr(m_urlResponse->Des());
+                    responsePtr.Copy(m_transaction->Request().URI().UriDes());
+                    responsePtr.Append(_L("#"));
+                    responsePtr.Append(*m_frag);
+                }
+                else {
+                    m_urlResponse = HBufC8::NewL(m_transaction->Request().URI().UriDes().Length());
+                    m_urlResponse->Des().Copy(m_transaction->Request().URI().UriDes());
+                }
+                // content type
+                THTTPHdrVal hdrVal;
+                RHTTPHeaders httpHeaders = m_transaction->Response().GetHeaderCollection();
+                RStringPool stringPool = m_transaction->Session().StringPool();
+                const TStringTable& stringTable = RHTTPSession::GetTable();
+                if( httpHeaders.GetField( stringPool.StringF( HTTP::EContentType, stringTable ), 0,
+                    hdrVal) == KErrNone ) {
+                    m_contentType = hdrVal.StrF().DesC().AllocL();
+                }
+                else {
+                    m_contentType = KNullDesC8().AllocL();
+                }
+                // content encoding
+                if( httpHeaders.GetParam( stringPool.StringF( HTTP::EContentType, stringTable ),
+                    stringPool.StringF( HTTP::ECharset, stringTable ), hdrVal ) == KErrNone ) {
+                    m_encoding = hdrVal.StrF().DesC().AllocL();
+                }
+                else {
+                    m_encoding = KNullDesC8().AllocL();
+                }
+                // content length
+                if( httpHeaders.GetField( stringPool.StringF( HTTP::EContentLength,
+                    stringTable ), 0, hdrVal ) == KErrNone ) {
+                    m_maxSize = hdrVal.Int();
+                }
+                String encoding;
+                if (m_encoding && m_encoding->Length()) {
+                    encoding = m_encoding->Des();
+                }
+                ResourceResponse response(m_urlResponse->Des(), m_contentType->Des(), m_maxSize, encoding, String() );
+                response.setHTTPStatusCode(m_transaction->Response().StatusCode());
+                //HTTP status text
+                response.setHTTPStatusText(((m_transaction->Response()).StatusText().DesC()));
+                
+                if (m_contentType && m_contentType->Length()) {
+                    response.setHTTPHeaderField("Content-Type", *m_contentType);
+                }
+		
+				TPtrC8 result;
+
+                if( httpHeaders.GetRawField( stringPool.StringF( HTTP::EContentDisposition, stringTable ), result) == KErrNone )
+                	response.setHTTPHeaderField("Content-Disposition", result);
+
+                if (m_handle->request().mainLoad()) {
+                    if(m_handle->request().url() != response.url()) {
+                        // Relative URLs are resolved based on the request URL, not response URL.
+                        // If a redirect happens, the request URL must be updated.
+                        m_handle->getInternal()->m_request.setURL(response.url());
+                        m_frame->loader()->activeDocumentLoader()->request().setURL(response.url());
+                    }
+                    if(MultipartContentHandler::IsSupported(response)) {
+                        m_IsMultipart = true;
+                        m_MultipartContentHandler = MultipartContentHandler::NewL();
+                        m_MultipartContentHandler->HandleResponseHeadersL(response, *m_transaction);
+                        return;
+                    }
+                    if (UnknownContentHandler::isUnknownContent(response)) {
+                        m_unknownContentHandler = UnknownContentHandler::NewL(this, response);
+                        return;
+                    }
+                }
+                // If loading is defered, don't send the headers now
+                if (m_defersData) {
+                    ResourceResponse* resp = new ResourceResponse(m_urlResponse->Des(), m_contentType->Des(), m_maxSize, encoding, String());
+                    if (resp == NULL) {
+                        complete(KErrNoMemory);
+                    }
+                    else {
+                        m_defersData->m_response = resp;
+                    }
+                }
+                else {
+                    CResourceHandleManager::self()->receivedResponse(m_handle, response, this);
+                }
+                // transaction is complete (must have been cancelled in receivedResponse call
+                if (m_isDone)
+                    return;
+                // transaction is taken, we need to cleanup this resource.
+                if (!m_transaction) {
+                    derefHandle();
+                    // this object might be invalid at this point
+                    return;
+                    }
+                }
+            break;
+        }
+        case THTTPEvent::EGotResponseBodyData:
+            {
+            if ( nonsecure ) {
+                // pass chunk to the cache first
+                TRAP_IGNORE( m_cacheSupply->BodyReceivedL() );
+                }
+            MHTTPDataSupplier* body = m_transaction->Response().Body();
+            // get it from the transaction
+            TPtrC8 chunkPtr;
+            body->GetNextDataPart( chunkPtr );
+            m_accumulatedSize += chunkPtr.Length();
+
+            if (chunkPtr.Length()) {
+                if(m_IsMultipart) {
+                    m_MultipartContentHandler->HandleResponseBodyL(chunkPtr);
+                } else {
+                    if (m_unknownContentHandler) {
+                        m_unknownContentHandler->updateContentTypeL(chunkPtr);
+                        if (m_defersData) {
+                            m_defersData ->m_response = m_unknownContentHandler->handOffResponse();
+                        }
+                        else {
+                            ResourceResponse* response = m_unknownContentHandler->handOffResponse();
+                            CResourceHandleManager::self()->receivedResponse(m_handle, *response, this);
+                            delete response;
+                            // transaction is complete (must have been cancelled in receivedResponse call
+                            if (m_isDone)
+                                return;
+                            // transaction is taken, we need to cleanup this resource.
+                            if (!m_transaction) {
+                                derefHandle();
+                                // this object might be invalid at this point
+                                return;
+                            }
+                        }
+                        delete m_unknownContentHandler;
+                        m_unknownContentHandler = NULL;
+                    }
+                    // If loading is defered, don't send the body now
+                    if (m_defersData) {
+                        HBufC8* buf = NULL;
+                        buf = chunkPtr.AllocL(); // ok to leave on error because it will trigger HandleError
+                        m_defersData->m_bodyParts.append(buf);
+                    }
+                    else {
+                        WebCore::ResourceHandle* rh = handle();
+                        if (rh) { rh->ref(); }
+                            
+                        CResourceHandleManager::self()->receivedData(m_handle, chunkPtr, 
+                        m_maxSize == 0 ? chunkPtr.Length() : m_maxSize, this);
+                        
+                        if ( m_transaction) 
+                            body->ReleaseData();
+                                    
+                        if (rh) { rh->deref(); }
+                        
+                        // this object might be invalid at this point
+                        return;
+                    }
+                }
+            }
+            /* If the transaction is closed - through extensive processing through receivedData(), above - the transaction may
+               already have been deleted (by HttpConnection::complete).  Check for existence of transaction
+               before releasing data (ReleaseData()) to prevent attempts to double delete memory. */
+            if ( m_transaction)
+                body->ReleaseData();
+            break;
+            }
+        case THTTPEvent::EResponseComplete:
+            {
+            // do not mix it up with the ESucceeded
+            // The transaction's response is complete. An incoming event.
+            if ( nonsecure ) {
+                TRAP_IGNORE( m_cacheSupply->ResponseCompleteL() );
+                }
+            break;
+            }
+        case THTTPEvent::ESucceeded:
+            {
+            complete(KErrNone);
+            break;
+            }
+        case THTTPEvent::ERequestComplete:
+            {
+            // request is all set
+            if ( nonsecure ) {
+                m_cacheSupply->CloseRequest();
+                }
+            break;
+            }
+        case THTTPEvent::EFailed:
+        case THTTPEvent::EMoreDataReceivedThanExpected:
+        case THTTPEvent::EUnrecoverableError:
+        case KErrAbort:
+            {
+                if (!m_transaction) {
+                    // this object might be invalid at this point.
+                    return;
+                    }
+                int statusCode = m_transaction->Response().StatusCode();
+                if ( statusCode != 200) {
+                    complete(-25000 - m_transaction->Response().StatusCode());
+                }
+                else if (statusCode == 200 && aEvent.iStatus == THTTPEvent::EFailed) {
+                    // this is a weird combination, it is caused by cached supplier when a response only has the
+                    // response header, but no response body is sent by the HTTP stack.  It is a legitimate senario though.
+                    complete(KErrNone);
+                }
+                else {
+                    complete(aEvent.iStatus);
+                }
+
+            break;
+            }
+        case THTTPEvent::ERedirectRequiresConfirmation:
+            {
+            TInt method = m_transaction->Request().Method().Index(RHTTPSession::GetTable());
+            TInt statusCode = m_transaction->Response().StatusCode();
+
+            if( (statusCode == 301 ) &&
+                !((method==HTTP::EGET) || (method==HTTP::EHEAD)) )
+                 {
+                    RHTTPRequest request = m_transaction->Request();
+                    RHTTPHeaders requestHeaders(request.GetHeaderCollection());
+                    RStringPool p = m_transaction->Session().StringPool();
+                    requestHeaders.RemoveField(p.StringF(HTTP::EContentLength,RHTTPSession::GetTable()));
+                    requestHeaders.RemoveField(p.StringF(HTTP::EContentType,RHTTPSession::GetTable()));
+                    m_transaction->Request().RemoveBody();
+                    m_transaction->Response().RemoveBody();
+                    m_transaction->Request().SetMethod(p.StringF(HTTP::EGET, RHTTPSession::GetTable()));
+                }
+            int ret = HandleSpecialEvent(THTTPEvent::ERedirectRequiresConfirmation);
+            if (ret != KErrNone) {
+                handleError(ret);
+                }
+            break;
+            }
+        case THTTPEvent::ERedirectedPermanently:
+        case THTTPEvent::ERedirectedTemporarily:
+            {
+            // for redirects, we must ensure that we properly handle
+            // any new or changed uri fragment
+            TUriParser8 uriParser;
+            uriParser.Parse( m_transaction->Request().URI().UriDes() );
+            // check for fragment
+            if(uriParser.IsPresent(EUriFragment)) {
+                // first extract the portion without fragment to
+                // return to Http framework
+                TPtrC8 uriNoFrag;
+                // extract non-fragment portion into uriNoFrag
+                uriParser.UriWithoutFragment( uriNoFrag );
+                TUriParser8 parserNoFrag;
+                parserNoFrag.Parse( uriNoFrag );
+                m_transaction->Request().SetURIL( parserNoFrag );
+                // now save the fragment for later use
+                const TDesC8& fragment = uriParser.Extract( EUriFragment );
+                delete m_frag;
+                m_frag = NULL;
+                m_frag = fragment.AllocL();
+                }
+            HandleSpecialEvent(aEvent.iStatus);
+            break;
+            }
+        case THTTPEvent::EGotResponseTrailerHeaders:
+            {
+            break;// We don't process this event
+            }
+        default:
+            {
+            // error handling
+            handleError(aEvent.iStatus);
+            break;
+            }
+        }
+    }
+
+int HttpConnection::HandleSpecialEvent(int event)
+{
+    int ret( KErrNone );
+    HttpSessionManager* httpSessionMgr = StaticObjectsContainer::instance()->resourceLoaderDelegate()->httpSessionManager();
+    switch( event )
+        {
+        case THTTPEvent::ERedirectRequiresConfirmation:
+            {
+                // Display a Redirect Confirmation dialog, before proceeding
+                ret = httpSessionMgr->uiCallback()->aboutToLoadPage(control(m_frame), HttpUiCallbacks::ERedirectConfirmation);
+                if (ret == KErrNone) {
+                    // submit redirected transaction
+                    TRAP(ret, m_transaction->SubmitL());
+                    return ret;
+                }
+                else {
+                    return KErrCancel;
+                }
+                break;
+            }
+        case THTTPEvent::ERedirectedPermanently:
+        case THTTPEvent::ERedirectedTemporarily:
+            {
+            // Cancel transaction first and resubmit it if the user accepted a secure connection
+            m_transaction->Cancel();
+            if (CheckForSecurityStatusChange() != KErrNone) {
+                return KErrCancel;
+                }
+            else {
+                ret = CheckForNonHttpRedirect();
+                if (ret == KErrNone) {
+                    // submit redirected transaction only in case of http request.
+                    TRAP(ret, m_transaction->SubmitL());
+                    return ret;
+                    }
+                else {
+                    return KErrCancel;
+                    }
+                }
+            break;
+            }
+        case KErrNotSupported:
+        default:
+            {
+                break;
+            }
+        }
+    return ret;
+}
+
+void HttpConnection::complete(int error)
+{
+    if (m_defersData) {
+        m_defersData->m_done = true;
+        m_defersData->m_error = error;
+        return;
+    }
+    
+    // protect this function from re-entry
+    if (m_isDone)
+        return;
+    m_isDone = true;
+
+    __ASSERT_DEBUG( m_transaction, THttpConnUtils::PanicLoader( KErrArgument ) );
+
+    if(m_IsMultipart && error == KErrNone) {
+        TInt status = m_MultipartContentHandler->ResponseComplete();
+        if(status == KErrNone) {
+            TPtrC8 encoding(*m_encoding);
+            if (m_MultipartContentHandler->MarkupCharset().Length()) {
+                encoding.Set(m_MultipartContentHandler->MarkupCharset());
+            }
+            ResourceResponse response(m_urlResponse->Des(), m_MultipartContentHandler->MarkupContentType(),
+                m_maxSize, encoding, String() );
+            response.setHTTPStatusCode(m_transaction->Response().StatusCode());
+            response.setHTTPStatusText(m_transaction->Response().StatusText().DesC());
+            if(m_handle->request().url() != response.url()) {
+                // Relative URLs are resolved based on the request URL, not response URL.
+                // If a redirect happens, the request URL must be updated.
+                m_handle->getInternal()->m_request.setURL(response.url());
+                m_frame->loader()->activeDocumentLoader()->request().setURL(response.url());
+            }
+            CResourceHandleManager::self()->receivedResponse(m_handle, response, this);
+            CResourceHandleManager::self()->receivedData(m_handle,
+                m_MultipartContentHandler->MarkupContent(), m_maxSize, this);
+        }
+        delete m_MultipartContentHandler;
+    }
+    if (!error) {
+        // Spawn active object for call to return immediately, to avoid blocking
+        activateReceivedFinished(error);  
+    }
+
+    if (m_cacheSupply) {
+        delete m_cacheSupply;
+        m_cacheSupply = NULL;
+    }
+    if (m_postDataSupplier) {
+        delete m_postDataSupplier;
+        m_postDataSupplier = NULL;
+    }
+    if (m_transaction) {
+        m_transaction->Cancel();
+        m_transaction->Close();
+        delete m_transaction;
+        m_transaction = NULL;
+    }
+    if (error) {
+        CResourceHandleManager::self()->receivedFinished(m_handle, error, this);
+        derefHandle();
+    }
+}
+
+// -----------------------------------------------------------------------------
+// HttpConnection::handleAuthRequestL
+//
+// -----------------------------------------------------------------------------
+//
+int HttpConnection::handleAuthRequestL(
+    int status )
+    {
+    int ret( KErrNone );
+    THTTPHdrVal usernameVal;
+    THTTPHdrVal passwordVal;
+    THTTPHdrVal realmVal;
+    THTTPHdrVal staleVal;
+    RHTTPTransactionPropertySet propSet = m_transaction->PropertySet();
+    RHTTPSession& session = StaticObjectsContainer::instance()->resourceLoaderDelegate()->httpSessionManager()->httpSession();
+    RStringPool strP = session.StringPool();
+    const TStringTable& stringTable = RHTTPSession::GetTable();
+
+    bool isProxy( EFalse );
+    bool needClose( EFalse );
+    bool pwdClose( EFalse );
+    bool realmClose( EFalse );
+    bool stale( propSet.Property( strP.StringF( HTTP::EStale, stringTable ), staleVal ) );
+
+    _LIT8( KStrNull, "" );
+    //
+    switch( status )
+        {
+        case EHttpUnauthorized:
+            {
+            if( !propSet.Property( strP.StringF( HTTP::ERealm, stringTable ), realmVal ) )
+                {
+                realmClose = ETrue;
+                realmVal = strP.OpenStringL( KStrNull );
+                }
+            if( !propSet.Property( strP.StringF( HTTP::EUsername, stringTable ), usernameVal ) )
+                {
+                needClose = ETrue;
+                usernameVal = strP.OpenStringL( KStrNull );
+                }
+            if( !propSet.Property(strP.StringF( HTTP::EPassword, stringTable ), passwordVal ) )
+                {
+                pwdClose = ETrue;
+                passwordVal = strP.OpenStringL( KStrNull );
+                }
+            break;
+            }
+        case EHttpProxyAuthenticationRequired:
+            {
+            const TStringTable& stringTableEx = HttpFilterCommonStringsExt::GetTable();
+            //
+            isProxy = ETrue;
+            if( !propSet.Property(strP.StringF( HttpFilterCommonStringsExt::EProxyRealm,
+                stringTableEx ), realmVal ) )
+                {
+                return KErrHttpDecodeUnknownAuthScheme;
+                }
+            if( !propSet.Property( strP.StringF( HttpFilterCommonStringsExt::EProxyUsername,
+                stringTableEx ), usernameVal ) )
+                {
+                needClose = ETrue;
+                usernameVal = strP.OpenStringL( KStrNull );
+                }
+            if( !propSet.Property( strP.StringF( HTTP::EPassword, stringTable ), passwordVal ) )
+                {
+                pwdClose = ETrue;
+                passwordVal = strP.OpenStringL( KStrNull );
+                }
+            break;
+            }
+        default:
+            {
+            __ASSERT_DEBUG( EFalse, THttpConnUtils::PanicLoader( KErrArgument ) );
+            break;
+            }
+        }
+
+    TRAP( ret, SendAuthRequestL( usernameVal, realmVal, isProxy, stale, passwordVal ) );
+    if (realmClose)
+      {
+        realmVal.Str().Close();
+        }
+    if( needClose )
+        {
+        usernameVal.Str().Close();
+        }
+    if( pwdClose )
+        {
+        passwordVal.Str().Close();
+        }
+    return(ret);
+    }
+
+// -----------------------------------------------------------------------------
+// HttpConnection::SendAuthRequestL
+//
+// -----------------------------------------------------------------------------
+//
+void HttpConnection::SendAuthRequestL(
+    THTTPHdrVal& aUsernameVal,
+    THTTPHdrVal& aRealmVal,
+    bool aIsProxy,
+    bool aStale,
+    THTTPHdrVal& aPasswordVal )
+    {
+
+    HttpSessionManager* httpSessionMgr = StaticObjectsContainer::instance()->resourceLoaderDelegate()->httpSessionManager();
+    RHTTPSession& session = httpSessionMgr->httpSession();
+    int popCount( 0 );
+
+    // prepare uri param
+    int len = m_transaction->Request().URI().UriDes().Length() + 1;
+    TUint16* uri = new(ELeave) TUint16 [ len ];
+    CleanupStack::PushL( uri );
+    popCount++;
+    TPtr uriPtr( uri, len );
+    uriPtr.Copy( m_transaction->Request().URI().UriDes() );
+    uriPtr.ZeroTerminate();
+
+    // prepare username param
+    len = aUsernameVal.Str().DesC().Length() + 1;
+    TUint16* username = new(ELeave) TUint16 [ len ];
+    CleanupStack::PushL( username );
+    popCount++;
+    TPtr usernamePtr( username, len );
+    usernamePtr.Copy( aUsernameVal.Str().DesC() );
+    usernamePtr.ZeroTerminate();
+
+    // prepare realm param
+    len = aRealmVal.Str().DesC().Length() + 1;
+    TUint16* realm = new(ELeave) TUint16 [ len ];
+    CleanupStack::PushL( realm );
+    popCount++;
+    TPtr realmPtr( realm, len );
+    realmPtr.Copy( aRealmVal.Str().DesC() );
+    realmPtr.ZeroTerminate();
+
+    // prepare password param
+    len = aPasswordVal.Str().DesC().Length() + 1;
+    TUint16* password = new(ELeave) TUint16 [ len ];
+    CleanupStack::PushL( password );
+    popCount++;
+    TPtr passwordPtr( password, len );
+    passwordPtr.Copy( aPasswordVal.Str().DesC() );
+    passwordPtr.ZeroTerminate();
+
+    // Get the authentication type
+    bool basicAuthentication( EFalse );
+    RHTTPTransactionPropertySet propSet = m_transaction->PropertySet();
+    THTTPHdrVal propRetVal;
+
+    // Get the name of the property
+    RStringF propName = session.StringPool().StringF( HTTP::EBasic, RHTTPSession::GetTable() );
+
+    // if it is set . .
+    if( propSet.Property( propName, propRetVal ) )
+        {
+        // . . then we have basic auth
+        basicAuthentication = ETrue;
+        }
+
+    // send data to dialog layer for user input.  Data from user is provided
+    // back to http transaction. by UiCallbacks calling HttpConnection::AuthenticationResponse
+    // Completion of this authentication process will therefore occur before
+    // the call below returns.
+    httpSessionMgr->uiCallback()->AuthenticationRequest( this, uriPtr, usernamePtr,
+        realmPtr, aIsProxy, aStale, passwordPtr, basicAuthentication );
+    CleanupStack::PopAndDestroy( popCount ); // password, realm, username, uri
+    }
+
+// -----------------------------------------------------------------------------
+// HttpConnection::AuthenticationResponse
+//
+//
+// -----------------------------------------------------------------------------
+//
+void HttpConnection::AuthenticationResponse(
+    TPtr& aUsername,
+    TPtr& aPassword,
+    bool aProxy,
+    int aError)
+    {
+    TUint16* username = (TUint16*) aUsername.Ptr();
+    TUint16* password = (TUint16*) aPassword.Ptr();
+
+    __ASSERT_DEBUG( m_transaction, THttpConnUtils::PanicLoader( KErrArgument ) );
+
+    int ret = KErrNone;
+
+    // Execution is back from the dialog, move the transaction
+    // from the authentication listback into active list
+    HttpSessionManager* httpSessionMgr = StaticObjectsContainer::instance()->resourceLoaderDelegate()->httpSessionManager();
+    httpSessionMgr->removeAuthRequest(this);
+    httpSessionMgr->addRequest(this, m_handle);
+
+    switch (aError)
+        {
+        case KErrNone:
+            {
+            TRAP( ret, this->AddAuthenticationPropertiesL( aUsername, aPassword, aProxy) );
+            if (ret == KErrNone)
+                {
+                m_transaction->SubmitL();
+                break;
+                }
+            aError = ret;
+            }
+        case KErrCancel:
+        case KErrNoMemory:
+        default:
+            {
+            delete username;
+            delete password;
+            this->complete( aError );
+            break;
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// HttpConnection::AddAuthenticationPropertiesL
+// Add username and password properties to the transaction.
+// -----------------------------------------------------------------------------
+//
+void HttpConnection::AddAuthenticationPropertiesL(
+    TPtr& aUsername,
+    TPtr& aPassword,
+    bool aProxy )
+    {
+    TUint16* username = (TUint16*) aUsername.Ptr();
+    TUint16* password = (TUint16*) aPassword.Ptr();
+    __ASSERT_DEBUG( username != NULL && password != NULL, THttpConnUtils::PanicLoader( KErrArgument ) );
+
+    __ASSERT_DEBUG( m_transaction, THttpConnUtils::PanicLoader( KErrArgument ) );
+
+    RString usernameStr;
+    RString passwordStr;
+    RStringPool stringPool = m_transaction->Session().StringPool();
+    RHTTPTransactionPropertySet propSet = m_transaction->PropertySet();
+    //
+    User::LeaveIfError( THttpConnUtils::OpenStringFromUnicode( stringPool, username, usernameStr ) );
+    CleanupClosePushL( usernameStr );
+    User::LeaveIfError( THttpConnUtils::OpenStringFromUnicode( stringPool, password, passwordStr ) );
+    CleanupClosePushL( passwordStr );
+    // set proxy authentication
+    if( aProxy )
+        {
+        propSet.RemoveProperty( stringPool.StringF( HttpFilterCommonStringsExt::EProxyUsername,
+            HttpFilterCommonStringsExt::GetTable() ) );
+
+        propSet.SetPropertyL( stringPool.StringF( HttpFilterCommonStringsExt::EProxyUsername,
+            HttpFilterCommonStringsExt::GetTable() ), usernameStr);
+
+        propSet.RemoveProperty( stringPool.StringF( HttpFilterCommonStringsExt::EProxyPassword,
+            HttpFilterCommonStringsExt::GetTable() ) );
+
+        propSet.SetPropertyL( stringPool.StringF( HttpFilterCommonStringsExt::EProxyPassword,
+            HttpFilterCommonStringsExt::GetTable()), passwordStr );
+        }
+    else
+        {
+        propSet.RemoveProperty( stringPool.StringF( HTTP::EUsername, RHTTPSession::GetTable() ) );
+
+        propSet.SetPropertyL( stringPool.StringF( HTTP::EUsername, RHTTPSession::GetTable() ),
+            usernameStr );
+
+        propSet.RemoveProperty( stringPool.StringF( HTTP::EPassword, RHTTPSession::GetTable() ) );
+
+        propSet.SetPropertyL( stringPool.StringF( HTTP::EPassword, RHTTPSession::GetTable() ),
+            passwordStr );
+        }
+    CleanupStack::PopAndDestroy( 2 ); // passwordStr, usernameStr
+    }
+
+// -----------------------------------------------------------------------------
+// HttpConnection::CheckForSecurityStatusChange
+//
+// -----------------------------------------------------------------------------
+//
+int HttpConnection::CheckForSecurityStatusChange()
+    {
+    int error(KErrNone);
+    bool requestedSecScheme(EFalse);
+    bool redirectedSecScheme(EFalse);
+
+    __ASSERT_DEBUG( m_transaction, THttpConnUtils::PanicLoader( KErrArgument ) );
+
+    if (m_handle->request().mainLoad() && !m_frame->ownerElement())
+        {
+        TUriParser8 redirectedParser;
+        if(redirectedParser.Parse( m_transaction->Request().URI().UriDes() ) == KErrNone)
+            {
+            //
+            if( redirectedParser.Extract( EUriScheme ).Compare(KHttps) == 0 )
+                {
+                    redirectedSecScheme = ETrue;
+                }
+            }
+        TUriParser8 requestedParser;
+        if(m_handle->request().url().des().Length() != 0 )
+            {
+            error = requestedParser.Parse(m_handle->request().url().des());
+            }
+        else
+            {
+            error = requestedParser.Parse(m_transaction->Request().URI().UriDes());
+            }
+        if(error == KErrNone)
+            {
+            //
+            if( requestedParser.Extract( EUriScheme ).Compare(KHttps) == 0 )
+                {
+                requestedSecScheme = ETrue;
+                }
+            }
+        //When submitting the request iSecurePage was set based on the request url
+        //Check the redirect url and see if the scheme has changed
+        HttpSessionManager* httpSessionMgr = StaticObjectsContainer::instance()->resourceLoaderDelegate()->httpSessionManager();
+        if(requestedSecScheme && !redirectedSecScheme) //redirection from a secure page to an unsecure one
+            {
+            error = httpSessionMgr->uiCallback()->aboutToLoadPage(control(m_frame), HttpUiCallbacks::EExitingSecurePage);
+            }
+        else if(redirectedSecScheme && !requestedSecScheme) //redirection to unsecurepage when secure page was requested
+            {
+            error = httpSessionMgr->uiCallback()->aboutToLoadPage(control(m_frame), HttpUiCallbacks::EEnteringSecurePage );
+            }
+        }
+    return error;
+    }
+
+// -----------------------------------------------------------------------------
+// HttpConnection::CheckForNonHttpRedirect
+//
+// -----------------------------------------------------------------------------
+//
+TInt HttpConnection::CheckForNonHttpRedirect()
+    {
+    TUriParser8 uriParser;
+
+    __ASSERT_DEBUG( m_transaction, THttpConnUtils::PanicLoader( KErrArgument ) );
+
+    if(uriParser.Parse( m_transaction->Request().URI().UriDes() ) == KErrNone)
+        {
+        if (uriParser.IsPresent(EUriHost) && uriParser.IsPresent(EUriScheme)) // looking only for absolue Url path and schemes other than http(s)
+            {
+            const TDesC8& scheme = uriParser.Extract(EUriScheme);
+            if (scheme.FindF(_L8("http")) == KErrNotFound) // everything but http(s)
+                {
+                TPtrC8 ptr(uriParser.UriDes());
+                // these arrays are pushed into CleanupStack in case leave
+                // if no leave, they will be freed below
+                RArray<TUint>* typeArray = new (ELeave) RArray<TUint>(1);
+                CleanupStack::PushL(typeArray);
+
+                CDesCArrayFlat* desArray = new (ELeave) CDesCArrayFlat(1);
+                CleanupStack::PushL(desArray);
+
+                User::LeaveIfError(typeArray->Append(EParamRequestUrl));
+
+                HBufC16* urlbuf = HBufC16::NewLC( ptr.Length()  + 1); // +1 for zero terminate
+                urlbuf->Des().Copy( ptr );
+                TPtr16 bufDes16 = urlbuf->Des();
+                bufDes16.ZeroTerminate();
+
+                desArray->AppendL(bufDes16);
+                CleanupStack::Pop();
+
+                MBrCtlSpecialLoadObserver* loadObserver = control(m_frame)->brCtlSpecialLoadObserver();
+
+                if (loadObserver)
+                    {
+                    TRAP_IGNORE(loadObserver->HandleRequestL(typeArray, desArray));
+                    }
+
+                // No leave, so pop here and clean up
+                CleanupStack::Pop(desArray);
+                CleanupStack::Pop(typeArray);
+
+                // cleanup arrays
+                if (typeArray)
+                    {
+                    // Closes the array and frees all memory allocated to the array
+                    typeArray->Close();
+                    delete typeArray;
+                    }
+
+                if (desArray)
+                    {
+                    // Deletes all descriptors from the array and frees the memory allocated to the array buffer
+                    desArray->Reset();
+                    delete desArray;
+                    }
+
+                return KErrCancel;
+                }
+            }
+        }
+    return KErrNone;
+    }
+
+RHTTPTransaction* HttpConnection::takeOwnershipHttpTransaction()
+{
+    __ASSERT_DEBUG( m_transaction, THttpConnUtils::PanicLoader( KErrArgument ) );
+
+    RHTTPTransaction* trans = m_transaction;
+    RHTTPSession& session = StaticObjectsContainer::instance()->resourceLoaderDelegate()->httpSessionManager()->httpSession();
+    // remove own address from transaction properties
+    m_transaction->PropertySet().RemoveProperty(session.StringPool().StringF(HttpFilterCommonStringsExt::ESelfPtr,
+        HttpFilterCommonStringsExt::GetTable()));
+    m_transaction = NULL;
+    return trans;
+}
+
+// -----------------------------------------------------------------------------
+// HttpConnection::addIMEINotifyPropertiesL
+// Keeping for completeness, but currently is not needed as functionality is implemented
+// in User-Agent Profile Filter
+// Add IMEINotify properties to the transaction.
+// -----------------------------------------------------------------------------
+//
+/*
+void HttpConnection::addIMEINotifyPropertiesL()
+{
+    // Get IMEI Notify enable/disable setting
+    HttpSessionManager* httpSessionMgr = StaticObjectsContainer::instance()->resourceLoaderDelegate()->httpSessionManager();
+    bool imeiNotify = httpSessionMgr->imeiEnabled();
+
+    RHTTPTransactionPropertySet propSet = m_transaction->PropertySet();
+
+    RStringPool stringPool = m_transaction->Session().StringPool();
+    propSet.RemoveProperty( stringPool.StringF(
+        HttpFilterCommonStringsExt::EIMEINotify, HttpFilterCommonStringsExt::GetTable() ) );
+    //
+    propSet.SetPropertyL( stringPool.StringF( HttpFilterCommonStringsExt::EIMEINotify,
+        HttpFilterCommonStringsExt::GetTable() ), THTTPHdrVal( imeiNotify ) );
+}
+*/
+
+// -----------------------------------------------------------------------------
+// HttpLoaderUtils::IsUrlInCache
+//
+// Returns ETrue if Cache Manager finds the Url in cache, EFalse otherwise
+// -----------------------------------------------------------------------------
+//
+bool HttpConnection::IsUrlInCacheL(
+    const TDesC8& aUrl )
+{
+    TBool inCache( EFalse );  // not in cache by default
+	m_isInCache = EFalse;
+
+    CHttpCacheManager* cache = StaticObjectsContainer::instance()->resourceLoaderDelegate()->httpSessionManager()->cacheManager();
+
+    if ( cache )
+    {
+        // call cache manager to check for url in cache
+        inCache = cache->Find( aUrl );
+    }
+	m_isInCache = inCache;
+    return inCache;
+}
+
+void HttpConnection::processDefersData(void* ctx)
+{
+    HttpConnection* self = static_cast<HttpConnection*>(ctx);
+    DefersData* defersData = self->m_defersData;
+    if (self->m_cancelled)
+        return;
+    if (self->m_defersData->m_response) {
+        CResourceHandleManager::self()->receivedResponse(self->m_handle, *(self->m_defersData->m_response), self);
+        // transaction is complete (must have been cancelled in receivedResponse call
+        if (self->m_isDone)
+            return;
+        // transaction is taken, we need to cleanup this resource.
+        if (!self->m_transaction) {
+            self->derefHandle();
+            // this object might be invalid at this point
+            return;
+        }
+        delete self->m_defersData->m_response;
+        self->m_defersData->m_response = NULL;
+        self->m_defersData->Activate();
+        return;
+    }
+    if (self->m_defersData->m_bodyParts.size()) {
+        HBufC8* buf = self->m_defersData->m_bodyParts.first();
+        self->m_defersData->m_bodyParts.remove(0);
+        CResourceHandleManager::self()->receivedData(self->m_handle, *buf, self->m_maxSize, self);
+        delete buf;
+        self->m_defersData->Activate();
+        return;
+    }
+    if (self->m_defersData->m_done) {
+        self->m_defersData = NULL;
+        self->complete(defersData->m_error);
+    }
+    self->m_defersData = NULL;
+    delete defersData;
+}
+
+
+void HttpConnection::activateReceivedFinished(TInt errorCode) 
+{
+        if (m_receivedFinished) {
+            if (m_receivedFinished->isDone()) {
+                delete m_receivedFinished;
+            } else {
+                // This would happen if processing of a previous transaction is hung.
+                // We should never get in here.
+                m_receivedFinished ->Cancel();
+                return;
+            }
+        }
+            
+        m_receivedFinished = new ReceivedFinished(this, processReceivedFinished);
+        m_receivedFinished->Activate(errorCode);
+}
+
+void HttpConnection::processReceivedFinished(void* ctx, TInt errorCode)
+{
+    HttpConnection* self = static_cast<HttpConnection*>(ctx);
+    CResourceHandleManager::self()->receivedFinished(self->m_handle, errorCode, self);
+
+    self->derefHandle();
+}
+
+
+// end of file