--- /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 );
+ };
+ }