IMPSengine/ImpsDataChannel/src/HttpTransportAdapter.cpp
changeset 0 094583676ce7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/IMPSengine/ImpsDataChannel/src/HttpTransportAdapter.cpp	Thu Dec 17 08:41:52 2009 +0200
@@ -0,0 +1,1009 @@
+/*
+* Copyright (c) 2003 Nokia Corporation and/or its subsidiary(-ies). 
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "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: Adapter for Http transport.
+*
+*
+*/
+
+
+// INCLUDE FILES
+#include <in_iface.h>
+#include <impserrors.h>
+#include <msgconnmanagerapi.h>
+#include "HttpTransportAdapter.h"
+#include "ImpsHttpTransaction.h"
+#ifdef _DEBUG
+#include "flogger.h"
+#endif
+
+// ================= MEMBER FUNCTIONS =======================
+//
+
+// ----------------------------------------------------------
+// CHttpTransportAdapter::CHttpTransportAdapter
+//
+// ----------------------------------------------------------
+//
+CHttpTransportAdapter::CHttpTransportAdapter( MImpsDataReceiver& aReceiver,
+                                              MMsgConnManager& aConnManager ) :
+        iSuspend( EFalse ),
+        iSessionClosed( ETrue ),
+        iReceiver( aReceiver ),
+        iConnManager( aConnManager )
+    {
+    }
+
+// ----------------------------------------------------------
+// CHttpTransportAdapter::NewL
+//
+// ----------------------------------------------------------
+//
+CHttpTransportAdapter* CHttpTransportAdapter::NewL( MImpsDataReceiver& aReceiver,
+                                                    MMsgConnManager& aConnManager,
+                                                    const TDesC8& aMimeType )
+    {
+    CHttpTransportAdapter* self = new ( ELeave ) CHttpTransportAdapter( aReceiver, aConnManager );
+    CleanupStack::PushL( self );
+    self->ConstructL( aMimeType );
+    CleanupStack::Pop();  //self
+    return self;
+    }
+
+// ----------------------------------------------------------
+// CHttpTransportAdapter::ConstructL
+//
+// ----------------------------------------------------------
+//
+void CHttpTransportAdapter::ConstructL( const TDesC8& aMimeType )
+    {
+#ifdef _DEBUG
+    DeleteLogFilesL();
+#endif
+    SetMimeTypeL( aMimeType );
+    }
+
+// ----------------------------------------------------
+// CHttpTransportAdapter::~CHttpTransportAdapter()
+// Destructor
+// ----------------------------------------------------
+//
+CHttpTransportAdapter::~CHttpTransportAdapter()
+    {
+#ifdef _DEBUG
+    WriteToLog( _L8( "CHttpTransportAdapter::~CHttpTransportAdapter(). Destructor called." ) );
+#endif
+    iHttpSession.Close();
+    iSessionClosed = ETrue;
+    iTransactionQueue.ResetAndDestroy();
+    iTransactionQueue.Close();
+    delete iUrlBuffer;
+    delete iProxyBuffer;
+    delete iMimeBuffer;
+#ifdef _DEBUG
+    WriteToLog( _L8( "  Destructor ended." ) );
+#endif
+    }
+
+// ----------------------------------------------------
+// CHttpTransportAdapter::InitialiseSessionL
+//
+// ----------------------------------------------------
+//
+void CHttpTransportAdapter::InitialiseSessionL()
+    {
+#ifdef _DEBUG
+    WriteToLog( _L8( "CHttpTransportAdapter::InitialiseSessionL()" ) );
+#endif
+    iHttpSession.OpenL();
+    RSocketServ& session = iConnManager.SocketSession();
+    RConnection& connection = iConnManager.Connection();
+    RHTTPConnectionInfo connInfo = iHttpSession.ConnectionInfo();
+    RStringPool stringPool = iHttpSession.StringPool();
+    TInt conn = reinterpret_cast <TInt> ( &connection );
+    connInfo.SetPropertyL( stringPool.StringF( HTTP::EHttpSocketServ, RHTTPSession::GetTable() ),
+                           THTTPHdrVal( session.Handle() ) );
+    connInfo.SetPropertyL( stringPool.StringF( HTTP::EHttpSocketConnection, RHTTPSession::GetTable() ),
+                           THTTPHdrVal( conn ) );
+    connInfo.SetPropertyL( stringPool.StringF( HTTP::EHTTPVersion, RHTTPSession::GetTable() ),
+                           THTTPHdrVal( stringPool.StringF( HTTP::EHttp11, RHTTPSession::GetTable() ) ) );
+    iSessionClosed = EFalse;
+#ifdef _DEBUG
+    WriteToLog( _L8( "InitialiseSessionL() ends." ) );
+#endif
+    }
+
+// ----------------------------------------------------
+// CHttpTransportAdapterder::CancelTransaction
+//
+// ----------------------------------------------------
+//
+void CHttpTransportAdapter::CancelTransaction( const TInt aTID )
+    {
+#ifdef _DEBUG
+    WriteToLog( _L( "CHttpTransportAdapter::CancelTransaction(): TID %d" ), aTID );
+#endif
+    TInt count = iTransactionQueue.Count();
+#ifdef _DEBUG
+    WriteToLog( _L( "  %d items in transaction queue." ), count );
+#endif
+    for ( TInt i = 0;i < count;i++ )
+        {
+        CImpsHttpTransaction* transaction = iTransactionQueue[i];
+        if ( transaction->TID() == aTID )
+            {
+#ifdef _DEBUG
+            WriteToLog( _L( "    Request TID %d set to cancelled state." ), transaction->TID() );
+#endif
+            RemoveFromQueue( transaction );
+            break;
+            }
+        }
+    }
+
+// ----------------------------------------------------
+// CHttpTransportAdapter::CancelAll()
+//
+// ----------------------------------------------------
+//
+void CHttpTransportAdapter::CancelAll()
+    {
+#ifdef _DEBUG
+    WriteToLog( _L( "CHttpTransportAdapter::CancelAll()" ) );
+#endif
+    CImpsHttpTransaction* transaction = NULL;
+    TInt count = iTransactionQueue.Count();
+#ifdef _DEBUG
+    WriteToLog( _L( "  %d items in transaction queue" ), count );
+#endif
+    for ( TInt i = 0;i < count;i++ )
+        {
+        transaction = iTransactionQueue[i];
+        delete transaction;
+        transaction = NULL;
+#ifdef _DEBUG
+        WriteToLog( _L( "    Item %d deleted from transaction queue" ), i );
+#endif
+        }
+    iTransactionQueue.Reset();
+    }
+
+// ----------------------------------------------------
+// CHttpTransportAdapter::SendL
+//
+// ----------------------------------------------------
+//
+void CHttpTransportAdapter::SendL( const TInt aTID, const TDesC8& aMessage,
+                                   const TInt aExpiryTime )
+    {
+#ifdef _DEBUG
+    WriteToLog( _L( "SendL() called, aTID: %d" ), aTID );
+#endif
+    //GPRS is suspended
+    if ( iSuspend )
+        {
+#ifdef _DEBUG
+        WriteToLog( _L( "SendL(): GPRS suspended, leaves with \"KImpsErrorBearerSuspended\"." ) );
+#endif
+        User::Leave( KImpsErrorBearerSuspended );
+        }
+    //OpenL() has not been called
+    else if ( iUrlBuffer == NULL )
+        {
+#ifdef _DEBUG
+        WriteToLog( _L( "SendL(): No SAP defined, leaves with KImpsErrorSessionNotOpen" ) );
+#endif
+        User::Leave( KImpsErrorSessionNotOpen );
+        }
+    else
+        {
+        CImpsHttpTransaction* transaction = CImpsHttpTransaction::NewL( this, aTID, aMessage );
+        CleanupStack::PushL( transaction );
+        //Append the transaction to the end of the list of pending
+        //requests. The request gets removed as soon as a response
+        //arrives or timer expires.
+        TInt error = iTransactionQueue.Append( transaction );
+        if ( error != KErrNone )
+            User::Leave( error );
+        else
+            {
+            CleanupStack::Pop();  //transaction
+            //If the client application wants to time this request,
+            //aExpiryTime parameter should not be 0. If it is,
+            //ignore it; if not, instantiate timer and set this
+            //object as the receiver of the prospective expiry event.
+            //This requires the MImpsTransportTimerCallback interface
+            //and HandleTransportTimerEvent function to be implemented
+            if ( aExpiryTime != 0 )
+                transaction->SetExpiryTimeL( /* The timer expects milliseconds,
+                                              * so multiply by million. */
+                    aExpiryTime * 1000000, this );
+            //If suspend occurs after this,
+            //there is absolutely nothing that can be done
+            if ( iConnManager.Status() )
+                transaction->DispatchMessageL();
+            else
+                User::Leave( KImpsErrorBearerSuspended );
+            }
+        }
+    }
+
+// ----------------------------------------------------
+// CHttpTransportAdapter::Open
+//
+// ----------------------------------------------------
+//
+void CHttpTransportAdapter::OpenL( const TDesC& aSAP )
+    {
+#ifdef _DEBUG
+    TBuf8<256> eightBuf;
+    eightBuf.Copy( aSAP );
+    WriteToLog( _L8( "CHttpTransportAdapter::OpenL()" ) );
+    WriteToLog( _L8( " SAP: %S" ), &eightBuf );
+#endif
+    if ( !iConnManager.Status() )
+        User::Leave( KImpsErrorBearerSuspended );
+    if ( iSessionClosed )
+        {
+        InitialiseSessionL();
+        SetUrlL( aSAP );
+        SetProxyL();
+#ifdef _DEBUG
+        WriteToLog( _L8( "  URL: %S" ), &iDefaultURL.UriDes() );
+#endif
+        iConnManager.AddEventSubscriberL( this );
+        }
+    else
+        {
+#ifdef _DEBUG
+        WriteToLog( _L8( "  OpenL(): Already open, leaves with KErrAlreadyExists." ) );
+#endif
+        User::Leave( KErrAlreadyExists );
+        }
+    }
+
+// ----------------------------------------------------
+// CHttpTransportAdapter::Close
+//
+// ----------------------------------------------------
+//
+void CHttpTransportAdapter::Close()
+    {
+#ifdef _DEBUG
+    WriteToLog( _L8( "CHttpTransportAdapter::Close()" ) );
+#endif
+    if ( iTransactionQueue.Count() > 0 )
+        CancelAll();
+    if ( iSuspend )
+        iSuspend = EFalse;
+    delete iUrlBuffer;
+    iUrlBuffer = NULL;
+    iHttpSession.Close();
+    iSessionClosed = ETrue;
+    iConnManager.RemoveEventSubscriber( this );
+    }
+
+// ----------------------------------------------------
+// CHttpTransportAdapter::SetProxyL
+//
+// ----------------------------------------------------
+//
+void CHttpTransportAdapter::SetProxyL()
+    {
+    //It must be checked if there is the
+    //dummy proxy defined in CommsDb
+    _LIT8( KPortSeparatorColon, ":" );
+    _LIT( KDummyProxy, "www.dummyproxy.com" );
+#ifdef _DEBUG
+    WriteToLog( _L8( "CHttpTransportAdapter::SetProxyL" ) );
+#endif
+    delete iProxyBuffer;
+    iProxyBuffer = NULL;
+    HBufC* address = iConnManager.ReadFromCommsDbLC( EMsgProxyAddress );
+    if ( address != NULL && address->CompareF( KDummyProxy ) != 0 )
+        {
+        HBufC* port = iConnManager.ReadFromCommsDbLC( EMsgProxyPort );
+        iProxyBuffer = HBufC8::NewL( address->Length() +
+                                     port->Length() + 1 );  //":"
+        iProxyBuffer->Des().Copy( *address );
+        iProxyBuffer->Des().Append( KPortSeparatorColon );
+        iProxyBuffer->Des().Append( *port );
+        CleanupStack::PopAndDestroy( 2 );  //port, address
+#ifdef _DEBUG
+        TPtrC8 proxy( *iProxyBuffer );
+        WriteToLog( _L8( "  Proxy set to: %S" ), &proxy );
+#endif
+        RStringF proxyAddress = iHttpSession.StringPool().OpenFStringL( iProxyBuffer->Des() );
+        RHTTPConnectionInfo connInfo = iHttpSession.ConnectionInfo();
+        THTTPHdrVal proxyUsage( iHttpSession.StringPool().StringF( HTTP::EUseProxy, RHTTPSession::GetTable() ) );
+        connInfo.SetPropertyL( iHttpSession.StringPool().StringF( HTTP::EProxyUsage, RHTTPSession::GetTable() ), proxyUsage );
+        THTTPHdrVal proxyAddr( proxyAddress );
+        connInfo.SetPropertyL( iHttpSession.StringPool().StringF( HTTP::EProxyAddress, RHTTPSession::GetTable() ), proxyAddr );
+        proxyAddress.Close();
+        }
+    else
+        {
+        if ( address != NULL )
+            {
+#ifdef _DEBUG
+            HBufC8* temp = HBufC8::NewL( address->Length() );
+            temp->Des().Copy( *address );
+            TPtrC8 proxy( temp->Des() );
+            WriteToLog( _L8( "  Improper proxy (%S) defined, ignore" ), &proxy );
+            delete temp;
+            temp = NULL;
+#endif
+            CleanupStack::PopAndDestroy();  //address
+            }
+        else
+            {
+#ifdef _DEBUG
+            WriteToLog( _L8( "  No proxy defined for this Access Point" ) );
+#endif
+            }
+        }
+    }
+
+// ----------------------------------------------------
+// CHttpTransportAdapter::SetMimeTypeL
+//
+// ----------------------------------------------------
+//
+void CHttpTransportAdapter::SetMimeTypeL( const TDesC8& aMimeType )
+    {
+    if ( aMimeType.Length() > 0 )
+        {
+        delete iMimeBuffer;
+        iMimeBuffer = NULL;
+        iMimeBuffer = HBufC8::NewL( aMimeType.Length() );
+        iMimeBuffer->Des().Copy( aMimeType );
+#ifdef _DEBUG
+        TPtr8 ptr( iMimeBuffer->Des() );
+        WriteToLog( _L8( "CHttpTransportAdapter::SetMimeTypeL(): %S" ), &ptr );
+#endif
+        }
+    }
+
+// ----------------------------------------------------
+// CHttpTransportAdapter::SetUrlL
+//
+// ----------------------------------------------------
+//
+void CHttpTransportAdapter::SetUrlL( const TDesC& aUrl )
+    {
+#ifdef _DEBUG
+    WriteToLog( _L8( "CHttpTransportAdapter::SetUrl()" ) );
+#endif
+    _LIT( KHttp, "http://" );
+    delete iUrlBuffer;
+    iUrlBuffer = NULL;
+    if ( aUrl.FindF( KHttp ) == 0 )
+        iUrlBuffer = HBufC8::NewL( aUrl.Length() );
+    else
+        {
+        iUrlBuffer = HBufC8::NewL( aUrl.Length() + 7 );
+        iUrlBuffer->Des().Copy( KHttp );
+        }
+    iUrlBuffer->Des().Append( aUrl );
+    iDefaultURL.Parse( iUrlBuffer->Des() );
+    }
+
+// ----------------------------------------------------------
+// CHttpTransportAdapter::HandleTransportTimerEventL
+//
+// ----------------------------------------------------------
+//
+void CHttpTransportAdapter::HandleTransportTimerEventL( TImpsTimingRequester* aTransaction,
+                                                        const TInt /*aStatus*/ )
+    {
+    CImpsHttpTransaction* transaction = ( CImpsHttpTransaction* ) aTransaction;
+    TInt httpStatus = transaction->HttpStatus();
+#ifdef _DEBUG
+    WriteToLog( _L8( "CHttpTransportAdapter::HandleTransportTimerEventL()  Request: %d" ), transaction->TID() );
+#endif
+    iReceiver.TransportResponse( transaction->TID(), KErrTimedOut, httpStatus, NULL );
+    RemoveFromQueue( transaction );
+    }
+
+// ----------------------------------------------------
+// CHttpTransportAdapter::MHFRunL
+//
+// ----------------------------------------------------
+//
+void CHttpTransportAdapter::MHFRunL( RHTTPTransaction aTransaction, const THTTPEvent& aEvent )
+    {
+    switch ( aEvent.iStatus )
+        {
+        case THTTPEvent::EGotResponseHeaders:
+            {
+            CImpsHttpTransaction* action = ImpsTransaction( aTransaction );
+            RHTTPResponse response = aTransaction.Response();
+            TInt contentLength = ContentLengthL( response );
+            action->SetContentLength( contentLength );
+#ifdef _DEBUG
+            TInt status = response.StatusCode();
+            RStringF statusStr = response.StatusText();
+            TBuf<32> statusStr16;
+            statusStr16.Copy( statusStr.DesC() );
+            WriteToLog( _L( "CHttpTransportAdapter::MHFRunL(), Status: %d (%S), TID: %d, Round-Trip: %d ms" ),
+                        status, &statusStr16, action->TID(),
+                        action->TimeL() - action->SendTime() );
+            DumpResponseHeadersL( aTransaction, action->TID() );
+#endif
+            //If this transaction has been cancelled, it must be handled now.
+            if ( action->IsCancelled() )
+                {
+                //This does cancelling automagically
+#ifdef _DEBUG
+                WriteToLog( _L( "CHttpTransportAdapter::MHFRunL(), TID: \"%d\" was cancelled" ), action->TID() );
+#endif
+                RemoveFromQueue( action );
+                break;
+                }
+            switch ( contentLength )
+                {
+                case 0:
+                    //Content-Length of the response may or may not be 0.
+                    //If it is, the response is most likely a poll response.
+#ifdef _DEBUG
+                    WriteToLog( _L8( "CHttpTransportAdapter::MHFRunL(), Content-Length 0, no body to wait for." ) );
+                    WriteToLog( _L8( "CHttpTransportAdapter::MHFRunL(), Calling receiver with a TID \"%d\"" ), action->TID() );
+#endif
+                    iReceiver.TransportResponse( action->TID(), KErrNone,
+                                                 action->HttpStatus(), NULL );
+                    RemoveFromQueue( action );
+                    break;
+                case KMaxTInt:
+                    /*
+                    It may be, however, that the Transfer-Encoding = "chunked",
+                    in which case missing Content-Length is perfectly acceptable.
+                    Thus, if the response body is supposed to arrive in chunks,
+                    ignore this event and wait for the next one. In other words,
+                    let the HTTP stack decide what to do next.
+                    This case is essentially identical to the default case, but
+                    rendering it this way might make the fact a bit more obvious and,
+                    thus, the code also a bit more readable. The compiler probably
+                    knows how to optimise this, anyway.
+                    */
+                    break;
+                default:
+                    break;
+                }
+            }
+        break;
+        case THTTPEvent::EGotResponseBodyData:
+            {
+            TPtrC8 bodyData;
+            CImpsHttpTransaction* action = ImpsTransaction( aTransaction );
+#ifdef _DEBUG
+            WriteToLog( _L8( "MHFRunL(): a body part received - TID: %d" ), action->TID() );
+#endif
+            //The request data can now be deleted
+            action->DoReleaseData();
+            // Get the body data supplier
+            iRespBody = aTransaction.Response().Body();
+            TBool lastChunk = iRespBody->GetNextDataPart( bodyData );
+            action->AppendDataL( bodyData, lastChunk );
+            // Done with that bit of body data
+            iRespBody->ReleaseData();
+            if ( lastChunk )
+                {
+#ifdef _DEBUG
+                WriteToLog( _L8( "  Last chunk - TID: %d" ), action->TID() );
+#endif
+                action->FinaliseRequestL( KErrNone );
+                }
+            }
+        break;
+        case THTTPEvent::EResponseComplete:
+            {
+            //The response of the transaction is complete
+#ifdef _DEBUG
+            WriteToLog( _L( "CHttpTransportAdapter::MHFRunL(), Transaction Complete" ) );
+#endif
+            }
+        break;
+        case THTTPEvent::ESucceeded:
+            {
+            CImpsHttpTransaction* action = ImpsTransaction( aTransaction );
+            //If iLastChunk is not ETrue, the framework has not changed it when
+            //it delivered the payload data. For some reason the framework
+            //does not return ETrue when GetNextDataPart() is called while the
+            //value of the Transfer-Encoding header is "chunked". Hence we must
+            //call the client application now.
+            if ( !action->LastChunk() )
+                {
+#ifdef _DEBUG
+                WriteToLog( _L8( "CHttpTransportAdapter::MHFRunL(), Transaction finished, but iLastChunk = EFalse." ) );
+                WriteToLog( _L8( "  Complete the transaction %d" ), action->TID() );
+#endif
+                action->FinaliseRequestL( KErrNone );
+                }
+            else
+                {
+#ifdef _DEBUG
+                WriteToLog( _L( "CHttpTransportAdapter::MHFRunL(), Transaction Successful. TID: %d" ), action->TID() );
+#endif
+                }
+            RemoveFromQueue( action );
+            }
+        break;
+        case THTTPEvent::EFailed:
+            {
+            CImpsHttpTransaction* action = ImpsTransaction( aTransaction );
+#ifdef _DEBUG
+            WriteToLog( _L( "Transaction Failed. TID: %d" ), action->TID() );
+#endif
+            if ( !action->LastChunk() )
+                action->FinaliseRequestL( KErrGeneral );
+            RemoveFromQueue( action );
+            }
+        break;
+        case THTTPEvent::ERedirectedPermanently:
+            {
+#ifdef _DEBUG
+            CImpsHttpTransaction* action = ImpsTransaction( aTransaction );
+            WriteToLog( _L( "  SAP redirected permanently - TID: %d" ), action->TID() );
+#endif
+            //For the time being, both redirections are handled the same way.
+            //Which is that they're not handled here at all, but in the HTTP Stack...
+            //HandleTemporaryRedirectionL( aTransaction );
+            //HandlePermanentRedirectionL( aTransaction );
+            }
+        break;
+        case THTTPEvent::ERedirectedTemporarily:
+            {
+#ifdef _DEBUG
+            CImpsHttpTransaction* action = ImpsTransaction( aTransaction );
+            WriteToLog( _L( "  SAP redirected temporarily - TID: %d" ), action->TID() );
+#endif
+            //HandleTemporaryRedirectionL( aTransaction );
+            }
+        break;
+        default:
+            {
+#ifdef _DEBUG
+            WriteToLog( _L( "<Unrecognised event: %d>" ), aEvent.iStatus );
+#endif
+            TInt error = ConvertUndefinedError( aEvent.iStatus );
+#ifdef _DEBUG
+            WriteToLog( _L( "  Error %d converted to %d" ), aEvent.iStatus, error );
+#endif
+            CImpsHttpTransaction* action = ImpsTransaction( aTransaction );
+            //Should we try to resend the request in case it fails?
+            //This has been an issue of some controversy, so just in case
+            //let's try the following procedure:
+            if ( error < 0 )
+                {
+                //Right, it failed for some reason. These two guys are the
+                //errors that we see most often, so give them a special
+                //treatment - try to send the request again. There is a
+                //const value in CImpsHttpTransaction KMaxNumberOfRetries
+                //which is followed at this point; if Resend() returns with EFalse,
+                //the request has spent all its "lives" and it gets the boot.
+                if ( action != NULL &&
+                     ( error == KErrEof ||
+                       error == KErrDisconnected ) )
+                    {
+                    if ( !action->ResendL() )
+                        {
+                        iReceiver.TransportResponse( action->TID(), error,
+                                                     action->HttpStatus(), NULL );
+                        RemoveFromQueue( action );
+                        }
+                    }
+                else
+                    {
+                    //There is little that can be done: the status is none of the ones
+                    //we're interested in, neither is it a system-wide error that might
+                    //be meaningful to the receiver. Forward the status to the receiver
+                    //nevertheless and delete the transaction, it is quite useless now.
+                    iReceiver.TransportResponse( action->TID(), error,
+                                                 action->HttpStatus(), NULL );
+                    RemoveFromQueue( action );
+                    }
+                }
+            else
+                {
+                //We don't know what this is... A positive number, but none of
+                //the HTTP specific ones. Simply ignore the response.
+                if ( action != NULL && error != 10 )
+                    {
+                    iReceiver.TransportResponse( action->TID(), error,
+                                                 action->HttpStatus(), NULL );
+                    RemoveFromQueue( action );
+                    }
+                else if ( error == 10 )
+                    {
+                    //Do nothing, this will return once more in THTTPEvent::EFailed.
+                    //The meaning of this status is a bit unclear.
+                    }
+                }
+            }
+        break;
+        }
+    }
+
+// ----------------------------------------------------------
+// CImpsHttpTransactionSender::HandleTemporaryRedirectionL
+//
+// ----------------------------------------------------------
+//
+void CHttpTransportAdapter::HandleTemporaryRedirectionL( RHTTPTransaction aTransaction )
+    {
+    RHTTPResponse response = aTransaction.Response();
+    TPtrC8 newURL( LocationL( response ) );
+    CImpsHttpTransaction* action = ImpsTransaction( aTransaction );
+    if ( newURL.Length() > 0 && action != NULL )
+        {
+        delete iUrlBuffer;
+        iUrlBuffer = NULL;
+        iUrlBuffer = HBufC8::NewL( newURL.Length() );
+        iUrlBuffer->Des().Copy( newURL );
+        action->ResendL();
+#ifdef _DEBUG
+        TPtr8 ptr( iUrlBuffer->Des() );
+        WriteToLog( _L8( "CHttpTransportAdapter::HandleTemporaryRedirectionL() - TID %d" ), action->TID() );
+        WriteToLog( _L8( "   New SAP address assigned: %S" ), &ptr );
+        WriteToLog( _L8( "   Transaction retransmitted to the new destination" ) );
+#endif
+        }
+    else
+        {
+#ifdef _DEBUG
+        WriteToLog( _L8( "CHttpTransportAdapter::HandleTemporaryRedirectionL() - TID %d" ), action->TID() );
+        WriteToLog( _L8( "   The SAP Server did not return a redirect address, cannot continue." ) );
+#endif
+        iReceiver.TransportResponse( action->TID(), KErrCouldNotConnect,
+                                     action->HttpStatus(), NULL );
+        RemoveFromQueue( action );
+        }
+    }
+
+// ----------------------------------------------------------
+// CImpsHttpTransactionSender::HandlePermanentRedirectionL
+//
+// ----------------------------------------------------------
+//
+void CHttpTransportAdapter::HandlePermanentRedirectionL( RHTTPTransaction /*aTransaction*/ )
+    {
+
+    }
+
+// ----------------------------------------------------------
+// CImpsHttpTransactionSender::ConvertUndefinedError
+//
+// ----------------------------------------------------------
+//
+TInt CHttpTransportAdapter::ConvertUndefinedError( const TInt aError )
+    {
+#ifdef _DEBUG
+    WriteToLog( _L8( "ConvertUndefinedError(): %d" ), aError );
+#endif
+    TInt error = 0;
+    switch ( aError )
+        {
+        case -5120:
+            error = KErrIfDNSNotFound;
+            break;
+        default:
+            error = aError;
+        }
+    return error;
+    }
+
+// ----------------------------------------------------------
+// CImpsHttpTransactionSender::ImpsTransaction
+//
+// ----------------------------------------------------------
+//
+CImpsHttpTransaction* CHttpTransportAdapter::ImpsTransaction( const RHTTPTransaction& aTransaction )
+    {
+    TInt count = iTransactionQueue.Count();
+    CImpsHttpTransaction* traverse = NULL;
+    CImpsHttpTransaction* ret = NULL;
+    for ( TInt i = 0;i < count;i++ )
+        {
+        traverse = iTransactionQueue[i];
+        if ( traverse->Transaction() == aTransaction )
+            {
+            ret = traverse;
+            break;
+            }
+        }
+    return ret;
+    }
+
+// ----------------------------------------------------------
+// CImpsHttpTransactionSender::ContentLengthL
+//
+// ----------------------------------------------------------
+//
+TInt CHttpTransportAdapter::ContentLengthL( RHTTPResponse aResponse ) const
+    {
+    TInt retVal = KMaxTInt;
+    _LIT8( KContentLength, "Content-Length" );
+    THTTPHdrVal fieldValue;
+    RStringPool stringPool = iHttpSession.StringPool();
+    RHTTPHeaders headers = aResponse.GetHeaderCollection();
+    RStringF lengthString = stringPool.OpenFStringL( KContentLength );
+    headers.GetField( lengthString, 0, fieldValue );
+    lengthString.Close();
+    if ( fieldValue.Type() == THTTPHdrVal::KTIntVal )
+        {
+#ifdef _DEBUG
+        WriteToLog( _L8( "CHttpTransportAdapter::ContentLengthL(): %d" ), fieldValue.Int() );
+#endif
+        retVal = fieldValue.Int();
+        }
+    return retVal;
+    }
+
+// ----------------------------------------------------------
+// CImpsHttpTransactionSender::LocationL
+//
+// ----------------------------------------------------------
+//
+TPtrC8 CHttpTransportAdapter::LocationL( RHTTPResponse aResponse ) const
+    {
+    TPtrC8 sapAddress;
+    _LIT8( KLocation, "Location" );
+    THTTPHdrVal fieldValue;
+    RStringPool stringPool = iHttpSession.StringPool();
+    RHTTPHeaders headers = aResponse.GetHeaderCollection();
+    RStringF location = stringPool.OpenFStringL( KLocation );
+    headers.GetField( location, 0, fieldValue );
+    location.Close();
+    if ( fieldValue.Type() == THTTPHdrVal::KStrVal ||
+         fieldValue.Type() == THTTPHdrVal::KStrFVal )
+        {
+        RString address = fieldValue.Str();
+        sapAddress.Set( address.DesC() );
+#ifdef _DEBUG
+        TPtrC8 dump( address.DesC() );
+        WriteToLog( _L8( "CHttpTransportAdapter::LocationL(): %S" ), &dump );
+#endif
+        }
+    return sapAddress;
+    }
+
+// ----------------------------------------------------------
+// CHttpTransportAdapter::RemoveFromQueue
+//
+// ----------------------------------------------------------
+//
+void CHttpTransportAdapter::RemoveFromQueue( const CImpsHttpTransaction* aRemove )
+    {
+    TInt index = iTransactionQueue.Find( aRemove );
+    if ( index >= 0 )
+        {
+#ifdef _DEBUG
+        WriteToLog( _L8( "CHttpTransportAdapter::RemoveFromQueue( transaction* ), TID: \"%d\"" ), aRemove->TID() );
+#endif
+        iTransactionQueue.Remove( index );
+        delete aRemove;
+        aRemove = NULL;
+        }
+    }
+
+// ----------------------------------------------------
+// CHttpTransportAdapter::MHFRunError
+// HTTP Stack callback interface
+// ----------------------------------------------------
+//
+TInt CHttpTransportAdapter::MHFRunError( TInt aInt, RHTTPTransaction aTransaction,
+                                         const THTTPEvent& /*aEvent*/ )
+    {
+    CImpsHttpTransaction* action = ImpsTransaction( aTransaction );
+#ifdef _DEBUG
+    WriteToLog( _L( "CHttpTransportAdapter::MHFRunError(): %d" ), aInt );
+    WriteToLog( _L( "Calling receiver with a TID \"%d\" and closing the corresponding request." ), action->TID() );
+#endif
+    iReceiver.TransportResponse( action->TID(), aInt,
+                                 action->HttpStatus(), NULL );
+    RemoveFromQueue( action );
+    return KErrNone;
+    }
+
+// ----------------------------------------------------------
+// CHttpTransportAdapter::HandleBearerEventL
+//
+// ----------------------------------------------------------
+//
+void CHttpTransportAdapter::HandleBearerEventL( TBool aIsAuthClose, TMsgBearerEvent aBearerEvent )
+    {
+#ifdef _DEBUG
+    WriteToLog( _L( "CHttpTransportAdapter::HandleBearerEventL() - Event: %d  AuthClose: %d" ),
+                aBearerEvent, aIsAuthClose );
+#endif
+    switch ( aBearerEvent )
+        {
+        case EMsgBearerSuspended:
+#ifdef _DEBUG
+            WriteToLog( _L( "  Bearer suspended" ) );
+#endif
+            iSuspend = ETrue;
+            break;
+        case EMsgBearerActive:
+#ifdef _DEBUG
+            WriteToLog( _L( "  Bearer active" ) );
+#endif
+            iSuspend = EFalse;
+            break;
+        case EMsgBearerLost:
+#ifdef _DEBUG
+            WriteToLog( _L( "  Bearer lost, close data channel" ) );
+#endif
+            Close();
+            break;
+        default:
+            break;
+        }
+    }
+
+#ifdef _DEBUG
+
+// ----------------------------------------------------
+// CHttpTransportAdapter::WriteToLog
+//
+// ----------------------------------------------------
+//
+/*TPtrC8 CHttpTransportAdapter::Name() const
+    {
+    return TPtrC8( _L8( "DataChannel" ) );
+    }*/
+
+// ----------------------------------------------------
+// CHttpTransportAdapter::WriteToLog
+// Writes to the log, 8-bit version
+// ----------------------------------------------------
+//
+void CHttpTransportAdapter::WriteToLog( TRefByValue<const TDesC8> aFmt, ... )
+    {
+    VA_LIST list;
+    VA_START( list, aFmt );
+    TBuf8<KLogBufferMaxSize> buf;
+    buf.FormatList( aFmt, list );
+    RFileLogger::Write( KLogDir, KTransportLogFile, EFileLoggingModeAppend, buf );
+    }
+
+// ----------------------------------------------------
+// CHttpTransportAdapter::RunL
+// Writes to the log, UNICODE version
+// ----------------------------------------------------
+//
+void CHttpTransportAdapter::WriteToLog( TRefByValue<const TDesC> aFmt, ... )
+    {
+    VA_LIST list;
+    VA_START( list, aFmt );
+    TBuf<KLogBufferMaxSize> buf;
+    buf.FormatList( aFmt, list );
+    RFileLogger::Write( KLogDir, KTransportLogFile, EFileLoggingModeAppend, buf );
+    }
+
+// ----------------------------------------------------------
+// CHttpTransportAdapter::DeleteLogFiles
+//
+// ----------------------------------------------------------
+//
+void CHttpTransportAdapter::DeleteLogFilesL()
+    {
+    RFs session;
+    User::LeaveIfError( session.Connect() );
+    CFileMan* manager = CFileMan::NewL( session );
+    manager->Delete( _L( "C:\\logs\\ImpsDataChannel\\*.*" ) );
+    session.Close();
+    delete manager;
+    manager = NULL;
+    }
+
+// ----------------------------------------------------
+// CHttpTransportAdapter::DumpResponseHeadersL
+//
+// ----------------------------------------------------
+//
+void CHttpTransportAdapter::DumpResponseHeadersL( RHTTPTransaction& aTrans,
+                                                  const TInt aTransactionID )
+    {
+    WriteToLog( _L( "--------------------" ) );
+    WriteToLog( _L( "Headers of the transaction %d: " ), aTransactionID );
+    RHTTPResponse resp = aTrans.Response();
+    RStringPool strP = aTrans.Session().StringPool();
+    RHTTPHeaders hdr = resp.GetHeaderCollection();
+    THTTPHdrFieldIter it = hdr.Fields();
+
+    TBuf<KMaxHeaderNameLen>  fieldName16;
+    TBuf<KMaxHeaderValueLen> fieldVal16;
+
+    while ( it.AtEnd() == EFalse )
+        {
+        RStringTokenF fieldName = it();
+        RStringF fieldNameStr = strP.StringF( fieldName );
+        THTTPHdrVal fieldVal;
+        if ( hdr.GetField( fieldNameStr, 0, fieldVal ) == KErrNone )
+            {
+            const TDesC8& fieldNameDesC = fieldNameStr.DesC();
+            fieldName16.Copy( fieldNameDesC.Left( KMaxHeaderNameLen ) );
+            switch ( fieldVal.Type() )
+                {
+                case THTTPHdrVal::KTIntVal:
+                    WriteToLog( _L( "%S: %d\n" ), &fieldName16, fieldVal.Int() );
+                    break;
+                case THTTPHdrVal::KStrFVal:
+                    {
+                    RStringF fieldValStr = strP.StringF( fieldVal.StrF() );
+                    const TDesC8& fieldValDesC = fieldValStr.DesC();
+                    fieldVal16.Copy( fieldValDesC.Left( KMaxHeaderValueLen ) );
+                    WriteToLog( _L( "%S: %S\n" ), &fieldName16, &fieldVal16 );
+                    }
+                break;
+                case THTTPHdrVal::KStrVal:
+                    {
+                    RString fieldValStr = strP.String( fieldVal.Str() );
+                    const TDesC8& fieldValDesC = fieldValStr.DesC();
+                    fieldVal16.Copy( fieldValDesC.Left( KMaxHeaderValueLen ) );
+                    WriteToLog( _L( "%S: %S\n" ), &fieldName16, &fieldVal16 );
+                    }
+                break;
+                case THTTPHdrVal::KDateVal:
+                    {
+                    TDateTime date = fieldVal.DateTime();
+                    TBuf<40> dateTimeString;
+                    TTime t( date );
+                    t.FormatL( dateTimeString, KDateFormat );
+                    WriteToLog( _L( "%S: %S\n" ), &fieldName16, &dateTimeString );
+                    }
+                break;
+                default:
+                    WriteToLog( _L( "%S: <unrecognised value type>\n" ), &fieldName16 );
+                    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 ) &&
+                     ( !hdr.GetParam( wwwAuth, realm, realmVal ) ) )
+                    {
+                    RStringF realmValStr = strP.StringF( realmVal.StrF() );
+                    fieldVal16.Copy( realmValStr.DesC() );
+                    WriteToLog( _L( "Realm is: %S\n" ), &fieldVal16 );
+                    }
+                }
+            }
+        ++it;
+        }
+    WriteToLog( _L( "--------------------" ) );
+    }
+
+#endif
+
+// ----------------------------------------------------
+// CHttpTransportAdapter::NewImpsSenderL
+// Returns a sender instance
+// ----------------------------------------------------
+//
+EXPORT_C MImpsSender* NewImpsSenderL( MImpsDataReceiver& aReceiver,
+                                      MMsgConnManager& aConnManager,
+                                      const TDesC8& aMimeType )
+    {
+    return CHttpTransportAdapter::NewL( aReceiver, aConnManager, aMimeType );
+    }
+
+
+// End of File