IMPSengine/ImpsDataChannel/src/HttpTransportAdapter.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Thu, 17 Dec 2009 08:41:52 +0200
changeset 0 094583676ce7
permissions -rw-r--r--
Revision: 200949 Kit: 200951

/*
* 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