httpfilters/httpfilterauthentication/Src/HttpFilterAuthentication.cpp
changeset 0 b16258d2340f
child 6 fa2fd8b2d6cc
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/httpfilters/httpfilterauthentication/Src/HttpFilterAuthentication.cpp	Tue Feb 02 01:09:52 2010 +0200
@@ -0,0 +1,1151 @@
+/*
+* 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:  Authentication filter
+*
+*/
+
+
+
+// INCLUDE FILES
+#include <e32std.h>
+#include <e32math.h>
+#include <Uri8.h>
+#include <http/rhttpsession.h>
+#include <http/rhttptransaction.h>
+#include <http/rhttpheaders.h>
+#include <httpstringconstants.h>
+#include <tconvbase64.h>
+
+// User Includes
+#include "HttpFilterAuthentication.h"
+#include "httpfiltercommonstringsext.h"
+#include "httperr.h"
+#include "HttpFilterAuthenticationLogger.h"
+
+// EXTERNAL DATA STRUCTURES
+
+// EXTERNAL FUNCTION PROTOTYPES
+
+// CONSTANTS
+
+// MACROS
+
+// LOCAL CONSTANTS AND MACROS
+
+// MODULE DATA STRUCTURES
+
+// LOCAL FUNCTION PROTOTYPES
+
+// FORWARD DECLARATIONS
+
+// ============================= LOCAL FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// PanicAuthenticationFilter
+// Panic
+// Returns: void
+// -----------------------------------------------------------------------------
+//
+void PanicAuthenticationFilter( TInt aErr = 0 )
+    {
+    User::Panic( _L( "HTTP FILTER AUTHENTICATION" ), aErr );
+    }
+
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// CHttpFilterAuthentication::CHttpFilterAuthentication
+// C++ default constructor can NOT contain any code, that
+// might leave.
+// -----------------------------------------------------------------------------
+//
+CHttpFilterAuthentication::CHttpFilterAuthentication( RHTTPSession* aSession, TBool aIsProxy )
+    {
+    __ASSERT_DEBUG( aSession != NULL, PanicAuthenticationFilter() );
+    iIsProxy = aIsProxy;
+    iSession = aSession;
+    iStringPool = ( *aSession ).StringPool();
+
+   
+    }
+
+
+// -----------------------------------------------------------------------------
+// CHttpFilterAuthentication::ConstructL
+// Symbian 2nd phase constructor can leave.
+// -----------------------------------------------------------------------------
+//
+void CHttpFilterAuthentication::ConstructL( RHTTPSession aSession )
+    {
+
+    // Register the filter. We only care about 401 status codes where
+    // there's a WWW-Authenticate header (which the RFC says MUST be
+    // present). If we don't fire (e.g. due to a missing header) then
+    // the transaction will fail if we ignore it, which is what we
+    // want.
+
+    // Register for submit events, to extract credentials from the URI
+    // and to pre-supply credentials for basic
+    // authentication. Registered as EStatusCodeHandler+1 so that it
+    // isn't offered submit events originating from the 401 handler
+    // (which is harmless but slow and confusing)
+    
+     iSession->StringPool().OpenL( HttpFilterCommonStringsExt::GetTable() );
+
+    if ( iIsProxy )
+        {
+        iHttpStringAuthorization = HTTP::EProxyAuthorization;
+        iHttpStringAuthenticate = HTTP::EProxyAuthenticate;
+        iStatusCode = HTTPStatus::EProxyAuthenticationRequired;   // 407
+        iRealmStr = iStringPool.StringF( HttpFilterCommonStringsExt::EProxyRealm, HttpFilterCommonStringsExt::GetTable() );
+        iUsernameStr = iStringPool.StringF( HttpFilterCommonStringsExt::EProxyUsername, HttpFilterCommonStringsExt::GetTable() );
+        iPasswordStr = iStringPool.StringF( HttpFilterCommonStringsExt::EProxyPassword, HttpFilterCommonStringsExt::GetTable() );
+        }
+
+    else
+        {
+        iHttpStringAuthorization = HTTP::EAuthorization;
+        iHttpStringAuthenticate = HTTP::EWWWAuthenticate;
+        iStatusCode = HTTPStatus::EUnauthorized;       // 401
+        iRealmStr = iStringPool.StringF( HTTP::ERealm, RHTTPSession::GetTable() );
+        iUsernameStr = iStringPool.StringF( HTTP::EUsername, RHTTPSession::GetTable() );
+        iPasswordStr = iStringPool.StringF( HTTP::EPassword, RHTTPSession::GetTable() );
+        }
+        
+    aSession.FilterCollection().AddFilterL( *this,
+                                            THTTPEvent::ESubmit,
+                                            RStringF(),
+                                            KAnyStatusCode,
+                                            EStatusCodeHandler + 1,
+                                            iStringPool.StringF( HTTP::EAuthentication, RHTTPSession::GetTable() ) );
+
+    // And for 401 status codes, for obvious reasons.
+    aSession.FilterCollection().AddFilterL( *this,
+                                            THTTPEvent::EGotResponseHeaders,
+                                            iStringPool.StringF( iHttpStringAuthenticate, RHTTPSession::GetTable() ),
+                                            iStatusCode,
+                                            EStatusCodeHandler,
+                                            iStringPool.StringF( HTTP::EAuthentication, RHTTPSession::GetTable() ) );
+
+    }
+
+// Destructor
+CHttpFilterAuthentication::~CHttpFilterAuthentication()
+    {
+    TInt credCount = iCredentials.Count();
+
+    for ( TInt ii = 0; ii < credCount; ++ii )
+        {
+        TCredentials& cred = iCredentials[ ii ];
+
+        // Close all owned strings now while we can get a string pool handle.
+        iStringPool.String( cred.iUser ).Close();
+        iStringPool.String( cred.iPassword ).Close();
+        iStringPool.StringF( cred.iURI ).Close();
+        iStringPool.String( cred.iRealm ).Close();
+        }
+
+    iCredentials.Close();
+    }
+
+// -----------------------------------------------------------------------------
+// CHttpFilterAuthentication::InstallFilterL
+// Two-phased constructor. This function replaces NewL.
+// -----------------------------------------------------------------------------
+//
+CHttpFilterAuthentication* CHttpFilterAuthentication::InstallFilterL( TAny* aAuthenticationParams )
+    {
+    __ASSERT_DEBUG( aAuthenticationParams != NULL, PanicAuthenticationFilter() );
+    TAuthenticationParams* authParams = REINTERPRET_CAST( TAuthenticationParams*, aAuthenticationParams );
+    __ASSERT_DEBUG( authParams->iSession != NULL, PanicAuthenticationFilter() );
+    CHttpFilterAuthentication* filter = new ( ELeave ) CHttpFilterAuthentication( authParams->iSession, authParams->iIsProxy );
+    CleanupStack::PushL( filter );
+    filter->ConstructL( *( authParams->iSession ) );
+    CleanupStack::Pop( filter );
+    return filter;
+    }
+
+// -----------------------------------------------------------------------------
+// CHttpFilterAuthentication::MHFLoad
+// Called when the filter is being added to the session's filter queue.
+// -----------------------------------------------------------------------------
+//
+void CHttpFilterAuthentication::MHFLoad( RHTTPSession, THTTPFilterHandle )
+    {
+    ++iLoadCount;
+    }
+
+// -----------------------------------------------------------------------------
+// CHttpFilterAuthentication::MHFUnload
+// Called when the filter is being removed from a session's filter queue.
+// -----------------------------------------------------------------------------
+//
+void CHttpFilterAuthentication::MHFUnload( RHTTPSession /*aSession*/, THTTPFilterHandle /*aFilterHandler*/ )
+    {
+    __ASSERT_DEBUG( iLoadCount >= 0, PanicAuthenticationFilter() );
+
+    if ( --iLoadCount )
+        {
+        return ;
+        }
+
+    delete this;
+    }
+
+
+// -----------------------------------------------------------------------------
+// CHttpFilterAuthentication::MHFRunL
+// Process a transaction event.
+// -----------------------------------------------------------------------------
+//
+void CHttpFilterAuthentication::MHFRunL( RHTTPTransaction aTransaction,
+        const THTTPEvent& aEvent )
+    {
+    switch ( aEvent.iStatus )
+        {
+
+        case THTTPEvent::ESubmit:
+            {
+            SubmitL( aTransaction );
+            break;
+            }
+
+        case THTTPEvent::EGotResponseHeaders:
+            {
+            HandleTransactionL( aTransaction );
+            break;
+            }
+
+        default:
+            {
+            __ASSERT_DEBUG( EFalse, PanicAuthenticationFilter() );
+            break;
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CHttpFilterAuthentication::MHFRunError
+// Process an error that occured while processing the transaction.
+// -----------------------------------------------------------------------------
+//
+TInt CHttpFilterAuthentication::MHFRunError( TInt /*aError*/,
+        RHTTPTransaction /*aTransaction*/,
+        const THTTPEvent& /*aEvent*/ )
+    {
+    // aTransaction.Fail(); This causes a crash in Symbian code
+    return KErrNone;
+    }
+
+// -----------------------------------------------------------------------------
+// CHttpFilterAuthentication::MHFSessionRunL
+// Process a session event.
+// -----------------------------------------------------------------------------
+//
+void CHttpFilterAuthentication::MHFSessionRunL( const THTTPSessionEvent& /*aEvent*/ )
+    {}
+
+// -----------------------------------------------------------------------------
+// CHttpFilterAuthentication::MHFSessionRunError
+// Called when MHFRunL leaves from a session event.
+// -----------------------------------------------------------------------------
+//
+TInt CHttpFilterAuthentication::MHFSessionRunError( TInt aError, const THTTPSessionEvent& /*aEvent*/ )
+    {
+    return aError;
+    }
+
+
+// -----------------------------------------------------------------------------
+// CHttpFilterAuthentication::HandleTransactionL
+// Provides a central point for all Tranaction handling.
+// -----------------------------------------------------------------------------
+//
+void CHttpFilterAuthentication::HandleTransactionL( RHTTPTransaction aTransaction )
+    {
+    AUTHLOGGER_ENTERFN( "CHttpFilterAuthentication::HandleTransactionL" );
+
+    // Find if we have credentials in the transaction's properties, and remove them from the list
+    // (but not from the properties)
+    // Find if there are WWWAuthenticate or ProxyAuthenticate headers in the request,
+    // and replace the realm property with what came from the request.
+    THTTPHdrVal realmVal;
+    TInt cred = KErrNotFound;
+
+    if ( aTransaction.PropertySet().Property( iRealmStr, realmVal ) )
+        {
+        if ( iIsProxy )
+            {
+            cred = FindCredentialsForRealm( realmVal );
+            }
+
+        else
+            {
+            cred = FindCredentials( realmVal, aTransaction.Request().URI() );
+            }
+        }
+
+    if ( cred != KErrNotFound )
+        {
+        RemoveCredentialsFromList( cred );
+        }
+
+    RStringF wwwAuthHeader = iStringPool.StringF( iHttpStringAuthenticate, RHTTPSession::GetTable() );
+    RHTTPHeaders headers( aTransaction.Response().GetHeaderCollection() );
+
+    if ( iIsProxy )
+        {
+        AddProxyRealmToTransactionL( aTransaction );
+        }
+
+    else
+        {
+        TInt headerPart = FindHeaderPartToUseL( aTransaction );
+
+        if ( headerPart == KErrNotFound )
+            {
+			aTransaction.Cancel();
+			aTransaction.SendEventL(KErrHttpDecodeUnknownAuthScheme, THTTPEvent::EIncoming, THTTPFilterHandle::ECurrentFilter);
+			return;
+            }
+
+        THTTPHdrVal authTypeParam;
+
+        if ( headers.GetField( wwwAuthHeader, headerPart, authTypeParam ) == KErrNone &&
+             headers.GetParam( wwwAuthHeader, iRealmStr, realmVal, headerPart ) == KErrNone )
+            {
+            TInt cred = FindCredentialsForRealm( realmVal.Str(), EFalse );
+
+            if( cred != KErrNotFound )
+                // We have already met with this realm. Check that it came from the same host.
+                {
+                const TUriC8& uri = aTransaction.Request().URI();
+                TUriParser8 uriCred;
+
+                uriCred.Parse( iStringPool.StringF(iCredentials[cred].iURI).DesC() );
+
+                if( !uriCred.Extract( EUriHost ).CompareF( uri.Extract( EUriHost ) ) )
+                    // the host and the realm are the same as previously
+                    // we most probably authenticated to this server
+                    // use the previously sent credentials
+                    {
+                    aTransaction.PropertySet().RemoveProperty( iRealmStr );
+                    aTransaction.PropertySet().RemoveProperty( iUsernameStr );
+                    aTransaction.PropertySet().RemoveProperty( iPasswordStr );
+
+                    aTransaction.PropertySet().SetPropertyL( iRealmStr, realmVal );
+
+                    SetPropertyL( aTransaction, iUsernameStr, iStringPool.String( iCredentials[ cred ].iUser).DesC() );
+                    SetPropertyL( aTransaction, iPasswordStr, iStringPool.String( iCredentials[ cred ].iPassword).DesC() );
+
+                    // 'stale' is used in digest authentication only. But we can
+                    // take its advantage here as well. Because we are working
+                    // in the same protection space as before thus we know 
+                    // the uname/pwd -> don't need to ask it again from user,
+                    // or show dialog the authentication failed.
+                    SetPropertyL( aTransaction, 
+                                  iSession->StringPool().StringF( HTTP::EStale, 
+                                                                  RHTTPSession::GetTable() ),
+                                  KNullDesC8 );
+                    }
+                }
+            else
+                {
+                aTransaction.PropertySet().RemoveProperty( iRealmStr );
+                aTransaction.PropertySet().SetPropertyL( iRealmStr, realmVal );
+
+                SetBasicProperty( aTransaction );
+                }
+            }
+        }
+    AUTHLOGGER_LEAVEFN( "CHttpFilterAuthentication::HandleTransactionL" );
+    }
+
+
+// -----------------------------------------------------------------------------
+// CHttpFilterAuthentication::SubmitL
+// Function to handle Submit events. We need to remove any username and password from the URI.
+// -----------------------------------------------------------------------------
+//
+void CHttpFilterAuthentication::SubmitL( RHTTPTransaction aTransaction )
+    {
+    // From RFC 2617:
+    // A client SHOULD assume that all paths at or deeper than the depth of
+    // the last symbolic element in the path field of the Request-URI also
+    // are within the protection space specified by the Basic realm value of
+    // the current challenge. A client MAY preemptively send the
+    // corresponding Authorization header with requests for resources in
+    // that space without receipt of another challenge from the server.
+
+    // First time the transaction is submitted, we check if the credentials are appended to the url,
+    // remove it from the url and add it to the transaction's properties.
+    // Then we check if there are credentials in the transaction's properties,
+    // and add it to the credentials list.
+    // Last thing is to lookup the list for credentials for:
+    //     WWWAuthenticate: match the URI.
+    //     ProxyAuthenticate: match the realm.
+    TInt cred = KErrNotFound;
+    // Get credentials from URI, only for wwwAuthenticate
+
+    // we don't need this property anymore
+    aTransaction.PropertySet().RemoveProperty( iStringPool.StringF( HTTP::EBasic,
+                                               RHTTPSession::GetTable() ) );
+
+    if ( !iIsProxy )
+        {
+        GetCredentialsFromURIL( aTransaction );
+        }
+
+    // If there are credentials in the transaction properties, add them to the list
+    GetCredentialsFromPropertiesL( aTransaction );
+
+    if ( iIsProxy )
+        {
+        THTTPHdrVal realmVal;
+
+        if ( aTransaction.PropertySet().Property( iRealmStr, realmVal ) )
+            {
+            cred = FindCredentialsForRealm( realmVal.Str() );
+            }
+
+        else
+            {
+            cred = FindCredentialsForProxy();
+            }
+        }
+
+    else
+        {
+        // If we have credentials for this URL, add them
+        cred = FindCredentialsForURI( aTransaction.Request().URI() );
+        }
+
+    if ( cred != KErrNotFound )
+        {
+        EncodeBasicAuthL( iStringPool.String( iCredentials[ cred ].iUser ),
+                          iStringPool.String( iCredentials[ cred ].iPassword ),
+                          aTransaction );
+
+        if( !iIsProxy )
+            {
+            SetPropertyL( aTransaction, iUsernameStr, iStringPool.String( iCredentials[ cred ].iUser ).DesC() );
+            SetPropertyL( aTransaction, iPasswordStr, iStringPool.String( iCredentials[ cred ].iPassword ).DesC() );
+            SetPropertyL( aTransaction, iRealmStr, iStringPool.String( iCredentials[ cred ].iRealm ).DesC() );
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CHttpFilterAuthentication::FindCredentials
+// Search list for matching credentials.
+// -----------------------------------------------------------------------------
+//
+TInt CHttpFilterAuthentication::FindCredentials( const RString& aRealm,
+        const TUriC8& aURI )
+    {
+    TInt count = iCredentials.Count();
+
+    for ( TInt cred = 0; cred < count; ++cred )
+        {
+        if ( iCredentials[ cred ].iRealm == aRealm )
+            {
+            TUriParser8 parser;
+            parser.Parse( iStringPool.StringF( iCredentials[ cred ].iURI ).DesC() );
+
+            if ( !parser.Compare(aURI, EUriScheme) &&
+                 !parser.Compare( aURI, EUriHost ) &&
+                 ( ( !parser.Compare( aURI, EUriPort ) )
+                   || ( !parser.IsPresent( EUriPort ) &&
+                        !aURI.IsPresent( EUriPort ) ) ) )
+                {
+                return cred;
+                }
+            }
+        }
+    return KErrNotFound;
+    }
+
+// -----------------------------------------------------------------------------
+// CHttpFilterAuthentication::FindCredentialsForURI
+// Searches list for credentials that can be used with this URI
+// -----------------------------------------------------------------------------
+//
+TInt CHttpFilterAuthentication::FindCredentialsForURI( const TUriC8& aURI )
+    {
+    // Check if any of the stored URIs are the beginning of the URI
+	// we're trying now. If they are, we can immediately attempt to
+	// re-use the existing credentials.
+	TInt count = iCredentials.Count();
+	for (TInt cred = 0; cred < count; ++cred)
+		{
+		const TDesC8& transDes = aURI.UriDes();
+		const TDesC8& credDes = 
+			iStringPool.StringF(iCredentials[cred].iURI).DesC();
+		if (transDes.Length() >= credDes.Length())
+			{
+			// The URI is long enough, which is a good start.
+			if (transDes.Left(credDes.Length()).Compare(credDes) == 0)
+				{
+				// The descriptors match. Things are looking good. In
+				// the interests of paranoia, if we haven't matched
+				// the entire URI, check that the character after the
+				// match is '/'.
+				if (transDes.Length() == credDes.Length())
+                {
+					return cred;
+                }
+				else if (transDes[credDes.Length()] == '/')
+                {
+					return cred;
+                }
+				}
+			}
+		}
+	return KErrNotFound;
+    }
+
+// -----------------------------------------------------------------------------
+// CHttpFilterAuthentication::FindCredentialsForRealm
+// Search list for matching credentials for a given realm.
+// -----------------------------------------------------------------------------
+//
+TInt CHttpFilterAuthentication::FindCredentialsForRealm( const RString& aRealm,
+                                                         TBool aCheckProxy )
+    {
+    RStringF proxyName;
+    TInt count = iCredentials.Count();
+
+    if( aCheckProxy )
+        {
+        TBool ret = GetProxyName( proxyName );
+
+        if ( ret )
+            {
+            for ( TInt cred = 0; cred < count; ++cred )
+                {
+                if ( iCredentials[ cred ].iRealm == aRealm && iCredentials[ cred ].iURI == proxyName )
+                    {
+                    return cred;
+                    }
+                }
+            }
+        }
+    else
+        {
+        for ( TInt cred = 0; cred < count; ++cred )
+            {
+            if ( iCredentials[ cred ].iRealm == aRealm )
+                {
+                return cred;
+                }
+            }
+        }
+    AUTHLOGGER_LEAVEFN( "CHttpFilterAuthentication::FindCredentialsForRealm" );
+    return KErrNotFound;
+    }
+
+
+// -----------------------------------------------------------------------------
+// CHttpFilterAuthentication::FindCredentialsForProxy
+// Search list for matching credentials based on proxy used.
+// -----------------------------------------------------------------------------
+//
+TInt CHttpFilterAuthentication::FindCredentialsForProxy()
+    {
+    RStringF proxyName;
+    TInt cred = KErrNotFound;
+    TInt count = iCredentials.Count();
+    TBool ret = GetProxyName( proxyName );
+
+    if ( ret )
+        {
+        for ( cred = 0; cred < count; ++cred )
+            {
+            if ( iCredentials[ cred ].iURI == proxyName )
+                {
+                return cred;
+                }
+            }
+        }
+
+    return KErrNotFound;
+    }
+
+
+// -----------------------------------------------------------------------------
+// CHttpFilterAuthentication::EncodeBasicAuthL
+// Set basic auth header.
+// -----------------------------------------------------------------------------
+//
+void CHttpFilterAuthentication::EncodeBasicAuthL( const RString& aUsername,
+        const RString& aPW,
+        RHTTPTransaction& aTransaction )
+    {
+    AUTHLOGGER_ENTERFN( "CHttpFilterAuthentication::EncodeBasicAuthL" );
+
+    // Standard, plain-text HTTP - Base 64 the name and password
+    TBase64 codec;
+    HBufC8* nameAndPW = HBufC8::NewMaxLC( aUsername.DesC().Length() + aPW.DesC().Length() + 1 );
+    _LIT8( KBasicAuthFormatString, "%S:%S" );
+    nameAndPW->Des().Format( KBasicAuthFormatString, &aUsername.DesC(), &aPW.DesC() );
+
+    // Conservatively allocate a buffer twice as big as the unencoded
+    // buffer for the encoded string.
+    HBufC8* encoded = HBufC8::NewMaxLC( nameAndPW->Des().Length() * 2 );
+    TPtr8 encodedPtr( encoded->Des() );
+    codec.Encode( *nameAndPW, encodedPtr );
+    HBufC8* authHeaderField = HBufC8::NewLC( encodedPtr.Length() + 1 +
+                              iStringPool.StringF( HTTP::EBasic, RHTTPSession::GetTable() ).DesC().Length() );
+    authHeaderField->Des().Copy( iStringPool.StringF( HTTP::EBasic, RHTTPSession::GetTable() ).DesC() );
+    _LIT8( KSpace, " " );
+    authHeaderField->Des().Append( KSpace );
+    authHeaderField->Des().Append( encoded->Des() );
+
+    RString encodedString = iStringPool.OpenStringL( *authHeaderField );
+    CleanupStack::PopAndDestroy( 3 ); // authHeaderField, encoded, nameAndPW
+
+    CleanupClosePushL( encodedString );
+
+    RHTTPHeaders requestHeaders( aTransaction.Request().GetHeaderCollection() );
+
+    requestHeaders.RemoveField( iStringPool.StringF( iHttpStringAuthorization, RHTTPSession::GetTable() ) );
+
+    requestHeaders.SetFieldL( iStringPool.StringF( iHttpStringAuthorization, RHTTPSession::GetTable() ),
+                              THTTPHdrVal( encodedString ) );
+
+    CleanupStack::PopAndDestroy(); // encodedString
+    AUTHLOGGER_LEAVEFN( "CHttpFilterAuthentication::EncodeBasicAuthL" );
+    }
+
+// -----------------------------------------------------------------------------
+// CHttpFilterAuthentication::FindHeaderPartToUseL
+// Find the Authentication header.
+// -----------------------------------------------------------------------------
+//
+TInt CHttpFilterAuthentication::FindHeaderPartToUseL( RHTTPTransaction aTransaction )
+    {
+    AUTHLOGGER_ENTERFN( "CHttpFilterAuthentication::FindHeaderPartToUseL" );
+
+    // There may be several different authentication fields. We need
+    // to chose the strongest one we understnad. Currently, we only
+    // support 2, Basic and Digest, and Digest is the strongest
+    // assuming there is a qop that we can accept. Therefore, we keep
+    // track of the last good basic one we found, and return the
+    // moment we find an acceptable digest one.
+
+    // While we're here, we check that all desired fields are there.
+
+    RStringF wwwAuthenticate = iStringPool.StringF( iHttpStringAuthenticate, RHTTPSession::GetTable() );
+    TInt lastGoodBasic = KErrNotFound;
+    RHTTPHeaders headers = aTransaction.Response().GetHeaderCollection();
+    const TInt parts = headers.FieldPartsL( wwwAuthenticate );
+
+    for ( TInt ii = 0; ii < parts; ii++ )
+        {
+        THTTPHdrVal fieldVal; // The name of the current field.
+        THTTPHdrVal hdrVal; //A scratch hdrVal
+        headers.GetField( wwwAuthenticate, ii, fieldVal );
+
+        switch ( fieldVal.StrF().Index( RHTTPSession::GetTable() ) )
+            {
+
+            case HTTP::EBasic:
+
+            if ( headers.GetParam( wwwAuthenticate, iRealmStr, hdrVal, ii ) == KErrNone )
+                lastGoodBasic = ii;
+
+            break;
+
+            default:
+            // We don't understand this, whatever it is. Ignore it.
+            break;
+            }
+        }
+    AUTHLOGGER_LEAVEFN( "CHttpFilterAuthentication::FindHeaderPartToUseL" );
+    return lastGoodBasic;
+    }
+
+// -----------------------------------------------------------------------------
+// CHttpFilterAuthentication::GetCredentialsFromURIL
+// Find credentials from the transaction's URI.
+// -----------------------------------------------------------------------------
+//
+void CHttpFilterAuthentication::GetCredentialsFromURIL( RHTTPTransaction& aTransaction )
+    {
+    AUTHLOGGER_ENTERFN( "CHttpFilterAuthentication::GetCredentialsFromURIL" );
+
+    const TUriC8 & uri = aTransaction.Request().URI();
+
+    if ( uri.IsPresent( EUriUserinfo ) )
+        {
+        const TPtrC8 userInfo = uri.Extract( EUriUserinfo );
+        TInt colonPos = userInfo.Locate( ':' );
+
+        if ( colonPos == KErrNotFound )
+            colonPos = userInfo.Length();
+
+        if ( colonPos )
+            {
+            // We have a username
+            TPtrC8 username = userInfo.Left( colonPos );
+            SetPropertyL( aTransaction, iUsernameStr, username );
+            }
+
+        if ( colonPos != userInfo.Length() )
+            {
+            // We have a password
+            TPtrC8 password = userInfo.Mid( colonPos + 1 );
+            SetPropertyL( aTransaction, iPasswordStr, password );
+            }
+
+        if ( colonPos && uri.IsPresent( EUriHost ) )
+            {
+            // Get the realm only if there is a username
+            TPtrC8 realm = uri.Extract( EUriHost );
+            SetPropertyL( aTransaction, iRealmStr, realm );
+            }
+
+        // Now remove the username and password from the URI
+        CUri8* newUri = CUri8::NewLC( uri );
+
+        newUri->RemoveComponentL( EUriUserinfo );
+
+        aTransaction.Request().SetURIL( newUri->Uri() );
+
+        CleanupStack::PopAndDestroy( newUri ); // newUri
+        }
+    AUTHLOGGER_LEAVEFN( "CHttpFilterAuthentication::GetCredentialsFromURIL" );
+    }
+
+// -----------------------------------------------------------------------------
+// CHttpFilterAuthentication::GetCredentialsFromPropertiesL
+// Find credentials from the transaction's properties.
+// -----------------------------------------------------------------------------
+//
+void CHttpFilterAuthentication::GetCredentialsFromPropertiesL( RHTTPTransaction& aTransaction )
+    {
+    AUTHLOGGER_ENTERFN( "CHttpFilterAuthentication::GetCredentialsFromPropertiesL" );
+
+    THTTPHdrVal usernameVal;
+    THTTPHdrVal passwordVal;
+    THTTPHdrVal realmVal;
+    const TUriC8& uri = aTransaction.Request().URI();
+    RHTTPTransactionPropertySet propSet = aTransaction.PropertySet();
+
+    if ( propSet.Property( iUsernameStr, usernameVal ) &&
+         propSet.Property( iPasswordStr, passwordVal ) &&
+         propSet.Property( iRealmStr, realmVal ) )
+        {
+        TInt cred;
+        RStringF uriStr;
+
+        if ( iIsProxy )
+            {
+            if ( ( cred = FindCredentialsForRealm( realmVal ) ) != KErrNotFound )
+                {
+                // Remove old credentials from the list
+                RemoveCredentialsFromList( cred );
+                }
+
+            if ( GetProxyName( uriStr ) )
+                {
+                // Add credentials to the list from the transaction's properties
+                AddCredentialsToListL( usernameVal.Str().Copy(), passwordVal.Str().Copy(),
+                                       realmVal.Str().Copy(), uriStr.Copy() );
+                }
+            }
+
+        else
+            {
+            if ( ( cred = FindCredentialsForURI( uri ) ) != KErrNotFound )
+                {
+                // Remove old credentials from the list
+                RemoveCredentialsFromList( cred );
+                }
+
+            TPtrC8 uriPathPtr( uri.UriDes() );
+
+            if ( uriPathPtr.LocateReverse( '/' ) > 0 )
+                {
+                uriPathPtr.Set( uriPathPtr.Left( uriPathPtr.LocateReverse( '/' ) ) );
+                }
+
+            uriStr = iStringPool.OpenFStringL( uriPathPtr );
+            // Add credentials to the list from the transaction's properties
+            AddCredentialsToListL( usernameVal.Str().Copy(), passwordVal.Str().Copy(),
+                                   realmVal.Str().Copy(), uriStr );
+            }
+        }
+    AUTHLOGGER_LEAVEFN( "CHttpFilterAuthentication::GetCredentialsFromPropertiesL" );
+    }
+
+// -----------------------------------------------------------------------------
+// CHttpFilterAuthentication::RemoveCredentialsFromList
+// Remove credentials from the list.
+// -----------------------------------------------------------------------------
+//
+void CHttpFilterAuthentication::RemoveCredentialsFromList( TInt aCredId )
+    {
+    __ASSERT_DEBUG( aCredId >= 0 && aCredId < iCredentials.Count(), PanicAuthenticationFilter() );
+
+    TCredentials& creds = iCredentials[ aCredId ];
+    iStringPool.String( creds.iUser ).Close();
+    iStringPool.String( creds.iPassword ).Close();
+    iStringPool.StringF( creds.iURI ).Close();
+    iStringPool.String( creds.iRealm ).Close();
+    iCredentials.Remove( aCredId );
+    }
+
+
+// -----------------------------------------------------------------------------
+// CHttpFilterAuthentication::AddCredentialsToListL
+// Store credentials in the list.
+// -----------------------------------------------------------------------------
+//
+void CHttpFilterAuthentication::AddCredentialsToListL( RString aUsernameStr,
+        RString aPasswordStr,
+        RString aRealmStr,
+        RStringF aUriStr )
+    {
+    TCredentials newCred;
+    newCred.iUser = aUsernameStr;
+    newCred.iPassword = aPasswordStr;
+    newCred.iRealm = aRealmStr;
+    newCred.iURI = aUriStr;
+    newCred.iID = iNextID++;
+    User::LeaveIfError( iCredentials.Append( newCred ) );
+    }
+
+
+// -----------------------------------------------------------------------------
+// CHttpFilterAuthentication::TrimLWSLeft
+// Remove white spaces from the left.
+// -----------------------------------------------------------------------------
+//
+void CHttpFilterAuthentication::TrimLWSLeft( TPtrC8& aPtr )
+    {
+    TInt i;
+    _LIT8( KSpaceNewLineTab, " \r\n\t" );
+    TInt len = aPtr.Length();
+
+    for ( i = 0; i < len; i++ )
+        {
+        if ( KSpaceNewLineTab().Locate( aPtr[ i ] ) == KErrNotFound )
+            {
+            break;
+            }
+        }
+
+    if ( i == len )
+        {
+        aPtr.Set( NULL, 0 );
+        }
+
+    else
+        {
+        aPtr.Set( aPtr.Right( len - i ) );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CHttpFilterAuthentication::TrimLWSRight
+// Remove white spaces from the right.
+// -----------------------------------------------------------------------------
+//
+void CHttpFilterAuthentication::TrimLWSRight( TPtrC8& aPtr )
+    {
+    TInt i;
+    _LIT8( KSpaceNewLineTab, " \r\n\t" );
+    TInt len = aPtr.Length();
+
+    for ( i = len - 1; i >= 0; i-- )
+        {
+        if ( KSpaceNewLineTab().Locate( aPtr[ i ] ) == KErrNotFound )
+            {
+            break;
+            }
+        }
+
+    if ( i == -1 )
+        {
+        aPtr.Set( NULL, 0 );
+        }
+
+    else
+        {
+        aPtr.Set( aPtr.Left( i + 1 ) );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CHttpFilterAuthentication::FindCharNotInQoutes
+// Find a character in a buffer, but not in a quoted string.
+// -----------------------------------------------------------------------------
+//
+TInt CHttpFilterAuthentication::FindCharNotInQoutes( TPtrC8& aPtr, TUint8 aCharToFind )
+    {
+    TInt len = aPtr.Length();
+    TInt i;
+
+    for ( i = 0; i < len; i++ )
+        {
+        if ( aPtr[ i ] == aCharToFind )
+            {
+            return i;
+            }
+
+        if ( aPtr[ i ] == '"' )
+            {
+            for ( ; i < len && i != '"'; i++ )
+
+                ;
+            }
+        }
+
+    return KErrNotFound;
+    }
+
+// -----------------------------------------------------------------------------
+// CHttpFilterAuthentication::FindCharNotInQoutes
+// Find a substring in a buffer, but not in a quoted string.
+// -----------------------------------------------------------------------------
+//
+TInt CHttpFilterAuthentication::FindCharNotInQoutes( TPtrC8& aPtr, const TPtrC8& aCharsToFind )
+    {
+    TInt len = aPtr.Length();
+    TInt i;
+
+    for ( i = 0; i < len; i++ )
+        {
+        if ( aCharsToFind.Locate( aPtr[ i ] ) != KErrNotFound )
+            return i;
+
+        if ( aPtr[ i ] == '"' )
+            {
+            for ( ; i < len && aPtr[ i ] != '"'; i++ )
+
+                ;
+            }
+        }
+
+    return KErrNotFound;
+    }
+
+
+// -----------------------------------------------------------------------------
+// CHttpFilterAuthentication::FindNextTokenInHeaderFieldL
+// Find a next token in the header.
+// -----------------------------------------------------------------------------
+//
+TInt CHttpFilterAuthentication::FindNextTokenInHeaderFieldL( TPtrC8& aHeaderPtr, TPtrC8& aTokenPtr )
+    {
+    _LIT8( KCommaSpaceNewLineTab, ", \r\n\t" );
+    aTokenPtr.Set( aHeaderPtr );
+    TrimLWSLeft( aTokenPtr ); // Skip leading spaces
+    TInt leadingSpaces = aHeaderPtr.Length() - aTokenPtr.Length();
+
+    if ( aTokenPtr.Length() == 0 )
+        return KErrNotFound;
+
+    TInt i = FindCharNotInQoutes( aTokenPtr, KCommaSpaceNewLineTab() ); // Find separator after leading spaces
+
+    if ( i == KErrNotFound )
+        {
+        i = aHeaderPtr.Length();
+        }
+
+    else
+        {
+        aTokenPtr.Set( aTokenPtr.Left( i ) );
+        i += leadingSpaces; // Add the number of leading spaces
+        i++; // Advance beyond separator
+        }
+
+    return i;
+    }
+
+
+// -----------------------------------------------------------------------------
+// CHttpFilterAuthentication::AddProxyRealmToTransactionL
+// Find the proxy realm in the response header and add it to the transaction's properties.
+// -----------------------------------------------------------------------------
+//
+void CHttpFilterAuthentication::AddProxyRealmToTransactionL( RHTTPTransaction aTransaction )
+    {
+    AUTHLOGGER_ENTERFN( "CHttpFilterAuthentication::AddProxyRealmToTransactionL" );
+
+    RStringF authenticateStr = iStringPool.StringF( HTTP::EProxyAuthenticate, RHTTPSession::GetTable() );
+    RHTTPHeaders headers = aTransaction.Response().GetHeaderCollection();
+    const TInt parts = headers.FieldPartsL( authenticateStr );
+    TInt i;
+    TInt offset = 0;
+    TInt equalOffset = 0;
+    TBool found = EFalse;
+    THTTPHdrVal fieldVal;
+    TPtrC8 headerPtr;
+    TPtrC8 tokenPtr;
+    TPtrC8 partTokenPtr;
+    RStringF tokenStr;
+    RString realmStr;
+
+    for ( i = 0; i < parts; i++ )
+        {
+        if ( headers.GetField( authenticateStr, i, fieldVal ) == KErrNotFound )
+            {
+            continue;
+            }
+
+        headerPtr.Set( fieldVal.StrF().DesC() );
+
+        while ( ( offset = FindNextTokenInHeaderFieldL( headerPtr, tokenPtr ) ) != KErrNotFound )     // Get next token
+            {
+            headerPtr.Set( headerPtr.Right( headerPtr.Length() - offset ) ); // Advance headerPtr
+            tokenStr = iStringPool.OpenFStringL( tokenPtr );
+
+            switch ( tokenStr.Index( RHTTPSession::GetTable() ) )     // Is it Basic?
+                {
+
+                case HTTP::EBasic:
+                    {
+                    found = ETrue;
+                    break;
+                    }
+
+                default:
+                    {
+                    found = EFalse;
+                    break;
+                    }
+
+                }
+            tokenStr.Close();
+
+            if ( !found )
+                {
+                continue;
+                }
+
+            offset = FindNextTokenInHeaderFieldL( headerPtr, tokenPtr ); // Find next token
+            headerPtr.Set( headerPtr.Right( headerPtr.Length() - offset ) ); // Advance headerPtr
+
+            equalOffset = FindCharNotInQoutes( tokenPtr, '=' );
+
+            if ( equalOffset < 1 )     // Not the first character
+                {
+                continue;
+                }
+
+            partTokenPtr.Set( tokenPtr.Left( equalOffset ) );
+            tokenStr = iStringPool.OpenFStringL( partTokenPtr );
+
+            switch ( tokenStr.Index( RHTTPSession::GetTable() ) )     // Is it realm?
+                {
+
+                case HTTP::ERealm:
+                    {
+                    found = ETrue;
+                    break;
+                    }
+
+                default:
+                    {
+                    found = EFalse;
+                    break;
+                    }
+
+                }
+            tokenStr.Close();
+
+            if ( !found )
+                {
+                continue;
+                }
+
+            partTokenPtr.Set( tokenPtr.Right( tokenPtr.Length() - equalOffset - 1 ) );
+
+            if ( partTokenPtr.Length() > 0 )
+                {
+                realmStr = iStringPool.OpenStringL( partTokenPtr );
+                CleanupClosePushL( realmStr );
+                aTransaction.PropertySet().RemoveProperty( iRealmStr );
+                aTransaction.PropertySet().SetPropertyL( iRealmStr, realmStr );
+                CleanupStack::PopAndDestroy(); // realmStr
+
+                SetBasicProperty( aTransaction );
+                }
+
+            }
+        }
+    AUTHLOGGER_LEAVEFN( "CHttpFilterAuthentication::AddProxyRealmToTransactionL" );
+    }
+
+
+// -----------------------------------------------------------------------------
+// CHttpFilterAuthentication::GetProxyName
+// Get proxy name from the HTTP session.
+// -----------------------------------------------------------------------------
+//
+TBool CHttpFilterAuthentication::GetProxyName( RStringF &aProxyName )
+    {
+    RHTTPConnectionInfo connInfo = iSession->ConnectionInfo();
+    THTTPHdrVal proxyAddrVal;
+
+
+    TBool ret = connInfo.Property( iStringPool.StringF( HTTP::EProxyAddress,
+                                   RHTTPSession::GetTable() ), proxyAddrVal );
+
+    if ( ret )
+        aProxyName = proxyAddrVal.StrF();
+
+    return ret;
+    }
+
+// -----------------------------------------------------------------------------
+// CHttpFilterAuthentication::SetPropertyL
+// Set property of the transaction
+// -----------------------------------------------------------------------------
+//
+void CHttpFilterAuthentication::SetPropertyL( RHTTPTransaction& aTransaction,
+                                              RStringF aPropertyName, 
+                                              const TDesC8& aToken )
+    {
+    RString tokenStr = iStringPool.OpenStringL( aToken );
+    THTTPHdrVal tokenVal = tokenStr;
+    CleanupClosePushL( tokenStr );
+    aTransaction.PropertySet().SetPropertyL( aPropertyName, tokenVal );
+    CleanupStack::PopAndDestroy(); // tokenStr
+    }
+
+// -----------------------------------------------------------------------------
+// CHttpFilterAuthentication::SetBasicProperty()
+// Set 'Basic' in property set indicating that this is a
+// basic authentication
+// -----------------------------------------------------------------------------
+//
+void CHttpFilterAuthentication::SetBasicProperty( RHTTPTransaction aTransaction )
+    {
+    // the value is dummy. The property needs to be there only
+    THTTPHdrVal value( 1 ); 
+    aTransaction.PropertySet().RemoveProperty( 
+    iStringPool.StringF( HTTP::EBasic, 
+                         RHTTPSession::GetTable() ) );
+    aTransaction.PropertySet().SetPropertyL( 
+    iStringPool.StringF( HTTP::EBasic, 
+                         RHTTPSession::GetTable() ), 
+                         value );
+    }
+
+//  End of File
+