diff -r 000000000000 -r b16258d2340f httpfilters/httpfilterproxy/Src/HttpFilterProxy.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/httpfilters/httpfilterproxy/Src/HttpFilterProxy.cpp Tue Feb 02 01:09:52 2010 +0200 @@ -0,0 +1,651 @@ +/* +* 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: Proxy filter +* +*/ + + + +// INCLUDE FILES +#include +#include +#include +#include + +// User Includes +#include "httpfilterproxy.h" +#include "httpfiltercommonstringsext.h" + +// EXTERNAL DATA STRUCTURES + +// EXTERNAL FUNCTION PROTOTYPES +void PanicHttpFiltersProxy(TInt aErr = 0); + +// CONSTANTS +const TInt KProxyOrderOffset = 20; +// MACROS + +// LOCAL CONSTANTS AND MACROS + +// MODULE DATA STRUCTURES + +// LOCAL FUNCTION PROTOTYPES + +// FORWARD DECLARATIONS + +// ============================= LOCAL FUNCTIONS =============================== + +// ----------------------------------------------------------------------------- +// LocalHostCheckL +// If the host is a local host, then remove the proxy property. Returns ETrue +// if the transaction request URI was for a localhost. +// ----------------------------------------------------------------------------- +// +TBool LocalHostCheckL(RHTTPTransaction& aTransaction, RStringPool& aStringPool) + { + _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) + { + // request is for localhost, explicitly state that this transaction + // must not be sent to proxy. + RStringF proxyUsageStrF = aStringPool.StringF(HTTP::EProxyUsage, + RHTTPSession::GetTable()); + + RStringF dontUseProxyStrF = aStringPool.StringF(HTTP::EDoNotUseProxy, + RHTTPSession::GetTable()); + + aTransaction.PropertySet().RemoveProperty(proxyUsageStrF); + aTransaction.PropertySet().SetPropertyL(proxyUsageStrF, dontUseProxyStrF); + + //RStringF proxyAddrStrF = aStringPool.StringF(HTTP::EProxyAddress, + // RHTTPSession::GetTable()); + + //aTransaction.PropertySet().RemoveProperty(proxyAddrStrF); + return ETrue; + } + return EFalse; + } + +// ============================ MEMBER FUNCTIONS =============================== + +// ----------------------------------------------------------------------------- +// CHttpFilterProxy::CHttpFilterProxy +// C++ default constructor can NOT contain any code, that +// might leave. +// ----------------------------------------------------------------------------- +// +CHttpFilterProxy::CHttpFilterProxy(RHTTPSession* aSession) +{ + __ASSERT_DEBUG(aSession != NULL, PanicHttpFiltersProxy()); + iSession = aSession; +} + + +// ------------------------------------------------------------------------------------------ +// CHttpFilterProxy::ConstructL +// Symbian 2nd phase constructor can leave. +// ------------------------------------------------------------------------------------------ +// +void CHttpFilterProxy::ConstructL() +{ + iStringPool = iSession->StringPool(); + iConnInfo = iSession->ConnectionInfo(); + + // Added to fix panic when Proxy filter is used outside the browser initiated HTTP Framework. + iSession->StringPool().OpenL(HttpFilterCommonStringsExt::GetTable()); + + // 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 - KProxyOrderOffset,// The position of the filter in the queue + iStringPool.StringF(HttpFilterCommonStringsExt::EProxyFilter,RHTTPSession::GetTable())); //The name of the filter to add + + // register for notification of KErrNotReady error codes + // this allows us to re-start the connection if it fails + iSession->FilterCollection().AddFilterL(*this, KErrNotReady, MHTTPFilter::ETidyUp -1, iStringPool.StringF(HttpFilterCommonStringsExt::EProxyFilter,RHTTPSession::GetTable())); +} + +//--------------------------------------------------------------------------------------------- +// Destructor +//---------------------------------------------------------------------------------------------- +// +CHttpFilterProxy::~CHttpFilterProxy() +{ + // Cleanup strings. + iProxyAddress.Close(); + iExceptions.Close(); + +/* +// Closing RSocketServ is causing crash in SDK Applications. SDK Apps will have to close RSocketServ and RConnection after closing CHTTPSession. +// It is not needed to close connection as soon as the CHttpConnectionManager close connection by +// calling CHttpConnectionManager::CloseConnection() + if(iFilterOwnsConnection) + { + // Close ESOCK handles + iConnection.Close(); + iSocketServ.Close(); + } +*/ +} + +// --------------------------------------------------------------------------------------------- +// CHttpFilterProxy::InstallFilterL +// Two-phased constructor. This function replaces NewL. +// --------------------------------------------------------------------------------------------- +// +CHttpFilterProxy* CHttpFilterProxy::InstallFilterL(TAny* aSession) +{ + __ASSERT_DEBUG(aSession != NULL, PanicHttpFiltersProxy()); + RHTTPSession* session = REINTERPRET_CAST(RHTTPSession*, aSession); + CHttpFilterProxy* filter = new (ELeave) CHttpFilterProxy( session ); + CleanupStack::PushL(filter); + filter->ConstructL(); + CleanupStack::Pop(filter); + return filter; +} + +// --------------------------------------------------------------------------------------------- +// CHttpFilterProxy::MHFLoad +// Called when the filter is being added to the session's filter queue. +// --------------------------------------------------------------------------------------------- +// +void CHttpFilterProxy::MHFLoad(RHTTPSession, THTTPFilterHandle) +{ + ++iLoadCount; +} + +// ---------------------------------------------------------------------------------------------- +// CHttpFilterProxy::MHFUnload +// Called when the filter is being removed from a session's filter queue. +// ---------------------------------------------------------------------------------------------- +// +void CHttpFilterProxy::MHFUnload(RHTTPSession /*aSession*/, THTTPFilterHandle /*aFilterHandler*/) +{ + __ASSERT_DEBUG(iLoadCount >= 0, PanicHttpFiltersProxy()); + if (--iLoadCount) + { + return; + } + delete this; +} + +// ------------------------------------------------------------------------------------------------ +// CHttpFilterProxy::MHFRunL +// Process a transaction event. +// ------------------------------------------------------------------------------------------------ +// +void CHttpFilterProxy::MHFRunL(RHTTPTransaction aTransaction, + const THTTPEvent& aEvent) + { + switch(aEvent.iStatus) + { + case THTTPEvent::ESubmit: + { + if (LocalHostCheckL(aTransaction, iStringPool)) + { + return; + } + SetProxyL(aTransaction); + } + break; + + case KErrNotReady: + { + if (LocalHostCheckL(aTransaction, iStringPool)) + { + return; + } + if(iFilterOwnsConnection) + { + // we must re-start the RConnection + TInt err = iConnection.Start(); + if (err == KErrAlreadyExists) + { + // the KErrNotReady must have come from elsewhere + return; + } + + User::LeaveIfError(err); + + // re-submit the transaction + aTransaction.Cancel(); + aTransaction.SubmitL(); + } + break; + } + + default: + break; + } + + } + +// ----------------------------------------------------------------------------- +// CHttpFilterProxy::MHFRunError +// Process an error that occured while processing the transaction. +// ----------------------------------------------------------------------------- +// +TInt CHttpFilterProxy::MHFRunError(TInt /*aError*/, + RHTTPTransaction aTransaction, + const THTTPEvent& /*aEvent*/) +{ + // Cleanup strings. + iProxyAddress.Close(); + iExceptions.Close(); + aTransaction.Fail(); + return KErrNone; +} + +// ----------------------------------------------------------------------------- +// CHttpFilterProxy::MHFSessionRunL +// Process a session event. +// ----------------------------------------------------------------------------- +// +void CHttpFilterProxy::MHFSessionRunL(const THTTPSessionEvent& /*aEvent*/) +{ +} + +// ----------------------------------------------------------------------------- +// CHttpFilterProxy::MHFSessionRunError +// Called when MHFRunL leaves from a session event. +// ----------------------------------------------------------------------------- +// +TInt CHttpFilterProxy::MHFSessionRunError(TInt aError, const THTTPSessionEvent& /*aEvent*/) +{ + return aError; +} + +// ----------------------------------------------------------------------------- +// CHttpFilterProxy::SetProxyL +// 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. If a proxy property has already been +// set by a higher filter or by the client, then those settings are preferred over +// CommsDB. +// ----------------------------------------------------------------------------- +// +void CHttpFilterProxy::SetProxyL(const RHTTPTransaction aTransaction) +{ + THTTPHdrVal isNewConn, proxyAddress; + + // If connection has been disconnected the user could change Access Point, so let's + // check if a new connection has been used. + TBool ret = iConnInfo.Property (iStringPool.StringF(HttpFilterCommonStringsExt::EHttpNewConnFlag, + HttpFilterCommonStringsExt::GetTable()), isNewConn); + + if (ret && isNewConn.Type() == THTTPHdrVal::KTIntVal && (isNewConn.Int() == 1)) + { + iUsage = EFalse; + // Read proxy info from the CommDB + ReadProxyInfoL(iStringPool, + iUsage, + iProxyAddress, + iExceptions); + } + else + { + TBool useProxy( ETrue ); + THTTPHdrVal proxyUsageVal; + + // Is the property for proxy usage set? + TBool hasUsageValue = iConnInfo.Property(iStringPool.StringF(HTTP::EProxyUsage, + RHTTPSession::GetTable()), proxyUsageVal); + + // If the property is set, is it EUseProxy + if (hasUsageValue) + { + useProxy = ( proxyUsageVal.StrF().Index(RHTTPSession::GetTable()) == HTTP::EUseProxy); + } + + // Use proxy if the property value is EUseProxy or no property is set. + if (useProxy || !hasUsageValue) + { + THTTPHdrVal proxyAddressVal; + TBool hasValue = iConnInfo.Property(iStringPool.StringF(HTTP::EProxyAddress, + RHTTPSession::GetTable()), proxyAddressVal); + if (!hasValue) + { + // The proxyAddress has not been set, so Read proxy info from the CommDB + ReadProxyInfoL(iStringPool, + iUsage, + iProxyAddress, + iExceptions); + + } + else + { + // Now get the proxy address... + iProxyAddress = proxyAddressVal.StrF().Copy(); + iUsage = ETrue; + } + } +// } + } + + // We should not use proxy if the uri matches to one of exceptions from the exception list + // In this case the Origing server will be used + + ExcptionsCompare(aTransaction); + + // Respect proxy settings already defined by client or higher HTTP filter + THTTPHdrVal proxyUsage; // Check if property present or not present, not the value. + if ( !iConnInfo.Property(iStringPool.StringF(HTTP::EProxyUsage, + RHTTPSession::GetTable()), proxyUsage)) + { + + // Set the proxy address and proxy Usage + proxyAddress = THTTPHdrVal(iProxyAddress); + + iConnInfo.RemoveProperty(iStringPool.StringF(HTTP::EProxyAddress, + RHTTPSession::GetTable())); + iConnInfo.SetPropertyL(iStringPool.StringF(HTTP::EProxyAddress, + RHTTPSession::GetTable()), proxyAddress); + + iConnInfo.RemoveProperty(iStringPool.StringF(HTTP::EProxyUsage, + RHTTPSession::GetTable())); + if (iUsage) + { + iConnInfo.SetPropertyL(iStringPool.StringF(HTTP::EProxyUsage, + RHTTPSession::GetTable()), iStringPool.StringF(HTTP::EUseProxy, + RHTTPSession::GetTable())); + } + else + { + iConnInfo.SetPropertyL(iStringPool.StringF(HTTP::EProxyUsage, + RHTTPSession::GetTable()), iStringPool.StringF(HTTP::EDoNotUseProxy, + RHTTPSession::GetTable())); + } + + } + + + // Cleanup strings. + iProxyAddress.Close(); + iExceptions.Close(); +} + + +// ----------------------------------------------------------------------------- +// CHttpFilterProxy::ReadProxyInfoL +// Purpose: Reads the Proxy information from the comms database. +// Gives the Proxy usage, a proxy address (:), +// and proxy exceptions through the output arguments. +// ----------------------------------------------------------------------------- +// +void CHttpFilterProxy::ReadProxyInfoL(const RStringPool aStringPool, + TBool& aUsage, + RStringF& aProxyAddress, + RStringF& aExceptions) + +{ + // Let's find Internet Access point ID (ServiceId) in use from the RConnection associated with the HTTP framework + THTTPHdrVal connValue; + TUint32 serviceId; + TUint pushCount = 0; + RConnection* connPtr = NULL; + THTTPHdrVal iapId; + TCommDbConnPref pref; + TBool hasValue = iConnInfo.Property (aStringPool.StringF(HTTP::EHttpSocketConnection, RHTTPSession::GetTable()), + connValue); + + if (hasValue && connValue.Type() == THTTPHdrVal::KTIntVal) + { + connPtr = REINTERPRET_CAST(RConnection*, connValue.Int()); + } + else + { + // Connect to ESOCK and open connection handle + User::LeaveIfError(iSocketServ.Connect()); + User::LeaveIfError(iConnection.Open(iSocketServ)); + + TBool ret = iConnInfo.Property (aStringPool.StringF(HttpFilterCommonStringsExt::EAccessPointID, HttpFilterCommonStringsExt::GetTable()), + iapId); + if (ret && (iapId.Type() == THTTPHdrVal::KTIntVal) && (iapId.Int() != 0) ) + { + pref.SetDialogPreference( ECommDbDialogPrefDoNotPrompt ); + pref.SetIapId( iapId.Int() ); + //pref.SetBearerSet( ECommDbBearerGPRS ); + pref.SetDirection(ECommDbConnectionDirectionOutgoing); + TInt err = iConnection.Start(pref); + if ( err != KErrNone ) + User::LeaveIfError(iConnection.Start()); + } + else + { + // start the connection - note that this thread will be blocked until the connection is established. + User::LeaveIfError(iConnection.Start()); + } + + connPtr = &iConnection; + + // set the ESOCK handles as session properties after successful connection + iConnInfo.SetPropertyL(aStringPool.StringF(HTTP::EHttpSocketServ, RHTTPSession::GetTable()), iSocketServ.Handle()); + iConnInfo.SetPropertyL(aStringPool.StringF(HTTP::EHttpSocketConnection, RHTTPSession::GetTable()), reinterpret_cast(&iConnection)); + + iFilterOwnsConnection = ETrue; + } + + // Retrieve the service Id from the RConnection ; "/ + User::LeaveIfError(connPtr->GetIntSetting(_L("IAP\\IAPService"), serviceId)); + + // Retrieve the service Type from the RConnection + HBufC* serviceType16 = HBufC::NewL(KCommsDbSvrMaxFieldLength); + CleanupStack::PushL(serviceType16); + pushCount++; + TPtr serviceTypePtr16 = serviceType16->Des(); + User::LeaveIfError(connPtr->GetDesSetting(_L("IAP\\IAPServiceType"), serviceTypePtr16)); + + // Open the Comms DB with the IAP style + CCommsDatabase* db=CCommsDatabase::NewL(EDatabaseTypeUnspecified); + CleanupStack::PushL(db); + pushCount++; + + // Opens a view on records in the Proxies table with a specified range of service types and service IDs. + // Proxies records are included that have matching service types and IDs. + // When the use of the view object is complete, it should be popped from the cleanup stack, and deleted. + CCommsDbTableView* pView = db->OpenViewOnProxyRecordLC(serviceId, serviceTypePtr16); + + pushCount++; + TInt err = pView->GotoFirstRecord(); + aUsage = ETrue; + // if there is some other DB error. + if ( err != KErrNotFound && err != KErrNone ) + { + User::LeaveIfError( err ); + } + if ( err == KErrNotFound ) + {// setting to EFalse because proxy table view does not exisit, was not created during Access point creation? + aUsage = EFalse; + } + else + // no need to keep going as not Proxy will be used. + { + // Read the proxy usage flag from the selected Proxy record. + pView->ReadBoolL(TPtrC(PROXY_USE_PROXY_SERVER), aUsage); + + // COntinue only if the proxy usage flag is set + if (aUsage) + { + // Read the server name specified in the selected Proxy record. + // The proxyAddress will be build based on the serverName and the port number + // separated with ':' + HBufC* serverName = pView->ReadLongTextLC(TPtrC(PROXY_SERVER_NAME)); + pushCount++; + TPtr serverNamePtr16 = serverName->Des(); + serverNamePtr16.Trim(); + + // Continue only if we have a proxy name + if (serverNamePtr16.Length() > 0 && serverNamePtr16.Ptr() != NULL) + { + // Read the port number specified in the selected Proxy record + TUint32 portNumber = 8080; // default port number + TInt length = 1; // add 1 for the separator ':' + pView->ReadUintL(TPtrC(PROXY_PORT_NUMBER), portNumber); + // calculate the length of portNumber + + if (portNumber == 0) + { + portNumber = 8080; + } + + TUint32 portNumSave = portNumber; + while (portNumSave > 0) + { + portNumSave = portNumSave/10; + length++; + } + // convert number to string & add to the server name. We should get : + HBufC8* proxyAddress8 = HBufC8::NewL(serverNamePtr16.Length() + length); + CleanupStack::PushL(proxyAddress8); + pushCount++; + TPtr8 proxyAddressPtr8 = proxyAddress8->Des(); + proxyAddressPtr8.Copy(serverNamePtr16); + _LIT(KSeparator, ":"); + proxyAddressPtr8.Append(KSeparator); + proxyAddressPtr8.AppendNum((TInt)portNumber); + + // Set gateway as a service number - this is the proxy address + aProxyAddress = aStringPool.OpenFStringL(proxyAddressPtr8); + + // Read the server name specified in the selected Proxy record. + HBufC* exceptions16 = pView->ReadLongTextLC(TPtrC(PROXY_EXCEPTIONS)); + pushCount++; + TPtr exceptionsPtr16 = exceptions16->Des(); + // Copy to 8-bits... + HBufC8* exceptions8 = HBufC8::NewL(exceptionsPtr16.Length()); + CleanupStack::PushL(exceptions8); + pushCount++; + TPtr8 exceptionsPtr8 = exceptions8->Des(); + exceptionsPtr8.Copy(exceptionsPtr16); + + // Set gateway as a service number - this is the proxy address + aExceptions = aStringPool.OpenFStringL(exceptionsPtr8); + } + else + { + aUsage = EFalse; + } + } + } + // All done - clean up + CleanupStack::PopAndDestroy(pushCount); //pView, serverType16, db, serverName, proxyAddress8, exceptions8 exceptions16 +} + +//--------------------------------------------------------------------------------- +// +// Get exception from the list of exceptions +// Returns ETrue if there is at least one exception in the list. +// Returns EFalse if list of exceptions is empty or there is no exceptions in the list any more. +//--------------------------------------------------------------------------------- +TBool CHttpFilterProxy::GetException(TPtr8& aException,TInt& aStartIndex) +{ + TBool done; + TPtrC8 exceptionsDesC = iExceptions.DesC(); + TPtr8 exceptionsDes((TUint8*)exceptionsDesC.Ptr(), exceptionsDesC.Length(),exceptionsDesC.Length()); + + exceptionsDes.TrimAll(); + // get part of string starting from aStartIndex. aStartIndex =0 when it is called the first time. + TPtrC8 desPtr = exceptionsDes.Mid(aStartIndex); + + //The offset of the exception position from the beginning of the exception list + const TChar separator(';'); + TInt position = desPtr.Locate(separator); + if (position != KErrNotFound) + { + // Extracts a portion of the data starting from the beggining + // Get the rest of the descriptor without the separator that we have found + aException.Set((unsigned char*)desPtr.Ptr(), position, position); + aStartIndex = position + 1; + done = ETrue; + } + else + { + aException.Set((unsigned char*)desPtr.Ptr(), desPtr.Length(), desPtr.Length()); + done = EFalse; + } + return done; +} + +// ----------------------------------------------------------------------------- +// CHttpFilterProxy::ExcptionsCompare +// Compare each exception from the exception list against the current uri. +// ----------------------------------------------------------------------------- +// +void CHttpFilterProxy::ExcptionsCompare(const RHTTPTransaction aTransaction) +{ + if (iUsage) + { + TBool isFound = ETrue; + TInt index = 0; + TInt loopCount = 0; + TPtr8 exception (NULL, 0,0); + // Let's get uri for this transaction to comapre the current uri with an exception. + // If the current uri has an exception for proxy set proxy usage to EDoNotUseProxy. + RHTTPRequest req = aTransaction.Request(); + TUriC8 originalUri = req.URI(); + const TDesC8& uriHost = originalUri.UriDes(); + + TPtrC8 exceptionsDes = iExceptions.DesC(); + if (exceptionsDes.Length() != 0) + { + // at least one exception has been found in the list of exceptions + while (isFound) + { + loopCount++; + isFound = GetException(exception, index); + if (exception.Compare(uriHost) == NULL) + { + iUsage = EFalse; + isFound = EFalse; + } + } //while + } + } +} + +// End of File