httpfilters/httpfilterconnhandler/Src/HttpFilterConnHandler.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Wed, 13 Oct 2010 15:09:28 +0300
branchRCL_3
changeset 53 c59bddbfd7b9
parent 10 73e95e652591
permissions -rw-r--r--
Revision: 201038 Kit: 201041

/*
* 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:  ConnHandler filter
*
*/



// INCLUDE FILES
#include <http.h>
#include <es_sock.h>

#include <ApEngineConsts.h>  // defines bearer types
#include "HttpFilterConnHandler.h"

#include "HttpFilterConnHandlerObserverPS.h"
#include <PSVariables.h>  // Publish & Subscribe

#include "httpfiltercommonstringsext.h"
#include "mconnectioncallback.h"

// uncomment for logging
//#include <flogger.h>
//_LIT(KDir, "connFilter");
//_LIT(KFile, "filtererr.txt");

// EXTERNAL DATA STRUCTURES

// EXTERNAL FUNCTION PROTOTYPES
void PanicHttpFiltersConnHandler(TInt aErr = 0);

// CONSTANTS
const TInt KConnHandlerOrderOffset = 10;

// MACROS

// LOCAL CONSTANTS AND MACROS

// MODULE DATA STRUCTURES

// LOCAL FUNCTION PROTOTYPES

// FORWARD DECLARATIONS

// ============================= LOCAL FUNCTIONS ===============================

// -----------------------------------------------------------------------------
// LocalHostCheckL
// If the host is a local host. Returns ETrue
// if the transaction request URI was for a localhost.
// -----------------------------------------------------------------------------
//
TBool LocalHostCheckL(RHTTPTransaction& aTransaction)
    {
    _LIT8(KLoopbackIPv4Url, "http://127.0.0.1"); 
    
    RHTTPRequest request = aTransaction.Request();
    TUriC8 uri = request.URI();

    TUriParser8 parserLoopBack;
    parserLoopBack.Parse(KLoopbackIPv4Url());
    TInt match = parserLoopBack.Compare(uri, EUriHost);

    if (KErrNone != match)
        {
        _LIT8(KLocalHostUrl, "http://localhost"); 

        // try another compare - compare against the "localhost".
        TUriParser8 parserLocalHost;
        parserLocalHost.Parse(KLocalHostUrl());
        match = parserLocalHost.Compare(uri, EUriHost);

        if (KErrNone == match) 
            {
            _LIT8(KLoopbackIPv4, "127.0.0.1"); 

            // "localhost" resolves to "::1", manually, replace with "127.0.0.1"
            CUri8* newUri = CUri8::NewLC(uri);
            newUri->SetComponentL(KLoopbackIPv4(), EUriHost);
            request.SetURIL(newUri->Uri());
            CleanupStack::PopAndDestroy(newUri);
            }
        }
              
    if (KErrNone == match)
        {
        return ETrue;                                                          
        }
    return EFalse;
    }

// ============================ MEMBER FUNCTIONS ===============================

// -----------------------------------------------------------------------------
// CHttpFilterConnHandler::CHttpFilterConnHandler
// C++ default constructor can NOT contain any code, that
// might leave.
// -----------------------------------------------------------------------------
//
CHttpFilterConnHandler::CHttpFilterConnHandler(RHTTPSession* aSession, MConnectionCallback* aConnCallback):
        iConnCallback (aConnCallback),
        iLastIapId (0)
{
    __ASSERT_DEBUG(aConnCallback != NULL, PanicHttpFiltersConnHandler());
    __ASSERT_DEBUG(aSession != NULL, PanicHttpFiltersConnHandler());
    iSession      = aSession;
}


