codhandler/codeng/src/HttpLoader.cpp
changeset 0 dd21522fd290
child 16 a359256acfc6
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/codhandler/codeng/src/HttpLoader.cpp	Mon Mar 30 12:54:55 2009 +0300
@@ -0,0 +1,1973 @@
+/*
+* Copyright (c) 2002 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: 
+*      Loading functions for COD Handler.   
+*      
+*
+*/
+
+
+// INCLUDE FILES
+
+#include "HttpLoader.h"
+#include "CodSaver.h"
+#include "HttpTcpSession.h"
+#include "HttpWapSession.h"
+#include "CodLogger.h"
+#include "CodPanic.h"
+#include "CodError.h"
+#include "CodUtil.h"
+#include "Connection.h"
+#include "Timeout.h"
+#include "CodProgress.h"
+#include "CodEngbase.h"
+
+#include <CookieFilterInterface.h>
+#include <uaproffilter_interface.h>
+#include <DeflateFilterInterface.h>
+#include <httperr.h>
+#include <bldvariant.hrh>
+#include <ECom.h>
+#include <es_sock.h>
+#include <EscapeUtils.h>
+#include <http/rhttpheaders.h>
+#include <Oma2Agent.h>
+#include <HttpDownloadMgrCommon.h>
+#include    "HeaderField.h"
+#include    "FileExt.h"
+#include    "CodData.h"
+
+
+
+_LIT8( KDRMOldContentType, "x-drm-old-content-type");           // old content type header to be added
+_LIT8( KAcceptRangeHeader, "bytes");           
+
+// ================= CONSTANTS =======================
+
+/// Maximum user name length we support.
+LOCAL_D const TInt KCodMaxAuthUserName = 50;
+/// Maximum password length we support.
+LOCAL_D const TInt KCodMaxAuthPassword = 50;
+/// WSP protocol name.
+_LIT8( KCodWspProtocol, "WSP/WSP" );
+/// Accept-header value (application/vnd.wap.mms-message).
+_LIT8( KCodAcceptMmsHeaderValue, "application/vnd.wap.mms-message" );
+/// Accept-header value (application/vnd.wap.sic).
+_LIT8( KCodAcceptSiHeaderValue, "application/vnd.wap.sic" );
+/// "No activity" timeout for GET request (in microseconds), 60 sec - Updated to 60 secs as part of error fix JSIN-7JSE6H
+/// Let's try to keep the same timeout for WCDMA & GPRS (???)
+LOCAL_D const TInt KCodGetTimeout = 60000000;
+/// "No activity" timeout for POST request (in microseconds), 10 sec.
+LOCAL_D const TInt KCodPostTimeout = 10000000;
+/// Install-notify timeout (in microseconds), 50 msec.
+LOCAL_D const TInt KCodINTimeout = 50000;
+/// Retry count for GET request timeout (1 attempt == no retry).
+LOCAL_D const TInt KCodGetRetry = 1;
+/// Retry count for POST request timeout (2 attempt == 1 retry).
+LOCAL_D const TInt KCodPostRetry = 2;
+/// Estimated data transfer for reponse headers. Needed for progress.
+LOCAL_D const TInt KCodRespHdrsTraffic = 512;
+/// characters which should be escaped from requested URL's
+_LIT8( KUriEscChars, " ");
+
+// ================= MEMBER FUNCTIONS =======================
+
+// ---------------------------------------------------------
+// CHttpLoader::NewL()
+// ---------------------------------------------------------
+//
+CHttpLoader* CHttpLoader::NewL
+        (
+        CConnection& aConnection,
+        MCodLoadObserver* aCodLoadObserver,
+        TCodProgress* aProgress ,
+        CCodEngBase* aCodEng 
+        )
+    {
+    CHttpLoader* loader =
+        new( ELeave ) CHttpLoader( aConnection, aCodLoadObserver, aProgress, aCodEng );
+    CleanupStack::PushL( loader );
+    loader->ConstructL();
+    CleanupStack::Pop( loader );
+    return loader;
+    }
+// ---------------------------------------------------------
+// CHttpLoader::~CHttpLoader()
+// ---------------------------------------------------------
+//
+CHttpLoader::~CHttpLoader()
+    {
+    Cancel();
+    iFeatMgr.Close();
+    delete iTimeout;
+    delete iSess;
+    delete iNotifyBody;
+    delete iUri;
+    delete iINTimeout;
+    
+     if(iResponseHeaders != NULL)
+    {
+    iResponseHeaders->ResetAndDestroy();
+    delete iResponseHeaders;
+    }
+    
+    delete iDownloadInfo;
+
+    REComSession::FinalClose();
+    __ASSERT_DEBUG( !iParentStatus, CodPanic( ECodRequestPending ) );
+    CLOG(( EHttpLoad, 2, _L("*** CHttpLoader::~CHttpLoader") ));
+    }
+
+// ---------------------------------------------------------
+// CHttpLoader::LoadL()
+// ---------------------------------------------------------
+//
+void CHttpLoader::LoadL
+        (
+        const TDesC8& aUrl,
+        MCodSaverFactory& aSaverFactory,
+        TRequestStatus* aStatus
+        )
+    {
+    CLOG(( EHttpLoad, 2, _L("-> CHttpLoader::LoadL") ));
+    // Misuse asserts.
+    __ASSERT_ALWAYS( aStatus, CodPanic( ECodInvalidArguments ) );
+    __ASSERT_ALWAYS( iState == EInit, CodPanic( ECodOffState ) );
+    // Internal asserts.
+    __ASSERT_DEBUG( !iParentStatus, CodPanic( ECodInternal ) );
+    __ASSERT_DEBUG( !iSaverFactory, CodPanic( ECodInternal ) );
+    __ASSERT_DEBUG( !iSaver, CodPanic( ECodInternal ) );
+    __ASSERT_DEBUG( !iUri, CodPanic( ECodInternal ) );
+
+    iUri = aUrl.AllocL();
+    iMethod = HTTP::EGET;
+    iRetry = KCodGetRetry;
+    iSaverFactory = &aSaverFactory;
+    iResult = KErrNone;
+    iRedirect = EFalse;
+    
+    
+    iCodEng->LoadSubInfoFileL(iCodEng->Data().ActiveDownload() , iResponseHeaders );
+    
+    TBuf8<128> contentType;
+    TRAPD( err, contentType = GetContentTypeL() );
+    if(err == KErrNone)
+        {
+        iSaver = iSaverFactory->CreateSaverL( contentType );
+        }
+        
+    iParentStatus = aStatus;
+    *iParentStatus = KRequestPending;
+
+    if( iProgress && iSaver )
+        {
+        iSaver->SetSourceUriL(iUri->Des() );
+        TInt dlSize( 0 );
+        //Current Track Downloaded Size
+        dlSize += iCodEng->Data()[iCodEng->Data().ActiveDownload()]->DownloadedSize();
+                
+        if(dlSize >= 0)
+            {
+            iProgress->SetAmountL(dlSize);                
+            }
+        }
+
+    if( iProgress )
+    	{
+    	iProgress->StartPhaseL(TCodProgress::ELoad);
+    	}
+
+    Continue( EStart );
+
+    CLOG(( EHttpLoad, 2, _L("<- CHttpLoader::LoadL") ));
+    }
+
+// ---------------------------------------------------------
+// CHttpLoader::NotifyL()
+// ---------------------------------------------------------
+//
+void CHttpLoader::NotifyL
+( const TDesC8& aUrl, const TDesC8& aNotifyBody, TRequestStatus* aStatus )
+    {
+    CLOG(( EHttpLoad, 2, _L("-> CHttpLoader::NotifyL") ));
+    // Misuse asserts.
+    __ASSERT_ALWAYS( aStatus, CodPanic( ECodInvalidArguments ) );
+    __ASSERT_ALWAYS( iState == EInit, CodPanic( ECodOffState ) );
+    // Internal asserts.
+    __ASSERT_DEBUG( !iParentStatus, CodPanic( ECodInternal ) );
+    __ASSERT_DEBUG( !iNotifyBody, CodPanic( ECodInternal ) );
+    __ASSERT_DEBUG( !iUri, CodPanic( ECodInternal ) );
+
+    // Allocation of two members iUri+iNotifyBody is atomic.
+    HBufC8* notifyBody = aNotifyBody.AllocLC();
+    iUri = aUrl.AllocL();
+    iNotifyBody = notifyBody;
+    CleanupStack::Pop( notifyBody );    // now member.
+    iMethod = HTTP::EPOST;
+    iRetry = KCodPostRetry;
+    iParentStatus = aStatus;
+    *iParentStatus = KRequestPending;
+    iResult = KErrNone;
+
+    Continue( EStart );
+
+    CLOG(( EHttpLoad, 2, _L("<- CHttpLoader::NotifyL") ));
+    }
+
+// ---------------------------------------------------------
+// CHttpLoader::DoCancel()
+// ---------------------------------------------------------
+//
+void CHttpLoader::DoCancel()
+    {
+    CLOG(( EHttpLoad, 2, _L("-> CHttpLoader::DoCancel iState(%d)"), iState ));
+    switch ( iState )
+        {
+        case EStart:
+            {
+            // Already completed (by self-completion).
+            __ASSERT_DEBUG( iStatus != KRequestPending, \
+                CodPanic( ECodInternal ) );
+            SelfComplete( KErrCancel );
+            break;
+            }
+
+        case EOpen:
+            {
+            __ASSERT_DEBUG( iSess, CodPanic( ECodInternal ) );
+            // This will complete our status.
+            iSess->Disconnect();
+            break;
+            }
+
+        case ERequest:
+            {
+            CompleteTransaction( KErrCancel );
+            break;
+            }
+
+        case EInit:
+        default:
+            {
+            // No requests should be outstanding in these states.
+            CLOG(( EHttpLoad, 0, _L("CHttpLoader::DoCancel: unexpected state") ));
+            CodPanic( ECodInternal );
+            break;
+            }
+        }
+
+    iResult = KErrCancel;
+    Done();
+
+    CLOG(( EHttpLoad, 2, _L("<- CHttpLoader::DoCancel") ));
+    }
+
+
+
+void CHttpLoader::Pause()
+    {
+    CLOG(( EHttpLoad, 2, _L("-> CHttpLoader::Pause iState(%d)"), iState ));
+    switch ( iState )
+        {
+        case ERequest:
+            {
+            CompleteTransaction( KErrCodHttpDownloadPaused );
+            break;
+            }
+        }
+    //Done();
+
+    CLOG(( EHttpLoad, 2, _L("<- CHttpLoader::Pause") ));
+    }
+
+// ---------------------------------------------------------
+// CHttpLoader::RunL()
+// ---------------------------------------------------------
+//
+void CHttpLoader::RunL()
+    {
+    CLOG(( EHttpLoad, 2, _L("-> CHttpLoader::RunL iState(%d) iStatus(%d)"), \
+        iState, iStatus.Int() ));
+
+    User::LeaveIfError( iStatus.Int() );    // Handle errors in RunError.
+    switch ( iState )
+        {
+        case EStart:
+            {
+            // Operation initiated - Open a session.
+            OpenSessionL();
+            break;
+            }
+
+        case EOpen:
+            {
+            // Session opened. Make the HTTP request.
+            RequestL();
+            break;
+            }
+
+        case ERequest:
+            {
+            // Request completed, we are done.
+            Done();
+            break;
+            }
+
+        case EInit:
+        default:
+            {
+            // No requests should be outstanding in these states.
+            CLOG(( ECodEng, 0, _L("CHttpLoader::RunL: unexpected state") ));
+            CodPanic( ECodInternal );
+            break;
+            }
+        }
+    CLOG(( EHttpLoad, 2, _L("<- CHttpLoader::RunL") ));
+    }
+
+// ---------------------------------------------------------
+// CHttpLoader::RunError()
+// ---------------------------------------------------------
+//
+TInt CHttpLoader::RunError( TInt aError )
+    {
+    CLOG(( EHttpLoad, 2, _L("-> CHttpLoader::RunError aError(%d)"), aError ));
+    iResult = aError;
+    Done();
+    CLOG(( EHttpLoad, 2, _L("<- CHttpLoader::RunError") ));
+    return KErrNone;
+    }
+
+// ---------------------------------------------------------
+// CHttpLoader::MHFRunL()
+// ---------------------------------------------------------
+//
+void CHttpLoader::MHFRunL
+( RHTTPTransaction DEBUG_ONLY( aTransaction ), const THTTPEvent& aEvent )
+    {
+    CLOG(( EHttpLoad, 0, _L("-> CHttpLoader::MHFRunL event(%d)"), \
+                                                            aEvent.iStatus ));
+    __ASSERT_DEBUG( aTransaction == iTrans, CodPanic( ECodInternal ) );
+    __ASSERT_DEBUG( iState == ERequest, CodPanic( ECodOffState ) );
+
+    StartTimeout();    // There was activity -> restart timeout.
+
+    switch ( aEvent.iStatus )
+        {
+        case THTTPEvent::EGotResponseHeaders:
+            {
+            // Now we know that the request was processed by the server.
+            iSuppressErrors = EFalse;
+            if (iMethod == HTTP::EGET)
+            {
+                StoreResponseHeaderL();
+                
+                //If DD contain TYPE defined more than once, 
+            	//TYPE defined in the ClntServ should match the Content-Type that we obtain in the header while content downloading 
+            
+           	    const TDesC8& ContentType = GetContentTypeL( iTrans.Response().GetHeaderCollection() );
+                const CCodData& CodData = iCodEng->Data();
+          
+                for ( TInt i = 1; i < CodData[CodData.ActiveDownload()]->Types().MdcaCount(); i++ )
+            		{
+          			const TDataType& type( CodData[CodData.ActiveDownload()]->Types().MdcaPoint( i ) );
+            		if(ContentType.Find (type.Des8()) != KErrNotFound )             
+                		{
+                		CodData[CodData.ActiveDownload()]->ReArrangeTypesL(i);
+                		iCodEng->ContentTypeChanged();
+                		break;
+               			}                
+            		}
+
+                iCodEng->StoreSubInfoFileL(iResponseHeaders, iCodEng->Data().ActiveDownload() );
+            }
+            HandleResponseHeadersL( iTrans.Response() );
+            
+            if (iResult == KErrCodHttpBadUrl ) 
+            {
+            	User::Leave( KErrCodHttpBadUrl );
+            } 
+            else if ( iResult == KErrCodHttpBadResponse ) 
+            {
+            	User::Leave( KErrCodHttpBadResponse );
+            }
+            else 
+            {
+                // Increment progress a bit to make update frequent.
+                IncProgressL( KCodRespHdrsTraffic );	
+            }
+            break;
+            }
+
+        case THTTPEvent::EGotResponseBodyData:
+            {
+            // Get body data and save (GET) or ignore (POST)
+            TInt err( KErrNone );
+            TInt size;
+            MHTTPDataSupplier* body = iTrans.Response().Body();
+            TPtrC8 bodyP;
+            // Caution: no leaving between body->GetNextDataPart and
+            // body->ReleaseData calls! Data must always be released.
+#ifdef __TEST_COD_LOG
+            TBool lastChunk = // ('Log-only' variable.)
+#endif /* def __TEST_COD_LOG */
+            body->GetNextDataPart( bodyP );     // No leave...
+            size = bodyP.Size();
+#ifdef __TEST_COD_LOG
+            CDUMP(( EHttpLoad, 5, _S("Data: "), _S("      "), \
+                bodyP.Ptr(), bodyP.Size() ));
+            if ( lastChunk )
+                {
+                CLOG(( EHttpLoad, 5, _L("      (EOF)") ));
+                }
+            else
+                {
+                CLOG(( EHttpLoad, 5, _L("      (more data)") ));
+                }
+#endif /* def __TEST_COD_LOG */
+            if ( iMethod == HTTP::EGET )
+                {
+//TODO check  if iSaver == NULL occures                __ASSERT_DEBUG( iSaver, CodPanic( ECodInternal ) );
+                if (iSaver)
+				{
+                  err = iSaver->AppendData( bodyP );
+                  iCodEng->UpdateDownloadedSize( bodyP.Size());  
+				}
+			}
+            body->ReleaseData();                // ...until here.
+            User::LeaveIfError( err );
+            IncProgressL( size );
+            break;
+            }
+            
+        case THTTPEvent::EResponseComplete:
+            {
+             if(iSaver)
+                 {
+                 iSaver->OnComplete();
+                 }
+             
+        	 break;
+            }    
+
+        case THTTPEvent::EFailed:
+            {
+            // Safety code: we should already have an error code.
+            if ( iResult == KErrNone )
+                {
+                iResult = KErrCodWapConnectionDropped;
+                }
+            // Fall through.
+            }
+
+        case THTTPEvent::ESucceeded:
+            {
+            CompleteTransaction( iResult );
+            break;
+            }
+
+        case THTTPEvent::ERedirectRequiresConfirmation:
+            {
+            // 3xx redirect response received for POST. Redirect filter is
+            // cautious to redirect POST request and asks for confirmation.
+            // Confirmation means that we must resubmit the transaction.
+            iTrans.SubmitL();
+            break;
+            }
+            
+        case THTTPEvent::ERedirectedPermanently:
+        	{
+        	RedirectedPermanentlyL(iTrans.Request().URI().UriDes());
+        	break;
+        	}
+        	
+        case THTTPEvent::ERedirectedTemporarily:
+        	{
+        	RedirectedTemporaryL(iTrans.Request().URI().UriDes());
+        	break;
+        	}
+
+        default:
+            {
+            if( aEvent.iStatus == KErrHttpRedirectUseProxy && UseProxyL() )
+                {
+                // KErrHttpRedirectUseProxy is sent by redirect filter if the
+                // response is 305 Use Proxy. This is not really an error;
+                // error code is returned only to indicate that the redirect
+                // filter cannot handle this kind of redirect automatically;
+                // client action is required.
+                //
+                // If UseProxyL can successfully set the new proxy address,
+                // this is not an error. Otherwise it is.
+                ;
+                }
+            else if( aEvent.iStatus == KErrConnectionTerminated )
+                {
+                // if we get KErrConnectionTerminated during period of time
+                // when install-notify timeout is active, that means that
+                // connection has closed prior to timer firing and we should
+                // not make content available to user, then handle the error
+                // normally after that
+                CLOG(( EHttpLoad, 2, _L("CHttpLoader::MHFRunL: aEvent.iStatus = KErrConnectionTerminated") ));
+                if( iINTimeout && iINTimeout->IsActive() )
+                    {
+                    CLOG(( EHttpLoad, 2, _L(" :install-notify timeout active: set iSuppressError=EFalse") ));
+                    iINTimeout->Cancel();
+                    iSuppressErrors = EFalse;
+                    }
+                // finish handling error in MHFRunError
+                User::Leave( KErrConnectionTerminated ); 
+                }
+            else if( aEvent.iStatus ==  KErrHttpPartialResponseReceived )
+                {
+                //Partial response has been received and connection has been disconnected. This error will be 
+                //propagated to the client only, if the HTTP:ENotifyOnDisconnect property is set with a value
+                //HTTP::EEnableDisconnectNotification
+                
+                //This error code was cancelling the pausable download. This error shud be ignored to keep the
+                //paused download.
+                //TSW Err ID : SXUU-77SRWL
+                
+                CLOG(( EHttpLoad, 2, _L("CHttpLoader::MHFRunL: aEvent.iStatus = KErrHttpPartialResponseReceived") ));
+                }                
+            else
+                {
+                // Handle errors in MHFRunError.
+                User::LeaveIfError( aEvent.iStatus );
+                }
+            break;
+            }
+        }
+    CLOG(( EHttpLoad, 0, _L("<- CHttpLoader::MHFRunL") ));
+    }
+
+// ---------------------------------------------------------
+// CHttpLoader::MHFRunError()
+// ---------------------------------------------------------
+//
+TInt CHttpLoader::MHFRunError
+        (
+        TInt aError,
+        RHTTPTransaction DEBUG_ONLY( aTransaction ),
+        const THTTPEvent& /*aEvent*/
+        )
+    {
+    CLOG(( EHttpLoad, 2, _L("-> CHttpLoader::MHFRunError (%d)"), aError ));
+    __ASSERT_DEBUG( aTransaction == iTrans, CodPanic( ECodInternal ) );
+    __ASSERT_DEBUG( iState == ERequest, CodPanic( ECodOffState ) );
+    CompleteTransaction( aError );
+    CLOG(( EHttpLoad, 2, _L("<- CHttpLoader::MHFRunError") ));
+    return KErrNone;
+    }
+
+// ---------------------------------------------------------
+// CHttpLoader::GetNextDataPart()
+// ---------------------------------------------------------
+//
+TBool CHttpLoader::GetNextDataPart( TPtrC8& aDataPart )
+    {
+    __ASSERT_DEBUG( iNotifyBody, CodPanic( ECodInternal ) );
+    aDataPart.Set( iNotifyBody->Des() );
+    return ETrue;
+    }
+
+// ---------------------------------------------------------
+// CHttpLoader::ReleaseData()
+// ---------------------------------------------------------
+//
+void CHttpLoader::ReleaseData()
+    {
+    // Do not delete iNotifyBody here. Reset() may be called and since we
+    // do support it, we may need to provide the data again.
+    // iNotifyBody will be deleted in Done(); that's a safe place.
+    }
+
+// ---------------------------------------------------------
+// CHttpLoader::OverallDataSize()
+// ---------------------------------------------------------
+//
+TInt CHttpLoader::OverallDataSize()
+    {
+    __ASSERT_DEBUG( iNotifyBody, CodPanic( ECodInternal ) );
+    return iNotifyBody->Des().Size();
+    }
+
+// ---------------------------------------------------------
+// CHttpLoader::Reset()
+// ---------------------------------------------------------
+//
+TInt CHttpLoader::Reset()
+    {
+    return KErrNone;
+    }
+
+// ---------------------------------------------------------
+// CHttpLoader::GetCredentialsL()
+// ---------------------------------------------------------
+//
+TBool CHttpLoader::GetCredentialsL
+        (
+        const TUriC8& aURI,
+        RString aRealm, 
+        RStringF /*aAuthenticationType*/,
+        RString& aUsername, 
+        RString& aPassword
+        )
+    {
+    TBool ret( EFalse );
+    if ( iCodLoadObserver )
+        {
+        // Unfortunately, everything has to be converted from 8 to 16 bit
+        // and vice versa.
+        HBufC* host = CodUtil::ConvertLC( aURI.UriDes() );
+        HBufC* realm = CodUtil::ConvertLC( aRealm.DesC() );
+        TBuf<KCodMaxAuthUserName> userName;
+        TBuf<KCodMaxAuthPassword> password;
+        ret = iCodLoadObserver->UserAuthL
+            ( *host, *realm, EFalse, userName, password );
+        CleanupStack::PopAndDestroy( 2 );   // realm, host
+        HBufC8* userName8 = CodUtil::ConvertLC( userName );
+        aUsername = iSess->Sess().StringPool().OpenStringL( *userName8 );
+        CleanupStack::PopAndDestroy( userName8 );
+        CleanupClosePushL<RString>( aUsername );
+        HBufC8* password8 = CodUtil::ConvertLC( password );
+        aPassword = iSess->Sess().StringPool().OpenStringL( *password8 );
+        CleanupStack::PopAndDestroy( password8 );
+        CleanupStack::Pop();    // closing aUsername
+        }
+    return ret;
+    }
+
+// ---------------------------------------------------------
+// CHttpLoader::CHttpLoader()
+// ---------------------------------------------------------
+//
+CHttpLoader::CHttpLoader
+        (
+        CConnection& aConnection,
+        MCodLoadObserver* aCodLoadObserver,
+        TCodProgress* aProgress,
+        CCodEngBase* aCodEng
+        )
+: CActive( CActive::EPriorityStandard ),
+  iMethod( HTTP::EGET ),
+  iHttpVersion( HTTP::EHttp11 ),
+  iConn( aConnection ),
+  iCodLoadObserver( aCodLoadObserver ),
+  iState( EInit ),
+  iResult( KErrNone ),
+  iSuppressErrors( EFalse ),
+  iProxySet( EFalse ),
+  iProgress( aProgress ),
+  iRetry( KCodGetRetry ),
+  iCodEng(aCodEng),
+  iPausableDRM( ETrue )
+    {
+    CActiveScheduler::Add( this );
+	if (iCodLoadObserver)
+	{
+	iCodLoadObserver->SetConnError( KErrNone);
+	}
+    CLOG(( EHttpLoad, 2, _L("*** CHttpLoader::CHttpLoader") ));
+    }
+// ---------------------------------------------------------
+// CHttpLoader::ConstructL()
+// ---------------------------------------------------------
+//
+void CHttpLoader::ConstructL() 
+    {
+    iFeatMgr.OpenL();
+    
+	iResponseHeaders = new (ELeave) CArrayPtrFlat<CHeaderField>(2);	
+	
+    }
+
+// ---------------------------------------------------------
+// CHttpLoader::OpenSessionL
+// ---------------------------------------------------------
+//
+void CHttpLoader::OpenSessionL()
+    {
+    CLOG(( EHttpLoad, 2, _L("-> CHttpLoader::OpenSessionL") ));
+
+    if( iSess )
+        {
+        // Already opened.
+        // Synchronous state change - we are already under RunL.
+        CLOG(( EHttpLoad, 3, _L("  already open") ));
+        iState = EOpen;
+        RequestL();
+        }
+    else
+        {
+        if ( iFeatMgr.FeatureSupported( KFeatureIdWsp ) )
+            {
+            CLOG(( EHttpLoad, 4, _L("  KFeatureIdWsp supported") ));
+            TUint32 iap;
+            if ( !iConn.IsConnected( iap ) )
+                {
+                CLOG(( EHttpLoad, 3, _L("  not connected, leaving") ));
+                User::Leave( KErrCodCannotConnect );
+                }
+            HBufC8* gateway = CodUtil::WapGatewayL( iap );  // NULL if not WAP.
+            CleanupStack::PushL( gateway );                 // Push NULL is OK.
+            if ( gateway )
+                {
+                CLOG(( EHttpLoad, 4, _L("  AP has WAP gateway") ));
+                // We have a valid WAP gateway. Check WSP protocol
+                // availability.
+                CLOG(( EHttpLoad, 3, _L("  Protocols available:") ));
+                TInt i;
+                TPtrC8 protocol;
+                RPointerArray<HBufC8> protocols;
+                RHTTPSession::ListAvailableProtocolsL( protocols );
+                for( i = 0; i < protocols.Count(); i++ )
+                    {
+                    protocol.Set( protocols[i]->Des() );
+                    CLOG(( EWapConn | ETcpConn, 3, _L8("  <%S>"), &protocol ));
+                    if( !protocol.Compare( KCodWspProtocol ) )
+                        {
+                        // WSP available. Use a WAP session.
+                        iSess = CHttpWapSession::NewL( *gateway );
+                        break;
+                        }
+                    }
+                }
+            CleanupStack::PopAndDestroy( gateway ); // NULL is OK.
+            }
+        if( !iSess )
+            {
+            // No valid WAP gateway or WSP not available - use TCP session.
+            iSess = CHttpTcpSession::NewL();
+            }
+
+        SetupSessionL();
+
+        iSess->ConnectL( &iStatus );
+        iState = EOpen;
+        SetActive();
+        }
+
+    CLOG(( EHttpLoad, 2, _L("<- CHttpLoader::OpenSessionL") ));
+    }
+
+// ---------------------------------------------------------
+// CHttpLoader::RequestL()
+// ---------------------------------------------------------
+//
+void CHttpLoader::RequestL()
+    {
+    CLOG(( EHttpLoad, 2, _L("-> CHttpLoader::RequestL") ));
+    __ASSERT_DEBUG( iState == EOpen, CodPanic( ECodOffState ) );
+    __ASSERT_DEBUG( iSess, CodPanic( ECodInternal ) );
+    if( !iTimeout )
+        {
+        iTimeout = CTimeout::NewL
+            ( CActive::EPriorityStandard, TCallBack( StaticTimeout, this ) );
+        }
+    iHttpVersion = HTTP::EHttp11;
+    CreateTransactionL();
+    SubmitTransactionL();
+    // Wait it out.
+    // In ERequest state there is no other object that takes a request status
+    // to complete. Instead, events come via MHF... callbacks, and there is
+    // always a final event, when we complete our status manually.
+    iState = ERequest;
+    iStatus = KRequestPending;
+    SetActive();
+    StartTimeout(); // After state change! Timeout unexpected in other states.
+    CLOG(( EHttpLoad, 2, _L("<- CHttpLoader::RequestL") ));
+    }
+
+// ---------------------------------------------------------
+// CHttpLoader::Done()
+// ---------------------------------------------------------
+//
+void CHttpLoader::Done()
+    {
+    CLOG(( EHttpLoad, 2, \
+        _L("-> CHttpLoader::Done iResult(%d) iSuppressErrors(%d)"), \
+        iResult, iSuppressErrors ));
+    if( iTimeout )
+        {
+        iTimeout->Cancel();
+        }
+    iTrans.Close();
+    if( iProxySet && iSess )
+        {
+        // Remove proxy address property from session.
+        RHTTPConnectionInfo connInfo = iSess->Sess().ConnectionInfo();
+        connInfo.RemoveProperty( StringF( HTTP::EUseProxy ) );
+        connInfo.RemoveProperty( StringF( HTTP::EProxyAddress ) );
+        iProxySet = EFalse;
+        }
+    if ( iSaver )
+        {
+        iSaver->CloseStore();
+        }
+    if( iINTimeout )
+        {
+        iINTimeout->Cancel();
+        }
+    iSaverFactory = NULL;
+    iSaver = NULL;
+    delete iNotifyBody;
+    iNotifyBody = NULL;
+    delete iUri;
+    iUri = NULL;
+    iMethod = HTTP::EGET;
+    if ( iSuppressErrors )
+        {
+        iResult = KErrNone;
+        iSuppressErrors = EFalse;
+        }
+    // Notify parent.
+    __ASSERT_DEBUG( iParentStatus, CodPanic( ECodInternal ) );
+    User::RequestComplete( iParentStatus, iResult );
+    iParentStatus = NULL;
+    iState = EInit;
+    CLOG(( EHttpLoad, 2, _L("<- CHttpLoader::Done") ));
+    }
+
+// ---------------------------------------------------------
+// CHttpLoader::Continue
+// ---------------------------------------------------------
+//
+void CHttpLoader::Continue( TState aNextState )
+    {
+    CLOG(( EHttpLoad, 2, _L("-> CHttpLoader::Continue nextState(%d)"), \
+        aNextState ));
+    __ASSERT_DEBUG( !IsActive(), CodPanic( ECodInternal ) );
+
+    iState = aNextState;
+    TRequestStatus* ownStatus = &iStatus;
+    *ownStatus = KRequestPending;
+    SetActive();
+    User::RequestComplete( ownStatus, KErrNone );
+    CLOG(( EHttpLoad, 2, _L("<- CHttpLoader::Continue") ));
+    }
+
+// ---------------------------------------------------------
+// CHttpLoader::SelfComplete
+// ---------------------------------------------------------
+//
+void CHttpLoader::SelfComplete( TInt aError )
+    {
+    // This method safely handles the case when a request may be completed
+    // from more then one place.
+    // The main use is for loading (ERequest state), where
+    // there is no real external request made and the request can complete
+    // the following ways:
+    // - Transaction finished
+    // - Error (MHFRunError())
+    // - Cancel
+    // - Timeout
+    CLOG(( EHttpLoad, 2, _L("CHttpLoader::SelfComplete(%d)"), aError ));
+    if ( iStatus == KRequestPending )
+        {
+        // Request is pending, complete now.
+        CLOG(( EHttpLoad, 4, _L("  completing now") ));
+        TRequestStatus* ownStatus = &iStatus;
+        User::RequestComplete( ownStatus, aError );
+        }
+    else
+        {
+        // Request already completed.
+        // - If this second completion is error, override status.
+        // - If this second completion is success, don't override - existing
+        //   result may be error and we can't undo that.
+        CLOG(( EHttpLoad, 4, _L("  already completed") ));
+        if ( aError != KErrNone )
+            {
+            iStatus = aError;
+            }
+        }
+    }
+// -----------------------------------------------------------------------------
+// CHttpLoader::SetRequestHeaderL
+// ?implementation_description
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CHttpLoader::SetRequestHeaderL( RStringPool& aStringPool,
+                                       RHTTPHeaders& aHeaders)
+    {
+    // Set default Accept header
+    SetHeaderL( aHeaders, HTTP::EAccept, HTTP::EAnyAny );
+
+    // Some wap gateways update their database of MMS capable devices
+    // *each time* the phone accesses the gateway. If these accept header is
+    // only */* in content download, then the database will be updated so that
+    // the terminal cannot receive MMS messages. As a result, MMS notifications
+    // will not be sent to the phone and the user never receives MMS messages.
+    // Overcome: add MMS and SI content types explicitly.
+    SetHeaderL( aHeaders, HTTP::EAccept, KCodAcceptMmsHeaderValue );
+    SetHeaderL( aHeaders, HTTP::EAccept, KCodAcceptSiHeaderValue );
+    
+    if ( iMethod == HTTP::EPOST )
+        {
+        // Content type header and body for POST.
+        SetHeaderL( aHeaders, HTTP::EContentType, HTTP::ETextPlain );
+        iTrans.Request().SetBody( *this );
+        }
+
+    // Find ETag in response header
+    RStringF etag = aStringPool.StringF(HTTP::EETag, RHTTPSession::GetTable());
+    TInt fieldInd = FindHeaderField( iResponseHeaders, etag.DesC() );
+    
+    if( fieldInd != KErrNotFound )
+        // ETag is known. ETag identifies the content. Set If-Match to see
+        // that if it's changed, or a redirection goes to another url.
+        // Server will respond with 412 on error.
+        {
+        RStringF ifMatch = aStringPool.StringF(HTTP::EIfMatch, RHTTPSession::GetTable());
+        aHeaders.RemoveField( ifMatch );
+        aHeaders.SetRawFieldL( ifMatch, 
+                               *(*iResponseHeaders)[fieldInd]->FieldRawData(), 
+                               KHttpFieldSeparator );
+        }
+
+    SetRangeFieldL( aStringPool, aHeaders );
+    }
+// ---------------------------------------------------------
+// CHttpLoader::CreateTransactionL()
+// ---------------------------------------------------------
+//
+void CHttpLoader::CreateTransactionL()
+    {
+    CLOG(( EHttpLoad, 2, _L("-> CHttpLoader::CreateTransactionL") ));
+    __ASSERT_DEBUG( iUri, CodPanic( ECodInternal ) );
+    __ASSERT_DEBUG( iMethod == HTTP::EGET || iMethod == HTTP::EPOST, \
+        CodPanic( ECodInternal ) );
+
+#ifdef __TEST_COD_LOG
+    TPtrC8 uriDes( iUri->Des() );
+    CLOG(( EHttpLoad, 4, _L8("  method<%S> URI<%S>"), \
+        &StringF( iMethod ).DesC(), &uriDes ));
+#endif /* def __TEST_COD_LOG */
+
+    // Create the transaction.
+    TUriParser8 uri; 
+    User::LeaveIfError( uri.Parse( *iUri ) );
+
+    // escape the uri for characters defined in KUriEscChars
+    HBufC8* escUri = NULL;
+    TRAPD( err, escUri = EscapeUtils::SpecificEscapeEncodeL(*iUri, KUriEscChars) );
+    if( err == KErrNone )
+        {
+        // switch buffers to use the the escape-encoded version
+        delete iUri;
+        iUri = escUri;
+        User::LeaveIfError( uri.Parse( *iUri ) );
+        }
+    else
+        {
+        // if encoding function leaves, perform cleanup for safety
+        // and attempt to continue with request
+        delete escUri;  
+        }
+    iTrans = iSess->Sess().OpenTransactionL( uri, *this, StringF( iMethod ) );
+
+    // Set request headers.
+    RHTTPHeaders hdr = iTrans.Request().GetHeaderCollection();
+    
+    RStringPool strPool = iSess->Sess().StringPool();
+    SetRequestHeaderL(strPool, hdr);
+        
+    CLOG(( EHttpLoad, 2, _L("<- CHttpLoader::CreateTransactionL") ));
+    }
+
+// ---------------------------------------------------------
+// CHttpLoader::SubmitTransactionL()
+// ---------------------------------------------------------
+//
+void CHttpLoader::SubmitTransactionL()
+    {
+#ifdef __TEST_COD_LOG
+    CLOG(( EHttpLoad, 0, _L("-> CHttpLoader::SubmitTransactionL") ));
+    RHTTPRequest req = iTrans.Request();
+    TPtrC8 method( req.Method().DesC() );
+    TPtrC8 uri( req.URI().UriDes() );
+    CLOG(( EHttpLoad, 0, _L8("  method<%S> URI<%S>"), &method, &uri ));
+    LogHeaders( req.GetHeaderCollection() );
+#endif /* def __TEST_COD_LOG */
+#ifdef _DEBUG
+    HBufC* method16 = CodUtil::ConvertLC( iTrans.Request().Method().DesC() );
+    User::InfoPrint( *method16 );
+    CleanupStack::PopAndDestroy( method16 );
+#endif
+
+    if( !IsConnectionActive() )
+        {
+        User::Leave( KErrCodHttpCommsFailed );
+        }
+    CLOG(( EHttpLoad, 0, _L(" :calling RHttpTransaction.SubmitL()") ));
+    iTrans.SubmitL();
+    if( iMethod == HTTP::EPOST ) // ie, install-notify
+        {
+        if( !iINTimeout )
+            {
+            iINTimeout = CTimeout::NewL
+                         ( CActive::EPriorityStandard, TCallBack( INStaticTimeout, this ) );
+            }
+        CLOG(( EHttpLoad, 1, _L(" :starting iINTimeout with timeout of %d microsecs"), KCodINTimeout ));
+        TTimeIntervalMicroSeconds32 inTimeout = KCodINTimeout;
+        iINTimeout->After( inTimeout );
+        }
+    CLOG(( EHttpLoad, 0, _L("<- CHttpLoader::SubmitTransactionL") ));
+    }
+
+// ---------------------------------------------------------
+// CHttpLoader::CompleteTransaction()
+// ---------------------------------------------------------
+//
+void CHttpLoader::CompleteTransaction( TInt aError )
+    {
+    CLOG(( EHttpLoad, 2, _L("-> CHttpLoader::CompleteTransaction(%d)"), \
+        aError ));
+    __ASSERT_DEBUG( iState == ERequest, CodPanic( ECodOffState ) );
+    iTrans.Close();
+    iResult = aError;
+    SelfComplete( iResult );
+    CLOG(( EHttpLoad, 2, _L("<- CHttpLoader::CompleteTransaction") ));
+    }
+
+// ---------------------------------------------------------
+// CHttpLoader::RestartTransaction()
+// ---------------------------------------------------------
+//
+void CHttpLoader::RestartTransaction()
+    {
+    CLOG(( EHttpLoad, 2, _L("-> CHttpLoader::RestartTransaction")));
+    __ASSERT_DEBUG( iState == ERequest, CodPanic( ECodOffState ) );
+    
+    iState = EStart;
+    CompleteTransaction(KErrNone);
+    
+    CLOG(( EHttpLoad, 2, _L("<- CHttpLoader::CompleteTransaction") ));
+    }
+
+
+// ---------------------------------------------------------
+// CHttpLoader::AcceptRangesSupported()
+// ---------------------------------------------------------
+//
+TBool CHttpLoader::AcceptRangesSupported()
+	{
+    RStringF range = iSess->Sess().StringPool().StringF(HTTP::EAcceptRanges, RHTTPSession::GetTable());
+    THTTPHdrVal value;
+    
+    TInt index = FindHeaderField(iResponseHeaders, range.DesC());
+    
+    if( index  != KErrNotFound ) 
+        {
+        if( !(*iResponseHeaders)[index]->FieldRawData()->Compare( KAcceptRangeHeader() ) )
+            {
+            return ETrue;
+            }
+        }
+        
+    return EFalse;    
+	}
+
+// ---------------------------------------------------------
+// CHttpLoader::HandleResponseHeadersL()
+// ---------------------------------------------------------
+//
+void CHttpLoader::HandleResponseHeadersL( RHTTPResponse aResponse )
+    {
+    CLOG(( EHttpLoad, 0, _L("-> CHttpLoader::HandleResponseHeadersL") ));
+    TInt httpCode = aResponse.StatusCode();
+#ifdef __TEST_COD_LOG
+    CLOG(( EHttpLoad, 0, _L8("  HttpStatus(%d) <%S>"), \
+        httpCode, &(aResponse.StatusText().DesC()) ));
+    LogHeaders( aResponse.GetHeaderCollection() );
+#endif /* def __TEST_COD_LOG */
+
+    if ( HTTPStatus::IsInformational( httpCode ) )
+        {
+        // 1xx
+        // Informational messages. Do nothing.
+        }
+    else if ( httpCode == HTTPStatus::EOk ||
+              httpCode == HTTPStatus::ENonAuthoritativeInfo ||
+              httpCode == HTTPStatus::EPartialContent
+            )
+        {
+        // 200 OK
+        // 203 Non-Authoritative Information
+        iResult = KErrNone;
+        if ( iMethod == HTTP::EGET )
+            {
+            // Successful GET. Get a saver.
+            __ASSERT_DEBUG( iSaverFactory, CodPanic( ECodInternal ) );
+
+            if(!iSaver)
+                {
+                iSaver = iSaverFactory->CreateSaverL( GetContentTypeL( aResponse.GetHeaderCollection() ) );
+                iSaver->SetSourceUriL( GetSourceUriL( iTrans ) );
+                }
+            if(httpCode != HTTPStatus::EPartialContent)
+                {
+                if( !iProgress->CurrentValue() )
+                    {
+                    iSaver->ResetL();
+                    iProgress->SetAmountL(1024);    
+                    }                
+                }
+            CheckRealDRMContentTypeL();
+           	iCodEng->SetPausable(AcceptRangesSupported() && iCodEng->Pausable());
+
+            // If we know the size, check it is valid and preallocate buffer
+            // for content.
+            if ( aResponse.HasBody() )
+                {
+                TInt dataSize = aResponse.Body()->OverallDataSize();
+                if ( dataSize >= 0 )
+                    {
+                    // Content size is known. Check if fits.
+                    User::LeaveIfError( iSaver->CheckMaxSize( dataSize ) );
+                    }
+                }
+                iCodEng->SetResumePDAvailable();
+            }
+        else
+            {
+            // Successful POST.
+            // Do nothing.
+            }
+        }
+    else if ( HTTPStatus::IsSuccessful( httpCode ) )
+        {
+        // 2xx
+        // Success codes without an usable body.
+        // For GET, it is a failure; for POST it's OK
+        iResult = (iMethod == HTTP::EGET) ? KErrCodHttpNoResponse : KErrNone;
+        }
+    // 3xx codes handled by redirect filter.
+    else if ( httpCode == HTTPStatus::EUnauthorized ||
+              httpCode == HTTPStatus::EProxyAuthenticationRequired )
+        {
+        // 401 Unauthorized
+        // 407 Proxy authentication required
+        iResult = KErrCodHttpAuthFailed;
+        }
+    else if ( httpCode == HTTPStatus::ENotFound ||
+              httpCode == HTTPStatus::EGone )
+        {
+        // 404 Not found
+        // 410 Gone
+        iResult = KErrCodHttpBadUrl;
+        
+        // Cancel the download if bad url.
+        // Set pausable status to false.
+        iCodEng->SetPausable( EFalse );
+        }
+        
+    else if ( httpCode == HTTPStatus::ERequestedRangeNotSatisfiable )
+        {
+        //416 Requested Range Not Satisfiable. Download has to be cancelled.
+        iResult = KErrCodHttpRequestedRangeNotSatisfiable;
+        }
+    else if( httpCode == HTTPStatus::EPreconditionFailed )        
+        {
+        // Re init the download
+        if(iSaver)
+            {
+            iSaver->ResetL();
+            iProgress->SetAmountL(0);
+            }
+        CompleteTransaction( KErrCodHttpPreconditionFailed );
+        }
+    else if ( HTTPStatus::IsClientError( httpCode ) )
+        {
+        // 4xx
+        iResult = KErrCodHttpUnavailable;
+        }
+    else if ( httpCode == HTTPStatus::EHTTPVersionNotSupported )
+        {
+        // 505 HTTP Version Not Supported
+        // Retry with lower HTTP version if we can.
+        iResult = VersionRetryL() ? KErrNone : KErrCodHttpUnavailable;
+        }
+    else if ( HTTPStatus::IsServerError( httpCode ) )
+        {
+        // 5xx
+        // HTTP/1.0 servers may return other 5xx error codes for HTTP/1.1
+        // requests. So the same treatment  is given for all 5xx errors
+        // (version retry) - it's worth a try.
+        iResult = VersionRetryL() ? KErrNone : KErrCodHttpServerError;
+        }
+    else
+        {
+        // Everything else.
+        iResult = KErrCodHttpBadResponse;
+        }
+    CLOG(( EHttpLoad, 0, _L("<- CHttpLoader::HandleResponseHeadersL") ));
+    }
+
+// ---------------------------------------------------------
+// CHttpLoader::VersionRetryL()
+// ---------------------------------------------------------
+//
+TBool CHttpLoader::VersionRetryL()
+    {
+    CLOG(( EHttpLoad, 2, \
+        _L8("-> CHttpLoader::VersionRetryL iHttpVersion <%S>"), \
+        &(StringF( iHttpVersion ).DesC() ) ));
+
+    // We should be in ERequest state, with the request outstanding.
+    __ASSERT_DEBUG( iState == ERequest, CodPanic( ECodInternal ) );
+    __ASSERT_DEBUG( iStatus == KRequestPending, CodPanic( ECodInternal ) );
+    __ASSERT_DEBUG( IsActive(), CodPanic( ECodInternal ) );
+
+    TBool retryDone( EFalse );
+    if ( iHttpVersion == HTTP::EHttp11 )
+        {
+        // Currently using HTTP/1.1. Cancel transaction and resubmit it using
+        // HTTP/1.0.
+        iTrans.Cancel();
+        iSess->Sess().ConnectionInfo().SetPropertyL
+            (
+            StringF( HTTP::EHTTPVersion ),
+            THTTPHdrVal( StringF( HTTP::EHttp10 ) )
+            );
+        iHttpVersion = HTTP::EHttp10;
+        SubmitTransactionL();
+        retryDone = ETrue;
+        }
+    CLOG(( EHttpLoad, 2, _L("<- CHttpLoader::VersionRetryL return(0x%x)"), \
+        retryDone ));
+    return retryDone;
+    }
+
+// ---------------------------------------------------------
+// CHttpLoader::UseProxyL()
+// ---------------------------------------------------------
+//
+TBool CHttpLoader::UseProxyL()
+    {
+    CLOG(( EHttpLoad, 2, _L("-> CHttpLoader::UseProxyL iProxySet(0x%x)"), \
+        iProxySet ));
+
+    // We should be in ERequest state, with the request outstanding.
+    __ASSERT_DEBUG( iState == ERequest, CodPanic( ECodInternal ) );
+    __ASSERT_DEBUG( iStatus == KRequestPending, CodPanic( ECodInternal ) );
+    __ASSERT_DEBUG( IsActive(), CodPanic( ECodInternal ) );
+    __ASSERT_DEBUG( iTrans.Response().StatusCode() == HTTPStatus::EUseProxy, \
+        CodPanic( ECodInvalidArguments ) );
+
+    // First check if we already have a proxy address set. If yes, do not set
+    // another.
+    if( !iProxySet )
+        {
+        TBool proxySet( EFalse );   // Set by somebody else (?).
+        RStringF proxyUsage = StringF( HTTP::EProxyUsage );
+        RStringF useProxy = StringF( HTTP::EUseProxy );
+        RHTTPConnectionInfo connInfo = iSess->Sess().ConnectionInfo();
+        THTTPHdrVal val;
+        if( connInfo.Property( proxyUsage, val ) )
+            {
+            if( val.Type() != THTTPHdrVal::KStrFVal )
+                {
+                User::Leave( KErrCodHttpBadResponse );
+                }
+            if( val.StrF() == useProxy )
+                {
+                proxySet = ETrue;
+                CLOG(( EHttpLoad, 2, _L("  proxy already set") ));
+                }
+            }
+        if( !proxySet )
+            {
+            // No proxy is currently set. Get the proxy address to set, from
+            // the Location header field.
+            RHTTPHeaders headers = iTrans.Response().GetHeaderCollection();
+            if( !headers.GetField( StringF( HTTP::ELocation ), 0, val ) )
+                {
+                if( val.Type() != THTTPHdrVal::KStrFVal )
+                    {
+                    User::Leave( KErrCodHttpBadResponse );
+                    }
+                // Cancel the transaction and resubmit after the proxy was set.
+                CLOG(( EHttpLoad, 2, _L8("  setting proxy <%S>"), \
+                    &(val.StrF().DesC()) ));
+                iTrans.Cancel();
+                connInfo.SetPropertyL( StringF( HTTP::EProxyAddress ), val );
+                connInfo.SetPropertyL( proxyUsage, THTTPHdrVal( useProxy ) );
+                SubmitTransactionL();
+                iProxySet = ETrue;
+                }
+            }
+        }
+    CLOG(( EHttpLoad, 2, \
+        _L("<- CHttpLoader::UseProxyL return iProxySet(0x%x)"), iProxySet ));
+    return iProxySet;
+    }
+
+// ---------------------------------------------------------
+// CHttpLoader::SetupSessionL()
+// ---------------------------------------------------------
+//
+void CHttpLoader::SetupSessionL()
+    {
+    CLOG(( EHttpLoad, 2, _L("-> CHttpLoader::SetupSessionL") ));
+    // Set our Socket Server handle and Connection as session properties.
+    iSess->Sess().ConnectionInfo().SetPropertyL
+        (
+        StringF( HTTP::EHttpSocketServ ),
+        THTTPHdrVal( iConn.SockServ().Handle() )
+        );
+    iSess->Sess().ConnectionInfo().SetPropertyL
+        (
+        StringF( HTTP::EHttpSocketConnection ),
+        THTTPHdrVal( REINTERPRET_CAST( TInt, &iConn.Conn() ) )
+        );
+
+    // Set the disconnect notification 
+    iSess->Sess().ConnectionInfo().SetPropertyL
+        (
+        iSess->Sess().StringPool().StringF( HTTP::ENotifyOnDisconnect, RHTTPSession::GetTable() ), 
+        iSess->Sess().StringPool().StringF( HTTP::EEnableDisconnectNotification, RHTTPSession::GetTable() )
+        ); 
+
+    CLOG(( EHttpLoad, 4, _L("  Install UAProf filter...") ));
+    // Install UAProf filter.
+    CHttpUAProfFilterInterface::InstallFilterL( iSess->Sess() );
+
+    CLOG(( EHttpLoad, 4, _L("  Install Cookie filter...") ));
+    // Install cookie filter.
+    CHttpCookieFilter::InstallFilterL( iSess->Sess() );
+
+    CLOG(( EHttpLoad, 4, _L("  Install Auth filter...") ));
+    // Install authentication filter.
+    InstallAuthenticationL( iSess->Sess() );
+
+    CLOG(( EHttpLoad, 4, _L("  Install Deflate filter...") ));
+    // Install deflate Filter.
+    CHttpDeflateFilter::InstallFilterL( iSess->Sess() );
+
+    CLOG(( EHttpLoad, 2, _L("<- CHttpLoader::SetupSessionL") ));
+    }
+
+// ---------------------------------------------------------
+// CHttpLoader::StartTimeout()
+// ---------------------------------------------------------
+//
+void CHttpLoader::StartTimeout()
+    {
+    CLOG(( EHttpLoad, 2, _L("-> CHttpLoader::StartTimeout") ));
+    __ASSERT_DEBUG( iState == ERequest, CodPanic( ECodOffState ) );
+    __ASSERT_DEBUG( iTimeout, CodPanic( ECodInternal ) );
+    TTimeIntervalMicroSeconds32 timeout = 
+        iMethod == HTTP::EGET ? KCodGetTimeout : KCodPostTimeout;
+    iTimeout->Cancel();         // Cancel pending (if any).
+    iTimeout->After( timeout ); // Start over.
+    CLOG(( EHttpLoad, 2, _L("<- CHttpLoader::StartTimeout (%d microsecs)"), \
+        timeout.Int() ));
+    }
+
+// ---------------------------------------------------------
+// CHttpLoader::Timeout()
+// ---------------------------------------------------------
+//
+void CHttpLoader::Timeout()
+    {
+    CLOG(( EHttpLoad, 2, _L("-> CHttpLoader::Timeout iRetry(%d)"), iRetry ));
+    __ASSERT_DEBUG( iState == ERequest, CodPanic( ECodOffState ) );
+    if ( --iRetry > 0 )
+        {
+        CompleteTransaction( KErrNone );    // Close (abandon) transaction.
+        iState = EOpen;                     // To RequestL() by self-complete.
+        }
+    else
+        {
+		if (iCodLoadObserver)
+			{
+			iCodLoadObserver->SetConnError( KErrTimedOut);
+			}
+        CompleteTransaction( KErrTimedOut );
+        }
+    CLOG(( EHttpLoad, 2, _L("<- CHttpLoader::Timeout") ));
+    }
+
+// ---------------------------------------------------------
+// CHttpLoader::INTimeout()
+// ---------------------------------------------------------
+//
+void CHttpLoader::INTimeout()
+    {
+    CLOG(( EHttpLoad, 2, _L("-> CHttpLoader::INTimeout") ));
+    __ASSERT_DEBUG( iState == ERequest, CodPanic( ECodOffState ) );
+    iSuppressErrors = ETrue;    // release content to user 
+    if( !IsConnectionActive() )
+        {
+        iSuppressErrors = EFalse;         // do not release content
+        iResult = KErrCodHttpCommsFailed; // set error code
+        }
+    CLOG(( EHttpLoad, 2, _L(" :iSuppressErrors = %d"), iSuppressErrors ));
+    CLOG(( EHttpLoad, 2, _L(" :iResult = %d"), iResult ));
+    CLOG(( EHttpLoad, 2, _L("<- CHttpLoader::INTimeout") ));
+    }
+
+// ---------------------------------------------------------
+// CHttpLoader::IncProgressL()
+// ---------------------------------------------------------
+//
+void CHttpLoader::IncProgressL( TInt aSize )
+    {
+    CLOG(( EHttpLoad, 2, _L("-> CHttpLoader::IncProgressL(%d)"), aSize ));
+    if ( iProgress )
+        {
+        iProgress->IncrementL( aSize );
+        }
+    CLOG(( EHttpLoad, 2, _L("<- CHttpLoader::IncProgressL") ));
+    }
+
+// ---------------------------------------------------------
+// CHttpLoader::SetHeaderL()
+// ---------------------------------------------------------
+//
+void CHttpLoader::SetHeaderL
+( RHTTPHeaders aHeaders, HTTP::TStrings aHdrField, const TDesC8& aHdrValue )
+    {
+    RStringF valStr = iSess->Sess().StringPool().OpenFStringL( aHdrValue );
+    CleanupClosePushL<RStringF>( valStr );
+    SetHeaderL( aHeaders, aHdrField, valStr );
+    CleanupStack::PopAndDestroy();  // close valStr
+    }
+
+// ---------------------------------------------------------
+// CHttpLoader::SetHeaderL()
+// ---------------------------------------------------------
+//
+void CHttpLoader::SetHeaderL
+( RHTTPHeaders aHeaders, HTTP::TStrings aHdrField, HTTP::TStrings aHdrValue )
+    {
+    SetHeaderL( aHeaders, aHdrField, StringF( aHdrValue ) );
+    }
+
+// ---------------------------------------------------------
+// CHttpLoader::SetHeaderL()
+// ---------------------------------------------------------
+//
+void CHttpLoader::SetHeaderL
+( RHTTPHeaders aHeaders, HTTP::TStrings aHdrField, const RStringF aHdrValue )
+    {
+    CLOG(( EHttpLoad, 2, _L8("CHttpLoader::SetHeaderL <%S> <%S>"), \
+        &StringF( aHdrField ).DesC(), &aHdrValue.DesC() ));
+    THTTPHdrVal val( aHdrValue );
+    aHeaders.SetFieldL( StringF( aHdrField ), val );
+    }
+
+// ---------------------------------------------------------
+// CHttpLoader::GetContentTypeL()
+// ---------------------------------------------------------
+//
+const TDesC8& CHttpLoader::GetContentTypeL( RHTTPHeaders aHeaders )
+    {
+    THTTPHdrVal hdrVal;
+    User::LeaveIfError
+        ( aHeaders.GetField( StringF( HTTP::EContentType ), 0, hdrVal ) );
+    if( hdrVal.Type() != THTTPHdrVal::KStrFVal )
+        {
+        User::Leave( KErrCodHttpBadResponse );
+        }
+    return hdrVal.StrF().DesC();
+    }
+
+// ---------------------------------------------------------
+// CHttpLoader::GetContentTypeL()
+// ---------------------------------------------------------
+//
+const TDesC8& CHttpLoader::GetContentTypeL()
+    {
+    _LIT8(KContentType, "Content-Type");
+
+    THTTPHdrVal value;
+    
+    TInt index = FindHeaderField(iResponseHeaders, KContentType);
+    
+    if( index  != KErrNotFound ) 
+        {
+        HBufC8 *ptr = (*iResponseHeaders)[index]->FieldRawData();
+        return *ptr;
+        }
+
+    return KNullDesC8;
+    }
+
+// ---------------------------------------------------------
+// CHttpLoader::GetSourceUriL()
+// ---------------------------------------------------------
+//
+const TDesC8& CHttpLoader::GetSourceUriL( RHTTPTransaction aTransaction )
+    {
+    // TODO if redirected URI exists, how do we get it?
+    // For the moment request URI is used.
+    return aTransaction.Request().URI().UriDes();
+    }
+
+// ---------------------------------------------------------
+// CHttpLoader::StaticTimeout()
+// ---------------------------------------------------------
+//
+TInt CHttpLoader::StaticTimeout( TAny* aPtr )
+    {
+    CLOG(( EHttpLoad, 2, _L("-> CHttpLoader::StaticTimeout") ));
+    STATIC_CAST( CHttpLoader*, aPtr )->Timeout();
+    CLOG(( EHttpLoad, 2, _L("<- CHttpLoader::StaticTimeout") ));
+    return EFalse;
+    }
+
+// ---------------------------------------------------------
+// CHttpLoader::INStaticTimeout()
+// ---------------------------------------------------------
+//
+TInt CHttpLoader::INStaticTimeout( TAny* aPtr )
+    {
+    CLOG(( EHttpLoad, 2, _L("-> CHttpLoader::INStaticTimeout") ));
+    STATIC_CAST( CHttpLoader*, aPtr )->INTimeout();
+    CLOG(( EHttpLoad, 2, _L("<- CHttpLoader::INStaticTimeout") ));
+    return EFalse;
+    }
+
+
+// ---------------------------------------------------------
+// CHttpLoader::IsConnectionActive()
+// ---------------------------------------------------------
+//
+TBool CHttpLoader::IsConnectionActive()
+    {
+    CLOG(( EHttpLoad, 2, _L("-> CHttpLoader::IsConnectionActive") ));
+
+    THTTPHdrVal val;
+    TBool active( ETrue );
+    TBool hasProp = iSess->Sess().ConnectionInfo().Property
+        ( StringF( HTTP::EHttpSocketConnection ), val );
+    if( hasProp && val.Type() == THTTPHdrVal::KTIntVal)
+        {
+        active = ( val.Int() != NULL );
+        CLOG(( EHttpLoad, 0, _L(" :RConnection found = %d"), active ));
+        }    
+
+    if( active ) // confirm with second level check
+        {
+        TUint32 iap;
+        active = iConn.IsConnected( iap );
+        CLOG(( EHttpLoad, 3, _L(" :CConnection.IsConnection() = %d"), active ));
+        }
+    CLOG(( EHttpLoad, 2, _L("<- CHttpLoader::IsConnectionActive") ));
+    return active;
+    }
+    
+// -----------------------------------------------------------------------------
+// CHttpDownload::StoreResponseHeaderL
+// ?implementation_description
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CHttpLoader::StoreResponseHeaderL()
+	{
+
+    TPtrC8 rawData;
+    RStringPool strPool = iSess->Sess().StringPool();
+
+    RHTTPHeaders headers( iTrans.Response().GetHeaderCollection() );
+    THTTPHdrFieldIter it = headers.Fields();
+
+    // forget the previous headers
+    iResponseHeaders->ResetAndDestroy();
+    
+    while ( !it.AtEnd() )
+        {
+        RStringTokenF fieldName = it();
+        RStringF fieldNameStr = strPool.StringF (fieldName );
+
+        headers.GetRawField( fieldNameStr, rawData );
+
+        CHeaderField* field = CHeaderField::NewL( &fieldNameStr.DesC(), &rawData );
+        CleanupStack::PushL( field );
+
+        iResponseHeaders->AppendL( field );
+
+        CleanupStack::Pop( field );
+
+        ++it;
+        }    
+
+    //ParseContentTypeL( strPool );
+
+    RStringF length = strPool.StringF(HTTP::EContentLength,RHTTPSession::GetTable());
+    RStringF date = strPool.StringF(HTTP::EDate,RHTTPSession::GetTable());
+    RStringF expires = strPool.StringF(HTTP::EExpires,RHTTPSession::GetTable());
+    RStringF maxAge = strPool.StringF(HTTP::EMaxAge,RHTTPSession::GetTable());
+    RStringF cacheControl = strPool.StringF(HTTP::ECacheControl,RHTTPSession::GetTable());
+    RStringF acceptRanges = strPool.StringF(HTTP::EAcceptRanges,RHTTPSession::GetTable());
+    
+    THTTPHdrVal value;
+    /*
+    if( !headers.GetField( length, 0, value ) )
+        {
+        if( iStorage->Length() == KDefaultContentLength )
+            // content size is
+            {
+            iStorage->SetLength( value );
+            }
+        }
+             
+    CheckRealDRMContentTypeL();
+    if( !iDrmContentLengthValid )
+        // Content was original encoded -> we don't know the actual content size.
+        {
+        iStorage->SetLength( KDefaultContentLength );
+        }*/ 
+        
+		CheckRealDRMContentTypeL();
+		
+    iMaxAge = 0;
+    TInt parts( 0 );
+    // this leave is trapped because we can still go on
+    TRAPD( err, parts = headers.FieldPartsL( cacheControl ) );
+
+    if( !err )
+        // try to find max-age in Cache-control field
+        {
+        for( TInt i = 0; i < parts; ++i )
+            {
+            RStringF directive;
+            THTTPHdrVal hdrVal;
+            TInt err;
+
+            // Get the cache-control from the headers
+            // initialise the fieldname
+            headers.GetField( cacheControl, i, hdrVal );
+
+            if((hdrVal.Type() == THTTPHdrVal::KStrVal) || (hdrVal.Type() == THTTPHdrVal::KStrFVal))
+                {
+                RStringF cacheDir = hdrVal.StrF();
+
+                TInt endPos;
+                _LIT8(KFind, "=");
+
+                endPos = cacheDir.DesC().Find( KFind );
+                if( endPos != -1 )
+                    {
+                    TRAP(err, directive = strPool.OpenFStringL(cacheDir.DesC().Left(endPos)));
+                    if( !err )
+                        {
+                        if( directive == maxAge )
+                            {
+                            TInt valueInt( 0 );
+                            TLex8 value( cacheDir.DesC().Right(cacheDir.DesC().Length() - endPos - 1) );
+
+                            value.Val( valueInt );
+                            iMaxAge = valueInt;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+    if( !headers.GetField( expires, 0, value ) )
+        {
+        iExpires = value;
+        }
+    else
+        {
+        iExpires.SetYear( 0 );
+        }
+
+    if( !headers.GetField( date, 0, value ) )
+        {
+        iDate = value;
+        }
+    else
+        {
+        iDate.SetYear( 0 );
+        }
+	}
+
+
+	
+void CHttpLoader::LoadHeadersL( RFile& aFile)
+	{
+    TInt headers;
+    READ_INT_L( aFile, headers );
+
+    iResponseHeaders->ResetAndDestroy();
+
+    for( TInt i = 0; i < headers; ++i )
+        {
+        CHeaderField* field = CHeaderField::NewL();
+        CleanupStack::PushL( field );
+
+        field->LoadHeaderInfoL( aFile );
+        iResponseHeaders->AppendL( field );
+
+        CleanupStack::Pop( field );
+        }	
+	}
+	
+void CHttpLoader::SetRangeFieldL( RStringPool& aStringPool,
+                                    RHTTPHeaders& aHeaders )
+    {
+    
+    if(!iSaver)
+    {
+        return;
+    }
+    
+    TInt size (iSaver->DownloadedFileSize());
+
+    if( size <= 0 )
+        {
+		// no bytes have been downloaded yet
+        return;
+        }
+
+    RStringF range = aStringPool.StringF(HTTP::ERange, RHTTPSession::GetTable());
+
+    aHeaders.RemoveField( range );
+
+    TBuf8<48> rawData;
+
+    rawData.Format( _L8("bytes=%d-"), size);
+
+    aHeaders.SetRawFieldL( range, rawData, KHttpFieldSeparator );
+    }
+    
+// -----------------------------------------------------------------------------
+// CHttpLoader::FindHeaderField
+// ?implementation_description
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TInt CHttpLoader::FindHeaderField( CArrayPtrFlat<CHeaderField>* aHeaders,
+                                     const TDesC8& aFieldName ) const
+    {
+    for( TInt index = 0; index < aHeaders->Count(); ++index )
+        {
+        if( *(*aHeaders)[index]->FieldName() == aFieldName )
+            {
+            return index;
+            }
+        }
+
+    return KErrNotFound;
+    }
+	
+void CHttpLoader::CheckRealDRMContentTypeL()
+    {
+    iPausableDRM = ETrue;
+    iDrmContentLengthValid = ETrue;
+    
+    TInt index = FindHeaderField( iResponseHeaders, KDRMOldContentType );
+    if( index != KErrNotFound )
+        // this is an old DRM protected content
+        // This transaction cannot be paused.
+        {
+        if( !(*iResponseHeaders)[index]->FieldRawData()->Compare( KDrmMessageMimeType() ) )
+            {
+            iPausableDRM = EFalse;
+            }
+        }
+        
+    UpdatePausableL();
+    }	
+
+// -----------------------------------------------------------------------------
+// CHttpLoader::UpdatePausableL
+// ?implementation_description
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CHttpLoader::UpdatePausableL()
+    {
+    TBool pausable( ETrue );
+
+    if( !iPausableDRM )
+        {
+        pausable = EFalse;
+        }
+        
+    if( iMethod == EMethodPOST )
+        {
+        pausable = EFalse;
+        }
+
+    if( pausable != iCodEng->Pausable() )
+        {
+        iCodEng->SetPausable( pausable );
+        
+        //TODO : Shud the change in pause behavior shud be notified. ??
+        // inform client about change
+        //TriggerEvent( iPausable ? EHttpDlPausable : EHttpDlNonPausable );
+
+        //TRAP_IGNORE(StoreDownloadInfoL() );
+        iCodEng->StoreSubInfoFileL(iResponseHeaders, iCodEng->Data().ActiveDownload() );
+        }
+    }    
+
+// ---------------------------------------------------------
+// CHttpLoader::LogHeaders()
+// ---------------------------------------------------------
+//
+void CHttpLoader::LogHeaders( RHTTPHeaders LOG_ONLY( aHeaders ) )
+    {
+#ifdef __TEST_COD_LOG
+    _LIT(KDateFormat,"%D%M%Y%/0%1%/1%2%/2%3%/3 %:0%H%:1%T%:2%S.%C%:3");
+
+    CLOG(( EHttpLoad, 1, _L("Headers:") ));
+
+    TInt i;
+    TInt fieldParts;
+    RStringPool strP = iTrans.Session().StringPool();
+    THTTPHdrFieldIter it = aHeaders.Fields();
+
+    while ( !it.AtEnd() )
+        {
+        RStringTokenF fieldName = it();
+        RStringF fieldNameStr = strP.StringF (fieldName );
+        THTTPHdrVal fieldVal;
+        fieldParts = 0; // For the case if next the call fails.
+        TRAP_IGNORE( fieldParts =  aHeaders.FieldPartsL( fieldNameStr ) );
+        for ( i = 0; i < fieldParts; i++ )
+            {
+            if ( aHeaders.GetField( fieldNameStr, i, fieldVal ) == KErrNone )
+                {
+                const TDesC8& fieldNameDesC = fieldNameStr.DesC();
+                switch ( fieldVal.Type() )
+                    {
+                    case THTTPHdrVal::KTIntVal:
+                        {
+                        CLOG(( EHttpLoad, 1, _L8("  <%S> (%d)"), \
+                            &fieldNameDesC, fieldVal.Int() ));
+                        break;
+                        }
+
+                    case THTTPHdrVal::KStrFVal:
+                        {
+                        RStringF fieldValStr = strP.StringF( fieldVal.StrF() );
+                        const TDesC8& fieldValDesC = fieldValStr.DesC();
+                        CLOG(( EHttpLoad, 1, _L8("  <%S> <%S>"), \
+                            &fieldNameDesC, &fieldValDesC ));
+                        }
+                        break;
+
+                    case THTTPHdrVal::KStrVal:
+                        {
+                        RString fieldValStr = strP.String( fieldVal.Str() );
+                        const TDesC8& fieldValDesC = fieldValStr.DesC();
+                        CLOG(( EHttpLoad, 1, _L8("  <%S> <%S>"), \
+                            &fieldNameDesC, &fieldValDesC ));
+                        }
+                        break;
+
+                    case THTTPHdrVal::KDateVal:
+                        {
+                        TDateTime date = fieldVal.DateTime();
+                        TBuf<40> dateTimeString;
+                        TTime t( date );
+                        TRAP_IGNORE\
+                            ( t.FormatL( dateTimeString, KDateFormat ) );
+                        TBuf8<40> dateTimeString8;
+                        dateTimeString8.Copy( dateTimeString );
+                        CLOG(( EHttpLoad, 1, _L8("  <%S> <%S>"), \
+                            &fieldNameDesC, &dateTimeString8 ));
+                        } 
+                        break;
+
+                    default:
+                        CLOG(( EHttpLoad, 1, \
+                            _L8("  <%S> unrecognised value type(%d)"), \
+                            &fieldNameDesC, fieldVal.Type() ));
+                        break;
+                    }
+
+                // Display realm for WWW-Authenticate header.
+                RStringF wwwAuth = strP.StringF
+                    ( HTTP::EWWWAuthenticate, RHTTPSession::GetTable() );
+                if ( fieldNameStr == wwwAuth )
+                    {
+                    // check the auth scheme is 'basic'
+                    RStringF basic = strP.StringF
+                        ( HTTP::EBasic, RHTTPSession::GetTable() );
+                    RStringF realm = strP.StringF
+                        ( HTTP::ERealm, RHTTPSession::GetTable() );
+                    THTTPHdrVal realmVal;
+                    if ( ( fieldVal.StrF() == basic ) && 
+                        ( !aHeaders.GetParam( wwwAuth, realm, realmVal ) ) )
+                        {
+                        RString realmValStr = strP.String( realmVal.Str() );
+                        const TDesC8& realmValDesC = realmValStr.DesC();
+                        CLOG(( EHttpLoad, 1, _L8("    Realm<%S>"), \
+                            &realmValDesC ));
+                        }
+                    }
+                }
+            }
+        ++it;
+        }
+#endif /* def __TEST_COD_LOG */
+    }
+
+
+// -----------------------------------------------------------------------------
+// CHttpLoader::RedirectedPermanentlyL
+// -----------------------------------------------------------------------------
+//
+void CHttpLoader::RedirectedPermanentlyL( const TDesC8& aNewUrl )
+    {
+    CLOG(( EHttpLoad, 0, _L("CHttpLoader::RedirectedPermanentlyL => NewUrl(%S)"), \
+                                                            &aNewUrl ));
+
+	// Use the redirected Url
+	ReallocateStringL( iUri, aNewUrl, KMaxUrlLength );
+	
+	// There has already been a temporary redirection
+    // This permanent is not used on next submitted request 
+	if (!iRedirect)
+		{
+		HBufC* newUrl = CodUtil::ConvertLC( aNewUrl );
+		iCodEng->SetUrlL( *newUrl );
+		
+		CleanupStack::PopAndDestroy( newUrl );
+		}
+    }
+
+// -----------------------------------------------------------------------------
+// CHttpLoader::RedirectedTemporaryL
+// -----------------------------------------------------------------------------
+//
+void CHttpLoader::RedirectedTemporaryL( const TDesC8& aNewUrl )
+    {
+    CLOG(( EHttpLoad, 0, _L("CHttpLoader::RedirectedTemporaryL => NewUrl(%S)"), \
+                                                            &aNewUrl ));
+
+	// Make it TRUE so that any permanent redirections after
+	// this are not saved
+	iRedirect = ETrue;
+	ReallocateStringL( iUri, aNewUrl, KMaxUrlLength );
+    }
+
+// -----------------------------------------------------------------------------
+// CHttpLoader::ResponseHeaders
+// -----------------------------------------------------------------------------
+//
+CArrayPtrFlat<CHeaderField>* CHttpLoader::ResponseHeaders()
+	{
+	return iResponseHeaders;
+	}