httpfilters/cookie/ManagerSrc/CookieArray.cpp
changeset 0 b16258d2340f
child 6 fa2fd8b2d6cc
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/httpfilters/cookie/ManagerSrc/CookieArray.cpp	Tue Feb 02 01:09:52 2010 +0200
@@ -0,0 +1,1029 @@
+/*
+* Copyright (c) 2009 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:
+*
+*/
+// INCLUDE FILES
+	// System includes
+#include <http/thttphdrval.h>
+#include <Uri8.h>
+
+	// User includes
+#include "CookieArray.h"
+#include "CookieCommonConstants.h"
+#include "cookielogger.h"
+#include "CookieServerPanic.h"
+
+// CONSTANTS
+
+const TUint KCookieAttributeSeparator = ',';	// comma
+
+_LIT8( KCookieSecureScheme, "https" );
+
+// ================= MEMBER FUNCTIONS ======================
+
+// ---------------------------------------------------------
+// CCookieArray::CCookieArray
+// ---------------------------------------------------------
+//
+CCookieArray::CCookieArray() : iCookies( KCookieStandardGranularity )
+	{
+    CLOG( ( ECookieArray, 0, _L( "" ) ) );
+    CLOG( ( ECookieArray, 0, _L( "*****************" ) ) );
+    CLOG( ( ECookieArray, 0,
+					_L( "CCookieArray::CCookieArray" ) ) );
+	}
+
+// ---------------------------------------------------------
+// CCookieArray::~CCookieArray
+// ---------------------------------------------------------
+//
+CCookieArray::~CCookieArray()
+	{
+	iCookies.ResetAndDestroy();
+	iCookies.Close();
+    CLOG( ( ECookieArray, 0,
+					_L( "CCookieArray::~CCookieArray ") ) );
+    CLOG( ( ECookieArray, 0, _L( "*****************" ) ) );
+	}
+
+
+
+// ---------------------------------------------------------
+// CCookieArray::AddL
+// ---------------------------------------------------------
+//
+void CCookieArray::AddL( const CCookie* aCookie, const TDesC8& aRequestUri )
+	{
+    CLOG( ( ECookieArray, 0,
+			_L( "-> CCookieArray::AddL" ) ) );
+
+    if ( ValidCookieL( *aCookie, aRequestUri ) )
+		{
+        MakeRoomIfNeeded( aCookie->Size( EFalse ) );
+		User::LeaveIfError( iCookies.Append( aCookie ) );
+		}
+	else
+		{
+		User::Leave( KErrCorrupt );
+		}
+
+    CLOG( ( ECookieArray, 0,
+			_L( "<- CCookieArray::AddL" ) ) );
+	}
+
+// ---------------------------------------------------------
+// CCookieArray::MakeRoomForInsertIfNeededL
+// ---------------------------------------------------------
+//
+
+void CCookieArray::MakeRoomForInsertIfNeededL( const CCookie* aCookie, const TDesC8& aRequestUri, TInt& aIndex  )
+    {
+    if( ValidCookieL( *aCookie, aRequestUri ))
+    	{
+    	TUint32 size = aCookie->Size( EFalse );
+	    TUint32 count( Count() );
+	    TUint32 totalsize( 0 );
+	    for ( TUint32 i=0; i<count; i++ )
+	        {
+	        totalsize += At( i )->Size( ETrue );
+	        }
+	    while ( ( ( totalsize + size ) > KCookieMaxFileLength ) && Count() )
+	        {
+	        totalsize-= At( 0 )->Size( ETrue );	        	          
+	        aIndex--;
+	        Remove( 0 );
+	        if( aIndex < 0) //The insert point in the array is no longer invalid.
+	                        //return without making more room. 
+	            break;	            
+	        };
+	    }
+	else
+		{
+		User::Leave( KErrCorrupt );
+		}    
+    }
+	
+// ---------------------------------------------------------
+// CCookieArray::InsertL
+// ---------------------------------------------------------
+//
+void CCookieArray::InsertL( const CCookie* aCookie, const TInt aIndex )
+	{	
+    CLOG( ( ECookieArray, 0,
+			_L( "-> CCookieArray::InsertL" ) ) );
+
+    User::LeaveIfError( iCookies.Insert( aCookie, aIndex ) );
+	
+	CLOG( ( ECookieArray, 0,
+			_L( "<- CCookieArray::InsertL" ) ) );
+	}
+	
+
+// ---------------------------------------------------------
+// CCookieArray::Remove
+// ---------------------------------------------------------
+//
+void CCookieArray::Remove( TInt aIndex )
+    {
+    CLOG( ( ECookieArray, 0,
+			_L( "-> CCookieArray::Remove" ) ) );
+    __ASSERT_DEBUG(
+        ( (aIndex>=0) && (aIndex<iCookies.Count()) ),
+        PanicServer( EArrayIndexOutOfRange ) );
+    delete iCookies[ aIndex ];
+    iCookies.Remove( aIndex );
+
+    CLOG( ( ECookieArray, 0,
+			_L( "<- CCookieArray::Remove" ) ) );
+    }
+
+
+// ---------------------------------------------------------
+// CCookieArray::ClearAllCookies
+// ---------------------------------------------------------
+//
+TInt CCookieArray::ClearAllCookies()
+	{
+    CLOG( ( ECookieArray, 0,
+			_L( "-> CCookieArray::ClearAllCookies" ) ) );
+	TInt count = iCookies.Count();
+
+	iCookies.ResetAndDestroy();
+
+    CLOG( ( ECookieArray, 0,
+			_L( "<- CCookieArray::ClearAllCookies returned %d" ), count ) );
+	return count;
+	}
+
+
+// ---------------------------------------------------------
+// CCookieArray::CompareCookies
+// ---------------------------------------------------------
+//
+/*
+TInt CCookieArray::CompareCookies( CCookie const & aFirstCookie,
+								  CCookie const & aSecondCooke )
+	{
+	// TBD : the order of the cookies (i.e. which is the first and which
+	// is the second) may be unpredictable (I guess, it is). This may have
+	// serious impact on the sorting/searching algorithm. TO BE CONSIDERED!!!
+
+	// TBD2 : IMPORTANT!!! Perhaps we should use different TLinearOrder methods
+	// depending on whether we want to insert a new element into the array or
+	// to find a particular element in the array.
+	TInt result;
+
+	TPtrC8 firstPathAttr;
+	TPtrC8 secondPathAttr;
+	if ( GetFoldedCookieAttr( aFirstCookie, CCookie::EPath, firstPathAttr ) &&
+		 GetFoldedCookieAttr( aSecondCooke, CCookie::EPath, secondPathAttr ) )
+		{
+		// TODO : use PathMatch method here
+		result = -1;
+		}
+	else
+		{
+		// First, there should be no problem with filling the two attribs,
+		// because if they happen to be empty (or missing) in the HTTP request
+		// header, then a default value must be assigned to them.
+		// Second, if we happen to be here, then we say : the first cookie is
+		// less than the second, in other words, the first precedes the second.
+		result = -1;
+		}
+
+	// if the paths are equal, we have to continue with checking the domain
+	// attributes
+	if ( !result )
+		{
+		TPtrC8 firstDomainAttr;
+		TPtrC8 secondDomainAttr;
+		if ( GetFoldedCookieAttr( aFirstCookie, CCookie::EDomain,
+												firstDomainAttr ) &&
+			GetFoldedCookieAttr( aSecondCooke, CCookie::EDomain,
+												secondDomainAttr ) )
+			{
+			// TODO : use DomainMatch method here
+			}
+		}
+	else
+		{
+		// First, there should be no problem with filling the two attribs,
+		// because if they happen to be empty (or missing) in the HTTP request
+		// header, then a default value must be assigned to them.
+		// Second, if we happen to be here, then we say : the first cookie is
+		// less than the second, in other words, the first precedes the second.
+		result = -1;
+		}
+
+	return result;
+	}
+*/
+
+
+// ---------------------------------------------------------
+// CCookieArray::Count
+// ---------------------------------------------------------
+//
+TInt CCookieArray::Count() const
+	{
+    CLOG( ( ECookieArray, 0,
+			_L( "<- CCookieArray::Count" ) ) );
+	return iCookies.Count();
+	}
+
+
+// ---------------------------------------------------------
+// CCookieArray::DomainMatch
+// Examples :
+//	1.) x.y.com domain-matches .y.com
+//	2.) x.y.com does NOT domain-match y.com
+// ---------------------------------------------------------
+//
+TBool CCookieArray::DomainMatch( const TDesC8& aDomain1,
+                                 const TDesC8& aDomain2,
+                                 const TBool aAllowedDot /* = EFalse */ ) const
+	{
+    CLOG( ( ECookieArray, 0,
+			_L( "-> CCookieArray::DomainMatch" ) ) );
+
+    TBool result;
+    TPtrC8 domain2noQuotes( CCookie::RemoveQuotes( aDomain2 ) );
+    
+    // domain2noQuotes should not be NULL or length == zero
+    if ( domain2noQuotes.Length() == 0 ) 
+	{
+		result = EFalse;
+	}
+	else
+	{		
+		// match "b.com" with ".b.com", not stricly by spec but thats what other browsers do
+	    TPtrC8 d2( domain2noQuotes );
+	    if ( domain2noQuotes.Length()>1 && domain2noQuotes[ 0 ] == '.' )
+	        {
+	        d2.Set(domain2noQuotes.Ptr()+1, domain2noQuotes.Length()-1);
+	        }
+
+	    if ( aDomain1.Length() == d2.Length() )
+			{
+	        result = ( !aDomain1.CompareF( d2 ) ? ETrue : EFalse );
+			}
+	    else if ( domain2noQuotes.Length() < aDomain1.Length() )
+	        {
+	        // Considering aDomain1 as "x.y.com", leftDomainFraction will be "x"
+	        TPtrC8 leftDomainFraction( aDomain1.Left( aDomain1.Length() -
+	                                                                        domain2noQuotes.Length() ) );
+	        // Considering aDomain1 as "x.y.com", rightDomainFraction will be
+	        // ".y.com"
+	        TPtrC8 rightDomainFraction( aDomain1.Right( domain2noQuotes.Length() ) );
+
+	        // x.y.com matches both .y.com and y.com, thats what other browsers do
+	        TBool dot = rightDomainFraction[0] == KCookieDomainSeparator ||
+	            leftDomainFraction[leftDomainFraction.Length()-1] == KCookieDomainSeparator;
+	        if ( dot && !rightDomainFraction.CompareF( domain2noQuotes ) )
+	            {
+	            result = aAllowedDot || // if dot is allowed doesn't care about them
+	                (leftDomainFraction.Locate( KCookieDomainSeparator ) == KErrNotFound );
+	            }
+	        else
+	            {
+	            result = EFalse;
+	            }
+	        }
+		else
+			{
+			result = EFalse;
+			}
+	}
+
+    CLOG( ( ECookieArray, 0,
+			_L( "<- CCookieArray::DomainMatch" ) ) );
+
+    return result;
+	}
+
+
+
+// ---------------------------------------------------------
+// CCookieArray::EffectiveHostNameL
+// ---------------------------------------------------------
+//
+TBool CCookieArray::EffectiveHostNameL( const TDesC8& aHostName,
+									   HBufC8*& aEffectiveHostName ) const
+	{
+    CLOG( ( ECookieArray, 0,
+			_L( "-> CCookieArray::EffectiveHostName" ) ) );
+
+	TBool hostNameChanged = EFalse;
+
+	TBuf8<sizeof(KCookieDomainSeparator)> separator;
+    separator.Append( KCookieDomainSeparator );
+	if ( aHostName.Find( separator ) == KErrNotFound )
+		{
+		HBufC8* newHostName = HBufC8::NewL( aHostName.Length() +
+							KCookieLocalHostNamePostfix().Length() );
+		TPtr8 newHostNameDes( newHostName->Des() );
+
+		newHostNameDes.Copy( aHostName );
+		newHostNameDes.Append( KCookieLocalHostNamePostfix() );
+
+		aEffectiveHostName = newHostName;
+
+		hostNameChanged = ETrue;
+		}
+    CLOG( ( ECookieArray, 0,
+			_L( "<- CCookieArray::EffectiveHostName" ) ) );
+	return hostNameChanged;
+	}
+
+
+// ---------------------------------------------------------
+// CCookieArray::GetCookies
+// ---------------------------------------------------------
+//
+TInt CCookieArray::GetCookies( const TDesC8& aRequestUri,
+							   RPointerArray<CCookie>& aCookies )
+	{
+    CLOG( ( ECookieArray, 0,
+			_L( "-> CCookieArray::GetCookies for an URI" ) ) );
+	TUriParser8 uriParser;
+	TInt err = uriParser.Parse( aRequestUri );
+	if ( !err )
+		{
+        // first get the details of the current requestUri,
+        // that is, Domain, Path and port
+		TPtrC8 requestPath( uriParser.IsPresent( EUriPath ) ?
+							uriParser.Extract( EUriPath ) : KNullDesC8() );
+		TPtrC8 requestDomain( uriParser.IsPresent( EUriHost ) ?
+							uriParser.Extract( EUriHost ) : KNullDesC8() );
+		TPtrC8 requestPort( uriParser.IsPresent( EUriPort ) ?
+				uriParser.Extract( EUriPort ) : KCookieDefaultRequestPort() );
+		TPtrC8 requestScheme( uriParser.IsPresent( EUriScheme ) ?
+							uriParser.Extract( EUriScheme ) : KNullDesC8() );
+
+		// now check the existing cookies
+        // remove expired ones first, if there are any
+        RemoveExpired();
+        // and finally, find the cookies...
+        TInt count = iCookies.Count();
+		for ( TInt i = 0; i < count && err == KErrNone; i++ )
+			{
+			// Does the cookie have Path attribute?
+			TPtrC8 cookiePath;
+			if ( !GetFoldedCookieAttr( *iCookies[i],
+										CCookie::EPath,
+										cookiePath ) )
+				{
+				continue;
+				}
+
+			// Does the cookie have Domain attribute?
+			TPtrC8 cookieDomain;
+			if ( !GetFoldedCookieAttr( *iCookies[i],
+										CCookie::EDomain,
+										cookieDomain ) )
+				{
+				continue;
+				}
+
+			TPtrC8 cookiePort;
+			GetFoldedCookiePortAttr( *iCookies[i], cookiePort );
+
+			if ( PathMatch( requestPath, cookiePath ) &&
+                DomainMatch( requestDomain, cookieDomain, ETrue ) &&
+				PortMatch( requestPort, cookiePort ) &&
+				SecureMatch( requestScheme, *iCookies[i] ) )
+				{
+				err = aCookies.Append( iCookies[i] );
+				}
+			}
+        aCookies.Sort( TLinearOrder<CCookie> (CCookieArray::CompareCookiesPath) );
+		}
+    CLOG( ( ECookieArray, 0,
+			_L( "<- CCookieArray::GetCookies  for an URI" ) ) );
+	return err;
+	}
+
+
+// ---------------------------------------------------------
+// CCookieArray::GetCookies
+// ---------------------------------------------------------
+//
+TInt CCookieArray::GetCookies( RPointerArray<CCookie>& aCookieArray )
+	{
+    CLOG( ( ECookieArray, 0,
+			_L( "-> CCookieArray::GetCookies" ) ) );
+	TInt err = KErrNone;
+    // Remove expired ones first, if there is any...
+    RemoveExpired();
+	TInt count = iCookies.Count();
+	for ( TInt i = 0; i < count && err == KErrNone; i++ )
+		{
+		err = aCookieArray.Append( iCookies[i] );
+		}
+
+    CLOG( ( ECookieArray, 0,
+			_L( "<- CCookieArray::GetCookies" ) ) );
+    return err;
+	}
+
+
+// ---------------------------------------------------------
+// CCookieArray::operator[]
+// ---------------------------------------------------------
+//
+const CCookie* CCookieArray::operator[](TInt aIndex) const
+    {
+    return iCookies[aIndex];
+    }
+
+
+// ---------------------------------------------------------
+// CCookieArray::At
+// ---------------------------------------------------------
+//
+const CCookie* CCookieArray::At(TInt aIndex) const
+    {
+    return iCookies[ aIndex ];
+    }
+
+
+// ---------------------------------------------------------
+// CCookieArray::DoesAlreadyExists
+// ---------------------------------------------------------
+//
+TBool CCookieArray::DoesAlreadyExists( const CCookie* aCookie,
+                                       TInt& aIndex ) const
+    {
+    CLOG( ( ECookieArray, 0,
+			_L( "->CCookieArray::DoesAlreadyExists" ) ) );
+
+    TBool  result( EFalse );
+
+    TInt i(0);
+    TInt count( iCookies.Count() );
+
+    for( i = 0; i< count; i++ )
+        {
+        // first check their names, case-sensitive
+        if ( CompareAttribute( aCookie, iCookies[ i ],
+                               CCookie::EName, EFalse ) == 0 )
+            {
+            // their NAME-s are EQUAL
+            // now shall check their DOMAIN, case-insensitive (F)
+            if ( CompareAttribute( aCookie, iCookies[ i ],
+                                   CCookie::EDomain, ETrue ) == 0 )
+                {
+                // their DOMAIN is matching
+                // now check Path, case-sensitive
+                if ( CompareAttribute( aCookie, iCookies[ i ],
+                                       CCookie::EPath, EFalse ) == 0 )
+                    { // their path is the same, too
+                    // so it already exists, should OVERWRITE!!!!!!!!
+                    result = ETrue;
+                    aIndex = i;
+                    }
+                }
+            }
+        }
+    CLOG( ( ECookieArray, 0,
+			_L( "<- CCookieArray::DoesAlreadyExists" ) ) );
+    return result;
+    }
+
+
+// ---------------------------------------------------------
+// CCookieArray::CookieArray
+// ---------------------------------------------------------
+//
+RPointerArray<CCookie>& CCookieArray::CookieArray()
+    {
+    return iCookies;
+    }
+
+
+// ---------------------------------------------------------
+// CCookieArray::GetFoldedCookieAttr
+// ---------------------------------------------------------
+//
+TBool CCookieArray::GetFoldedCookieAttr( const CCookie& aCookie,
+										 CCookie::TCookieAttributeName aAttr,
+										 TPtrC8& aAttrDes ) const
+	{
+    CLOG( ( ECookieArray, 0,
+			_L( "-> CCookieArray::GetFoldedCookieAttr" ) ) );
+	TBool result = EFalse;
+	THTTPHdrVal attrVal;
+	if ( aCookie.Attribute( aAttr, attrVal ) == KErrNone )
+		{
+		if ( attrVal.Type() == THTTPHdrVal::KStrFVal )
+			{
+			aAttrDes.Set( attrVal.StrF().DesC() );
+			result = ETrue;
+			}
+		else if ( attrVal.Type() == THTTPHdrVal::KStrVal )
+			{
+			aAttrDes.Set( attrVal.Str().DesC() );
+			result = ETrue;
+			}
+		}
+
+    CLOG( ( ECookieArray, 0,
+			_L( "<- CCookieArray::GetFoldedCookieAttr" ) ) );
+	return result;
+	}
+
+
+// ---------------------------------------------------------
+// CCookieArray::FoldedCookiePortAttr
+// ---------------------------------------------------------
+//
+void CCookieArray::GetFoldedCookiePortAttr( const CCookie& aCookie,
+										   TPtrC8& aPort ) const
+	{
+	// We have to check if the cookie has Port attribute
+	if ( !GetFoldedCookieAttr( aCookie, CCookie::EPort, aPort ) )
+		{
+		aPort.Set( KNullDesC8() );
+		}
+	}
+
+// ---------------------------------------------------------
+// CCookieArray::PathMatch
+// Examples :
+//	1.) /tec path-matches /tec
+//	2.) /tec/waldo path-matches /tec
+// ---------------------------------------------------------
+//
+TBool CCookieArray::PathMatch( const TDesC8& aPath1,
+							  const TDesC8& aPath2 ) const
+	{
+    if( aPath1.Length() == 0 ) // root folder is requested
+        return ETrue;
+    TPtrC8 path2noQuotes( CCookie::RemoveQuotes( aPath2 ) );
+	return ( aPath1.Find( path2noQuotes ) == 0 );
+	}
+
+
+// ---------------------------------------------------------
+// CCookieArray::PortMatch
+// ---------------------------------------------------------
+//
+TBool CCookieArray::PortMatch( const TDesC8& aRequestPort,
+							  const TDesC8& aCookiePort ) const
+	{
+    CLOG( ( ECookieArray, 0,
+			_L( "-> CCookieArray::PortMatch" ) ) );
+
+    TBool result;
+
+	// cookiePort - it is a 'global' port string that may contain more
+	// than one ports, each is separated from the other by
+	// KCookieAttributeSeparator. We use it for positioning in the original
+	// string, that is, in this string.
+	TPtrC8 cookiePort( CCookie::RemoveQuotes( aCookiePort ) );
+	if ( !aCookiePort.Length() )
+		{
+		// if there is no Port attribute in the cookie, then it may be
+		// be sent to any ports
+		result = ETrue;
+		}
+	else if ( !aRequestPort.Length() )
+		{
+		// there is Port attribute, but there is no request-port
+		// (which may never happen in theory)
+		result = EFalse;
+		}
+	else
+		{
+		// portList - it is a local port string that may contain more
+		// than one ports, each is separated from the other by
+		// KCookieAttributeSeparator. We use it for searching the
+		// request-port inside this string.
+		TPtrC8 portList( cookiePort );
+		// globalPos - for positioning in the 'global' port list string
+		// whose size does not change
+		TInt globalPos = 0;
+		// localPos - for positioning in the local port list string
+		// that is getting shorter and shorter
+		TInt localPos = 0;
+
+		TBool loopRunning = ETrue;	// loop variable
+		while ( loopRunning )
+			{
+			localPos = portList.Find( aRequestPort );
+			if ( localPos == KErrNotFound )
+				{
+				// if the pattern cannot be located in the string, then
+				// the result is EFalse, too
+				loopRunning = EFalse;
+				}
+			else
+				{
+				globalPos += localPos;
+				TInt newLocalPos = localPos + aRequestPort.Length();
+				// Assume aRequestPort is 80! Next statement is to filter
+				// out "...80"-type matching : "80" or "...,80"
+				if ( newLocalPos == portList.Length() &&
+					( globalPos == 0 ||	cookiePort[ globalPos - 1 ] ==
+										KCookieAttributeSeparator ) )
+					{
+					// we found the location of the pattern in question
+					// and there are no characters beyond this location
+					loopRunning = EFalse;
+					}
+				// Assume aRequestPort is 80! Next statement is to filter
+				// out "...80,..."-type matching : "80,..." or
+				// "...,80,..."
+				else if ( portList[ newLocalPos ] ==
+							KCookieAttributeSeparator &&
+						( globalPos == 0 ||	cookiePort[ globalPos - 1 ] ==
+											KCookieAttributeSeparator ) )
+					{
+					// we found the pattern and there is a separator char
+					// right after it ==> this is the perfect port-match
+					loopRunning = EFalse;
+					}
+				else
+					{
+					// we have to continue searching from the new position
+					portList.Set( portList.Right( portList.Length() -
+												newLocalPos ) );
+					globalPos += newLocalPos - localPos;
+					}
+				}
+			}
+
+		// ETrue if we found something, EFalse if the result was
+		// KErrNotFound
+		result = ( localPos != KErrNotFound );
+		}
+    CLOG( ( ECookieArray, 0,
+			_L( "<- CCookieArray::PortMatch" ) ) );
+	return result;
+	}
+
+
+
+
+// ---------------------------------------------------------
+// CCookieArray::SecureMatch
+// ---------------------------------------------------------
+//
+TBool CCookieArray::SecureMatch( const TDesC8& aUriScheme,
+								 const CCookie& aCookie ) const
+	{
+    CLOG( ( ECookieArray, 0,
+			_L( "-> CCookieArray::SecureMatch" ) ) );
+    TBool result;
+
+	TPtrC8 cookieSecurity;	// the value will never be used
+	if ( !GetFoldedCookieAttr( aCookie, CCookie::ESecure, cookieSecurity ) )
+		{
+		// if there is no ESecure attribute - the cookie is not secure ==>
+		// it can be sent even over an insecure connection
+		result = ETrue;
+		}
+	else	// there is ESecure attribute - the cookie is secure
+		{
+		result = ( aUriScheme.CompareF( KCookieSecureScheme ) == 0 );
+		}
+
+    CLOG( ( ECookieArray, 0,
+			_L( "<- CCookieArray::SecureMatch" ) ) );
+	return result;
+	}
+
+
+// ---------------------------------------------------------
+// CCookieArray::ValidCookie
+// The validation rules may be different for Netscape and RFC
+// cookies :
+//	- A. RFC (reject cookie when) :
+//		==> 1. Version attribute is missing
+//		==> 2. Path attribute is not a prefix of the request-URI
+//		==> 3. Domain attribute contains no embedded dots, and the
+//			value is not .local
+//		==> 4. Effective host name does not domain-match the Domain
+//			attribute
+//		==> 5.* The request-host is a HDN and has the form HD, where
+//			D is the value of the Domain attribute, and H is a string
+//			that contains one or more dots
+//		==> 6. The Port attribute has a "port-list", and the request-
+//			port is not in the list
+//	- B. Netscape (reject cookie when) :
+//		==> 1.* Only hosts within the specified domain can set a cookie
+//			for a domain
+//		==> 2.* Any domain that falls within one of the seven special
+//			top level domains (COM, EDU, NET, ORG, GOV, MIL and INT)
+//			only require two periods. Any other domain requires
+//			at least three
+//	- C. Common (reject cookie when) :
+//		==> 1. NAME or VALUE attribute is missing
+// Note : numbers marked with * (asterisk) indicate features to be
+// implemented.
+// ---------------------------------------------------------
+//
+TBool CCookieArray::ValidCookieL( const CCookie& aCookie,
+								 const TDesC8& aRequestUri ) const
+	{
+    CLOG( ( ECookieArray, 0,
+			_L( "-> CCookieArray::ValidCookieL" ) ) );
+
+    // TODO : validation must take cookie-type into account ==> whether it is
+	// a Netscape- or RFC-type cookie
+	TBool validCookie = ETrue;
+	TBool newCookie = aCookie.FromCookie2();
+	THTTPHdrVal hdrVal;
+
+	// C.1. (Name attribute)
+	TInt findAttrib = aCookie.Attribute( CCookie::EName, hdrVal );
+	if ( findAttrib != KErrNone )
+		{
+		validCookie = EFalse;
+		}
+
+	// C.1. (Value attribute)
+	if ( validCookie )
+		{
+		findAttrib = aCookie.Attribute( CCookie::EValue, hdrVal );
+		if ( findAttrib != KErrNone )
+			{
+			validCookie = EFalse;
+			}
+		}
+
+
+	// General rule : if the request-URI is invalid, then the cookie is invalid
+	TUriParser8 uriParser;
+	if ( validCookie )
+		{
+		if ( ( uriParser.Parse( aRequestUri ) != KErrNone ) ||
+			!uriParser.IsPresent( EUriHost ) )
+			{
+			validCookie = EFalse;
+			}
+		}
+
+
+    // A.1.
+	if ( validCookie && newCookie )
+		{
+		findAttrib = aCookie.Attribute( CCookie::EVersion, hdrVal );
+		if ( findAttrib != KErrNone )
+			{
+			validCookie = EFalse;
+			}
+		}
+
+
+	// Domain checking is done here
+	// TODO : B.1. and B.2. ==> newCookie verification must be placed deeper
+	if ( validCookie && newCookie )
+		{
+		findAttrib = aCookie.Attribute( CCookie::EDomain, hdrVal );
+		// TBD : what if there is no Domain attribute (even defaulted)?
+		// Should we bother with filtering out this anomaly?
+		if ( findAttrib == KErrNone )
+			{
+			TPtrC8 cookieDomain( hdrVal.StrF().DesC() );
+
+			TBuf8<sizeof(KCookieDomainSeparator)> separator;
+			separator.Append( KCookieDomainSeparator );
+
+			// A.3.
+			if ( cookieDomain.Find( separator ) == KErrNotFound ||
+				!cookieDomain.CompareF( KCookieLocalHostNamePostfix() ) )
+				{
+				validCookie = EFalse;
+				}
+
+			TPtrC8 requestDomain( uriParser.Extract( EUriHost ) );
+
+			// A.4.
+			if ( validCookie )
+				{
+				HBufC8* effHostName = NULL;
+				if ( EffectiveHostNameL( requestDomain, effHostName ) )
+					{
+					validCookie = ( DomainMatch( *effHostName,
+									cookieDomain ) ? ETrue : EFalse );
+
+					delete effHostName;
+					}
+				else
+					{
+					validCookie = ( DomainMatch( requestDomain,
+									cookieDomain ) ? ETrue : EFalse );
+					}
+				}
+
+			// A.5.
+			if ( validCookie )
+				{
+				// TODO
+				}
+			}
+		}
+
+	// A.2. (Path)
+	// Note : although Path attribute may be used in a Netscape-cookie as well,
+	// we need not bother with it as the Netscape specification do not say
+	// anything about cookie-path validation
+	if ( validCookie && newCookie )
+		{
+		findAttrib = aCookie.Attribute( CCookie::EPath, hdrVal );
+		if ( findAttrib == KErrNone )
+			{
+			TPtrC8 cookiePath( hdrVal.StrF().DesC() );
+			TPtrC8 requestPath( uriParser.IsPresent( EUriPath ) ?
+							uriParser.Extract( EUriPath ) : KNullDesC8() );
+   			validCookie = ( PathMatch( requestPath, cookiePath ) ?
+   			    ETrue : EFalse );
+			}
+		}
+
+	// A.6. (Port)
+	// Note : it is RFC2965-specific
+	if ( validCookie && newCookie )
+		{
+		TPtrC8 cookiePort;
+		GetFoldedCookiePortAttr( aCookie, cookiePort );
+		TPtrC8 requestPort( uriParser.IsPresent( EUriPort ) ?
+				uriParser.Extract( EUriPort ) : KCookieDefaultRequestPort() );
+
+		validCookie = ( PortMatch( requestPort, cookiePort ) ? ETrue
+															: EFalse );
+		}
+
+    CLOG( ( ECookieArray, 0,
+			_L( "<- CCookieArray::ValidCookieL" ) ) );
+	return validCookie;
+	}
+
+
+
+
+// ---------------------------------------------------------
+// CCookieArray::RemoveExpired
+// ---------------------------------------------------------
+//
+void CCookieArray::RemoveExpired()
+    {
+    CLOG( ( ECookieArray, 0,
+			_L( "-> CCookieArray::RemoveExpired" ) ) );
+    TInt i( 0 );
+
+    while( i < iCookies.Count() )
+        {
+        if ( iCookies[ i ]->Expired() )
+            {
+            delete iCookies[ i ];
+            iCookies.Remove( i );
+            }
+        else
+            {
+            i++;
+            }
+        };
+    CLOG( ( ECookieArray, 0,
+			_L( "<- CCookieArray::RemoveExpired" ) ) );
+    }
+
+
+
+// ---------------------------------------------------------
+// CCookieArray::RemoveNonPersistent
+// ---------------------------------------------------------
+//
+void CCookieArray::RemoveNonPersistent()
+    {
+    CLOG( ( ECookieArray, 0,
+			_L( "-> CCookieArray::RemoveNonPersistent" ) ) );
+    TInt i( 0 );
+
+    while( i < iCookies.Count() )
+        {
+        if (!iCookies[ i ]->Persistent() || iCookies[ i ]->Expired() )
+            {
+            delete iCookies[ i ];
+            iCookies.Remove( i );
+            }
+        else
+            {
+            i++;
+            }
+        };
+    CLOG( ( ECookieArray, 0,
+			_L( "<- CCookieArray::RemoveNonPersistent" ) ) );
+    }
+
+// ---------------------------------------------------------
+// CCookieArray::CompareAttribute
+// ---------------------------------------------------------
+//
+TInt CCookieArray::CompareAttribute( const CCookie* aCookie1,
+                                     const CCookie* aCookie2,
+                                     CCookie::TCookieAttributeName aAttr,
+                                     TBool aFolded ) const
+    {
+    CLOG( ( ECookieArray, 0,
+			_L( "-> CCookieArray::CompareAttribute" ) ) );
+
+    TInt result( -1 );
+
+    THTTPHdrVal val1;
+    THTTPHdrVal val2;
+
+
+    if ( aCookie1->Attribute( aAttr, val1 ) == KErrNone )
+        {
+        if ( aCookie2->Attribute( aAttr, val2 ) == KErrNone )
+            {
+            if ( aFolded )
+                {
+                if( val1.Type() == THTTPHdrVal::KStrFVal )
+                    result = val1.StrF().DesC().CompareF( val2.StrF().DesC() );
+                else if( val1.Type() == THTTPHdrVal::KStrVal )
+                    result = val1.Str().DesC().CompareF( val2.Str().DesC() );
+                }
+            else
+                {
+                if( val1.Type() == THTTPHdrVal::KStrFVal )
+                    result = val1.StrF().DesC().Compare( val2.StrF().DesC() );
+                else if( val1.Type() == THTTPHdrVal::KStrVal )
+                    result = val1.Str().DesC().Compare( val2.Str().DesC() );
+                }
+            }
+        }
+    CLOG( ( ECookieArray, 0,
+			_L( "<- CCookieArray::CompareAttribute" ) ) );
+    return result;
+    }
+
+
+// ---------------------------------------------------------
+// CCookieArray::CompareCookiesPath
+// ---------------------------------------------------------
+//
+TInt CCookieArray::CompareCookiesPath( const CCookie & aFirstCookie,
+                                        const CCookie & aSecondCookie )
+{
+    TInt result( -1 );
+
+    THTTPHdrVal val1;
+    THTTPHdrVal val2;
+
+    if ( aFirstCookie.Attribute( CCookie::EPath, val1 ) == KErrNone )
+        {
+        if ( aSecondCookie.Attribute( CCookie::EPath, val2 ) == KErrNone )
+            {
+            TInt length1 = val1.StrF().DesC().Length();
+            TInt length2 = val2.StrF().DesC().Length();
+            if( length1 > length2 )
+                {
+                result = -1;
+                }
+            else if( length1 < length2)
+                {
+                result = 1;
+                }
+            else
+                {
+                result = 0;
+                }
+            }
+        }
+
+    return result;
+}
+
+// ---------------------------------------------------------
+// CCookieArray::MakeRoomIfNeeded
+// ---------------------------------------------------------
+//
+void CCookieArray::MakeRoomIfNeeded( TUint32 aSize )
+    {
+    TUint32 count( Count() );
+    TUint32 totalsize( 0 );
+    for ( TUint32 i=0; i<count; i++ )
+        {
+        totalsize += At( i )->Size( ETrue );
+        }
+    while ( ( ( totalsize + aSize ) > KCookieMaxFileLength ) && Count() )
+        {
+        totalsize-= At( 0 )->Size( ETrue );
+        Remove( 0 );
+        };
+    }