// ------------------------------------------------------------------------------------------
// CHttpFilterConnHandler::ConstructL
// Symbian 2nd phase constructor can leave.
// ------------------------------------------------------------------------------------------
//
void CHttpFilterConnHandler::ConstructL()
{
    // Register the filter for THTTPSessionEvent::EConnect events,
    // Adds a filter to the session's filter queue.
    iSession->FilterCollection().AddFilterL(*this,   // The filter to add
                                            THTTPSessionEvent::EConnect,       // The event that triggers this filter
                                            RStringF(),   // The header whose presence triggers this filter, or KNullDesC to trigger on any header
                                            KAnyStatusCode,  // The status code that triggers this filter, or KAnyStatusCode to trigger on any status code
                                            ECache - KConnHandlerOrderOffset,            // The position of the filter in the queue
                                            iSession->StringPool().StringF(HttpFilterCommonStringsExt::EConnHandlerFilter,
                                                                           HttpFilterCommonStringsExt::GetTable()));    //The name of the filter to add

    // Register the filter for submit events,
    // Adds a filter to the session's filter queue.
    iSession->FilterCollection().AddFilterL(*this,   // The filter to add
                                            THTTPEvent::ESubmit,       // The event that triggers this filter
                                            RStringF(), // The header whose presence triggers this filter, or KNullDesC to trigger on any header
                                            KAnyStatusCode, // The status code that triggers this filter, or KAnyStatusCode to trigger on any status code
                                            ECache - KConnHandlerOrderOffset,            // The position of the filter in the queue
                                            iSession->StringPool().StringF(HttpFilterCommonStringsExt::EConnHandlerFilter,
                                                                           HttpFilterCommonStringsExt::GetTable())); //The name of the filter to add

	// Create an instance of the CHttpFilterConnHandlerObserver in order to handle "No coverage" situation
    iObserver = CHttpFilterConnHandlerObserver::NewL(iConnCallback);
}

//---------------------------------------------------------------------------------------------
// Destructor
//----------------------------------------------------------------------------------------------
//
CHttpFilterConnHandler::~CHttpFilterConnHandler()
{
    delete iObserver;
}

// ---------------------------------------------------------------------------------------------
// CHttpFilterConnHandler::InstallFilterL
// Two-phased constructor. This function replaces NewL.
// ---------------------------------------------------------------------------------------------
//
CHttpFilterConnHandler* CHttpFilterConnHandler::InstallFilterL(TAny* aParams)
{
    __ASSERT_DEBUG(aParams != NULL, PanicHttpFiltersConnHandler());
    TConnParams* connParams = REINTERPRET_CAST(TConnParams*, aParams);
    __ASSERT_DEBUG(connParams->iSession != NULL, PanicHttpFiltersConnHandler());
    __ASSERT_DEBUG(connParams->iConnCallback != NULL, PanicHttpFiltersConnHandler());

    CHttpFilterConnHandler* filter = new (ELeave) CHttpFilterConnHandler( connParams->iSession, connParams->iConnCallback );
    CleanupStack::PushL(filter);
    filter->ConstructL();
    CleanupStack::Pop(filter);
    return filter;
}

// ---------------------------------------------------------------------------------------------
// CHttpFilterConnHandler::MHFLoad
// Called when the filter is being added to the session's filter queue.
// ---------------------------------------------------------------------------------------------
//
void CHttpFilterConnHandler::MHFLoad(RHTTPSession, THTTPFilterHandle)
{
    ++iLoadCount;
}

// ----------------------------------------------------------------------------------------------
// CHttpFilterConnHandler::MHFUnload
// Called when the filter is being removed from a session's filter queue.
// ----------------------------------------------------------------------------------------------
//
void CHttpFilterConnHandler::MHFUnload(RHTTPSession /*aSession*/, THTTPFilterHandle /*aFilterHandler*/)
{
    __ASSERT_DEBUG(iLoadCount >= 0, PanicHttpFiltersConnHandler());
    if (--iLoadCount)
    {
        return;
    }
    delete this;
}

// ------------------------------------------------------------------------------------------------
// CHttpFilterConnHandler::MHFRunL
// Process a transaction event.
// ------------------------------------------------------------------------------------------------
//
void CHttpFilterConnHandler::MHFRunL(RHTTPTransaction aTransaction,
                                     const THTTPEvent& aEvent)
{
    TInt state = 0;
    TInt gprsState = 0;
    TInt wcdmaState = 0;
    TApBearerType bearerType;

    if (aEvent.iStatus == THTTPEvent::ESubmit)
    {
        THTTPHdrVal isNewConn;
        RHTTPConnectionInfo	connInfo = iSession->ConnectionInfo();
        RStringPool strPool = aTransaction.Session().StringPool();
        TBool ret = connInfo.Property (strPool.StringF(HttpFilterCommonStringsExt::EHttpNewConnFlag,
                                       HttpFilterCommonStringsExt::GetTable()), isNewConn);

        if ( LocalHostCheckL(aTransaction) && !( ret && isNewConn.Type() == THTTPHdrVal::KTIntVal ) )
            {
            return;
            }

        THTTPHdrVal callback;
        RHTTPTransactionPropertySet propSet = aTransaction.PropertySet();
        RStringF callbackStr = strPool.StringF( HttpFilterCommonStringsExt::EConnectionCallback, 
            HttpFilterCommonStringsExt::GetTable() );

        MConnectionCallback* callbackPtr = NULL;
    
        // this is a transaction, already forwarded to download manager
        if( propSet.Property( callbackStr, callback ) )
        {
            callbackPtr = REINTERPRET_CAST( MConnectionCallback*, callback.Int() );
        }        
        // make sure it is not null
        callbackPtr = callbackPtr ? callbackPtr : iConnCallback;

        CreateConnectionL( &bearerType, callbackPtr );

        iObserver->SetBearerTypeAndUid(bearerType);
        // check if "No coverage" situation exists for the GPRS bearer
        if (bearerType == EApBearerTypeGPRS)
        {
            // we sent request, so change Observer state to  EActiveReady
            iObserver->GetObserverState(state);
            if (state == EIdle)
            {
              iObserver->GetStateL(KPSUidGprsStatusValue, gprsState);
			  iObserver->GetStateL(KPSUidWcdmaStatusValue, wcdmaState);
              if (gprsState == EPSGprsSuspend && wcdmaState == EPSWcdmaSuspend)
              {
                // user sent request from "No coverage" area, so all outstanding transactions will 
                // be canceled in this case and user will be notified.
                  callbackPtr->CoverageEvent(EErrNetUnreach);
              }
              else
              {
                  iObserver->SetObserverState(EActiveReady);         
              }
            }  
        }
        else if(bearerType == EApBearerTypeCDMA) 
        {
            // we sent request, so change Observer state to  EActiveReady
            iObserver->GetObserverState(state);
            if (state == EIdle)
            {
              iObserver->GetStateL(KPSUidWcdmaStatusValue, wcdmaState);
			  iObserver->GetStateL(KPSUidGprsStatusValue, gprsState);
              if (wcdmaState == EPSWcdmaSuspend  && gprsState == EPSGprsSuspend) //this should not meet all the time.
              {
                // user sent request from "No coverage" area, so all outstanding transactions will 
                // be canceled in this case and user will be notified.  
                  callbackPtr->CoverageEvent(EErrNetUnreach);
              }
              else
              {
                  iObserver->SetObserverState(EActiveReady);
              }
            }
        }
    }
}

// -----------------------------------------------------------------------------
// CHttpFilterConnHandler::MHFRunError
// Process an error that occured while processing the transaction.
// -----------------------------------------------------------------------------
//
TInt CHttpFilterConnHandler::MHFRunError(TInt ,
        RHTTPTransaction aTransaction,
        const THTTPEvent& )
{
    aTransaction.Cancel();
    return KErrNone;
}

// -----------------------------------------------------------------------------
// CHttpFilterConnHandler::MHFSessionRunL
// Process a session event.
// -----------------------------------------------------------------------------
//
void CHttpFilterConnHandler::MHFSessionRunL(const THTTPSessionEvent& aEvent)
{
    TApBearerType bearerType;

    if (aEvent.iStatus == THTTPSessionEvent::EConnect)
    {
        CreateConnectionL(&bearerType, iConnCallback );
    }
}

// -----------------------------------------------------------------------------
// CHttpFilterConnHandler::MHFSessionRunError
// Called when MHFRunL leaves from a session event.
// -----------------------------------------------------------------------------
//
TInt CHttpFilterConnHandler::MHFSessionRunError(TInt aError, const THTTPSessionEvent& /*aEvent*/)
{
    return aError;
}

// -----------------------------------------------------------------------------
// CHttpFilterConnHandler::GetObserver
// Access method
// -----------------------------------------------------------------------------
//
void CHttpFilterConnHandler::GetObserver(CHttpFilterConnHandlerObserver*& aObserver)
{
    aObserver = iObserver;
}


// -----------------------------------------------------------------------------
// CHttpFilterConnHandler::CreateConnection
// Function to handle Submit events.
// Set proxy properties (EUseProxy and EProxyAddress) in order to get connected throught
// proxy when a new HTTP session will be in effect.  The Proxy data will be taken from
// the CommDb if a new connection has been used.
// -----------------------------------------------------------------------------
//
void CHttpFilterConnHandler::CreateConnectionL(
    TApBearerType* bearerType,
    MConnectionCallback* aCallbackPtr )
{
    RStringPool stringPool = iSession->StringPool();
    RHTTPConnectionInfo	connInfo = iSession->ConnectionInfo();

    // pointer to RConnection typecasted as TInt
    TInt connectionPtr = 0;
    // handle to the socket server
    TInt sockSvrHandle = 0;
    // flag of a new connection
    TBool newConn = ETrue;

    TInt error = aCallbackPtr->CreateConnection(&connectionPtr, &sockSvrHandle, &newConn, bearerType);

    // Possible causes to leave are: KErrCommsLineFail (NW_STAT_CONN_FAILED), KErrCancel (NW_STAT_CANCELLED)
    if (error != KErrNone)
    {
        User::LeaveIfError( error );
    }

    // Remove the properties if they were set before, before setting them again
    connInfo.RemoveProperty(stringPool.StringF(HTTP::EHttpSocketConnection,
                            RHTTPSession::GetTable()));
    connInfo.RemoveProperty(stringPool.StringF(HTTP::EHttpSocketServ,
                            RHTTPSession::GetTable()));
    connInfo.RemoveProperty(stringPool.StringF(HttpFilterCommonStringsExt::EHttpNewConnFlag,
                            HttpFilterCommonStringsExt::GetTable()));


    // Add the properties only if there is valid connection and socket server handler
    if (connectionPtr != NULL && sockSvrHandle != 0)
    {
        connInfo.SetPropertyL(stringPool.StringF(HTTP::EHttpSocketConnection,
                              RHTTPSession::GetTable()), THTTPHdrVal(connectionPtr));
        // Set socket server handle
        connInfo.SetPropertyL(stringPool.StringF(HTTP::EHttpSocketServ,
                              RHTTPSession::GetTable()), THTTPHdrVal((TInt)sockSvrHandle));

        // Double check that client has set newConn properly
        if (!newConn)
        {
            RConnection* connPtr = NULL;
            TUint32 iapId = 0;
            
            // Client claims that connection has not changed, make sure
            connPtr = REINTERPRET_CAST(RConnection*, connectionPtr);
            error = connPtr->GetIntSetting ( _L("IAP\\Id"), iapId );
            // If reading failed or the IAP has changed since last query -> set newConn bit
            if ((error != KErrNone) || (iLastIapId != iapId))
            {
                newConn = ETrue;
                iLastIapId = iapId;
            }
        }
        else if (iLastIapId == 0)
        {
            RConnection* connPtr = NULL;
            TUint32 iapId = 0;
            
            // Initialize last IAP variable for the first transaction
            connPtr = REINTERPRET_CAST(RConnection*, connectionPtr);
            error = connPtr->GetIntSetting ( _L("IAP\\Id"), iapId );
            if ((error != KErrNone) || (iLastIapId != iapId))
            {
                iLastIapId = iapId;
            }
        }
        
        // Set aNewConn flag
        connInfo.SetPropertyL(stringPool.StringF(HttpFilterCommonStringsExt::EHttpNewConnFlag,
                              HttpFilterCommonStringsExt::GetTable()), THTTPHdrVal((TBool)newConn));
    }
}

//  End of File