applayerprotocols/httpexamples/cookies/example/examplecookiemanager.cpp
changeset 0 b16258d2340f
equal deleted inserted replaced
-1:000000000000 0:b16258d2340f
       
     1 // Copyright (c) 2001-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    15 
       
    16 #include "examplecookiemanager.h"
       
    17 #include "httpcookieerr.h"
       
    18 
       
    19 #include <http/ccookie.h>
       
    20 #include <http/thttphdrval.h>
       
    21 
       
    22 EXPORT_C CExampleCookieManager* CExampleCookieManager::NewL(RStringPool aStringPool)
       
    23 	{
       
    24 	CExampleCookieManager* cookieManager = new(ELeave)CExampleCookieManager(aStringPool);
       
    25 	return cookieManager;
       
    26 	}
       
    27 
       
    28 EXPORT_C CExampleCookieManager::~CExampleCookieManager()
       
    29 	{
       
    30 	// At this point a real cookie manager would go through the list of cookies
       
    31 	// and destroy any that don't have an Expires or MaxAge attribute (because they 
       
    32 	// should only last for the session).
       
    33 	// Any remaining ones should be persisted till the next session.
       
    34 
       
    35 	// However, we don't persist for this implementation
       
    36 	iCookies.ResetAndDestroy();
       
    37 	}
       
    38 
       
    39 CExampleCookieManager::CExampleCookieManager(RStringPool aStringPool) :
       
    40 	iStringPool(aStringPool)
       
    41 	{
       
    42 	}
       
    43 
       
    44 EXPORT_C void CExampleCookieManager::StoreCookieL(CCookie* aCookie, const TUriC8& aUri)
       
    45 	{
       
    46 	CleanupStack::PushL(aCookie);
       
    47 
       
    48 	if(ValidateCookieL(*aCookie, aUri))
       
    49 		{
       
    50 		User::LeaveIfError(iCookies.Append(aCookie));
       
    51 		CleanupStack::Pop(aCookie);
       
    52 		}
       
    53 	else
       
    54 		CleanupStack::PopAndDestroy(aCookie);
       
    55 	}
       
    56 
       
    57 EXPORT_C void CExampleCookieManager::GetCookiesL(RHTTPTransaction aTransaction, 
       
    58 												 RArray<CCookie*>& aCookieList,
       
    59 												 TBool& aCookie2Reqd)
       
    60 	{
       
    61 	// For comparing cookies to insert them in the correct order to the returned array
       
    62 	TLinearOrder<CCookie*> compareFunc(CompareCookiePaths);
       
    63 
       
    64 	// Ensure the array is empty
       
    65 	__ASSERT_DEBUG(aCookieList.Count()==0, HTTPCookiePanic::Panic(HTTPCookiePanic::EGetCookiesArrayNotEmpty));
       
    66 
       
    67 	const TInt numCookies = iCookies.Count();
       
    68 	for (TInt ii=0; ii<numCookies; ++ii)
       
    69 		{
       
    70 		CCookie* cookie = iCookies[ii];
       
    71 		const TUriC8& uri = aTransaction.Request().URI();
       
    72 
       
    73 		if(CheckDomainMatch(*cookie, uri) &&
       
    74 		   CheckPathMatch(*cookie, uri) &&
       
    75 		   CheckPortMatch(*cookie, uri) &&
       
    76 		   CheckSecureMatch(*cookie, uri))
       
    77 			{
       
    78 			User::LeaveIfError(aCookieList.InsertInOrderAllowRepeats(cookie, compareFunc));
       
    79 
       
    80 			if(!cookie->FromCookie2())
       
    81 				aCookie2Reqd = ETrue;
       
    82 			}
       
    83 		}
       
    84 	}
       
    85 
       
    86 TBool CExampleCookieManager::CheckDomainMatch(CCookie& aCookie, const TUriC8& aUri) const
       
    87 	{
       
    88 	TChar domainSep = '.';
       
    89 
       
    90 	if(aUri.IsPresent(EUriHost))
       
    91 		{
       
    92 		THTTPHdrVal attributeVal;
       
    93 		aCookie.Attribute(CCookie::EDomain, attributeVal);
       
    94 
       
    95 		const TDesC8& domain = aUri.Extract(EUriHost);
       
    96 		const TPtrC8 cookieDomain = RemoveQuotes(attributeVal.StrF().DesC());
       
    97 
       
    98 		// Domain matching rules:
       
    99 		// if the cookie domain doesn't start with a dot then it must match the uri domain exactly
       
   100 		// if it does start with a dot and it 
       
   101 		TInt matchLoc = domain.FindF(cookieDomain);
       
   102 		if((cookieDomain[0] != TUint(domainSep))		&& 
       
   103 			(matchLoc == 0)								&& 
       
   104 			(domain.Length() == cookieDomain.Length()))
       
   105 			return ETrue;
       
   106 		else if((matchLoc != KErrNotFound) &&
       
   107 				(domain.Left(matchLoc).Locate(domainSep) == KErrNotFound))
       
   108 				return ETrue;
       
   109 		}
       
   110 
       
   111 	return EFalse;
       
   112 	}
       
   113 
       
   114 TBool CExampleCookieManager::CheckPathMatch(CCookie& aCookie, const TUriC8& aUri) const
       
   115 	{
       
   116 	THTTPHdrVal attributeVal;
       
   117 	aCookie.Attribute(CCookie::EPath, attributeVal);
       
   118 	TPtrC8 cookiePath = RemoveQuotes(attributeVal.StrF().DesC());
       
   119 
       
   120 	const TDesC8& uriPath = aUri.Extract(EUriPath);
       
   121 	if(uriPath.Length() == 0)
       
   122 		{
       
   123 		// if the uri has no path then it matches against no cookie path
       
   124 		// or a cookie path of just a /
       
   125 		const TInt pathLength = cookiePath.Length();
       
   126 		if(pathLength == 0 || pathLength == 1)
       
   127 			return ETrue;
       
   128 		}
       
   129 	else if(uriPath.FindF(cookiePath) == 0)
       
   130 		{
       
   131 		TChar separator('/');
       
   132 		// Check that the character after the matched bit is a / otherwise
       
   133 		// /path would match against /path2
       
   134 		const TInt uriLength = uriPath.Length();
       
   135 		const TInt cookieLength = cookiePath.Length();
       
   136 
       
   137 		if(uriLength == cookieLength)
       
   138 			return ETrue;
       
   139 		else if(uriLength > cookieLength)
       
   140 			{
       
   141 			if(cookiePath[cookieLength - 1] == TUint(separator))
       
   142 				return ETrue;
       
   143 			else if(uriPath[cookieLength] == TUint(separator))
       
   144 				return ETrue;
       
   145 			}
       
   146 		}
       
   147 
       
   148 	return EFalse;
       
   149 	}
       
   150 
       
   151 TBool CExampleCookieManager::CheckPortMatch(CCookie& aCookie, const TUriC8& aUri) const
       
   152 	{
       
   153 	THTTPHdrVal val;
       
   154 	if(aCookie.Attribute(CCookie::EPort, val) == KErrNone)
       
   155 		{
       
   156 		TChar portSeparator(',');
       
   157 		_LIT8(KDefaultPort, "80");
       
   158 
       
   159 		const TDesC8& port = aUri.IsPresent(EUriPort)? aUri.Extract(EUriPort) : KDefaultPort();
       
   160 
       
   161 		const TPtrC8& portList = RemoveQuotes(val.StrF().DesC());
       
   162 		TInt portPos = portList.FindF(port);
       
   163 		// if we do not find the port in the list then do not match
       
   164 		if(portPos == KErrNotFound)
       
   165 			return EFalse;
       
   166 		// if the number was the last in the list then match
       
   167 		else if((portPos + port.Length()) == portList.Length())
       
   168 			return ETrue;
       
   169 		// check that the number is followed by a separator ie do not match 80 with 8000
       
   170 		else if(portList[portPos + port.Length()] == TUint(portSeparator))
       
   171 			return ETrue;
       
   172 		// we have not found a match
       
   173 		else
       
   174 			return EFalse;
       
   175 		}
       
   176 
       
   177 	// If the cookie does not have a portlist return ETrue to match any port
       
   178 	return ETrue;
       
   179 	}
       
   180 
       
   181 TBool CExampleCookieManager::CheckSecureMatch(CCookie& aCookie, const TUriC8& aUri) const
       
   182 	{
       
   183 	THTTPHdrVal val;
       
   184 	TBool secureCookie = aCookie.Attribute(CCookie::ESecure, val) == KErrNone;
       
   185 
       
   186 	// if the cookie is not secure we don't care about the uri
       
   187 	if(!secureCookie)
       
   188 		return ETrue;
       
   189 
       
   190 	// Check if the scheme is https - if there is no scheme then assume not
       
   191 	if(aUri.IsPresent(EUriScheme))
       
   192 		{
       
   193 		_LIT8(KSecureScheme, "https");
       
   194 		const TDesC8& scheme = aUri.Extract(EUriScheme);
       
   195 		return scheme.CompareF(KSecureScheme()) == 0;
       
   196 		}
       
   197 
       
   198 	// The cookie is secure and we don't have a secure transaction
       
   199 	return EFalse;
       
   200 	}
       
   201 
       
   202 TBool CExampleCookieManager::ValidateCookieL(CCookie& aCookie, const TUriC8& aUri)
       
   203 	{
       
   204 	THTTPHdrVal attributeVal;
       
   205 
       
   206 	if(aCookie.Attribute(CCookie::EPath, attributeVal) == KErrNone)
       
   207 		{
       
   208 		// if the path attribute exists check it is a prefix of the path
       
   209 		// of the uri that issued it (if not reject)
       
   210 		RStringF cookiePath = attributeVal.StrF();
       
   211 		const TDesC8& uriPath = aUri.Extract(EUriPath);
       
   212 		if(uriPath.FindF(RemoveQuotes(cookiePath.DesC())) != 0)
       
   213 			return EFalse;
       
   214 		}
       
   215 	else
       
   216 		{
       
   217 		// if the path attribute doesn't exist add it
       
   218 		THTTPHdrVal val(iStringPool.OpenFStringL(aUri.Extract(EUriPath)));
       
   219 		aCookie.SetAttributeL(CCookie::EPath, val);
       
   220 		}
       
   221 
       
   222 	if(aCookie.Attribute(CCookie::EDomain, attributeVal) == KErrNone)
       
   223 		{
       
   224 		const TChar dot('.');
       
   225 		const TDesC8& cookieDomain = attributeVal.StrF().DesC();
       
   226 		const TDesC8& uriDomain = aUri.Extract(EUriHost);
       
   227 
       
   228 		// if the domain does not exactly match the uri and does not begin
       
   229 		// with a dot then add one
       
   230 		if((cookieDomain.Compare(uriDomain) != 0) &&
       
   231 		   (cookieDomain.Locate(dot) != 0))
       
   232 			{
       
   233 			_LIT8(KAddDotString, ".%S");
       
   234 			HBufC8* newDomain = HBufC8::NewLC(cookieDomain.Length() + 1);
       
   235 			newDomain->Des().AppendFormat(KAddDotString(), &cookieDomain);
       
   236 
       
   237 			RStringF domain = iStringPool.OpenFStringL(*newDomain);
       
   238 			CleanupStack::PopAndDestroy(newDomain);
       
   239 
       
   240 			THTTPHdrVal val(domain);
       
   241 			aCookie.SetAttributeL(CCookie::EDomain, val);
       
   242 			domain.Close();
       
   243 			}
       
   244 
       
   245 		// if the domain does not contain an embedded dot then reject it
       
   246 		// ie reject .com or .com.
       
   247 		// Start by removing one character from each end. ie start at pos 1 and take a length
       
   248 		// which is 2 shorter than the original descriptor
       
   249 		TPtrC8 domainMiddle = cookieDomain.Mid(1, cookieDomain.Length() - 2);
       
   250 		if(domainMiddle.Locate(dot) == KErrNotFound)
       
   251 			return EFalse;
       
   252 
       
   253 		// Reject the cookie if the domain differs by two or more levels from the uri
       
   254 		// ie if uri=www.x.y.com then accept a cookie with .x.y.com but reject .y.com
       
   255 		TInt pos = uriDomain.FindF(cookieDomain);
       
   256 		if(pos > 2)
       
   257 			{
       
   258 			const TDesC8& domainDiff = uriDomain.Left(pos);
       
   259 
       
   260 			// Remove one character from each end. ie start at pos 1 and take a length
       
   261 			// which is 2 shorter than the original descriptor
       
   262 			const TDesC8& diffMiddle = domainDiff.Mid(1, domainDiff.Length() - 2);
       
   263 			if(diffMiddle.Locate(dot) != KErrNotFound)
       
   264 				return EFalse;
       
   265 			}
       
   266 		}
       
   267 	else
       
   268 		{
       
   269 		// if the domain attribute is not found add it
       
   270 		THTTPHdrVal val(iStringPool.OpenFStringL(aUri.Extract(EUriHost)));
       
   271 		aCookie.SetAttributeL(CCookie::EDomain, val);
       
   272 		val.StrF().Close();
       
   273 		}
       
   274 
       
   275 	if(!CheckPortMatch(aCookie, aUri))
       
   276 		return EFalse;
       
   277 
       
   278 	return ETrue;
       
   279 	}
       
   280 
       
   281 TInt CExampleCookieManager::CompareCookiePaths(CCookie* const & aCookie1, CCookie* const & aCookie2)
       
   282 	{
       
   283 	THTTPHdrVal path1Val;
       
   284 	THTTPHdrVal path2Val;
       
   285 
       
   286 	// if the first cookie has no path then it must be smaller
       
   287 	if(aCookie1->Attribute(CCookie::EPath, path1Val) == KErrNotFound)
       
   288 		return -1;
       
   289 
       
   290 	if(aCookie2->Attribute(CCookie::EPath, path2Val) == KErrNotFound)
       
   291 		return 1;
       
   292 
       
   293 	TInt path1Count = CountSeparators(path1Val.StrF().DesC());
       
   294 	TInt path2Count = CountSeparators(path2Val.StrF().DesC());
       
   295 
       
   296 	return path1Count - path2Count;
       
   297 	}
       
   298 TInt CExampleCookieManager::CountSeparators(const TDesC8& aDes)
       
   299 	{
       
   300 	const TChar pathSeparator('/');
       
   301 	TInt numSeps = 0;
       
   302 
       
   303 	// Get all the descriptor to start with
       
   304 	TPtrC8 desPtr = aDes.Mid(0);
       
   305 	TInt sepPos = desPtr.Locate(pathSeparator);
       
   306 	while(sepPos != KErrNotFound)
       
   307 		{
       
   308 		++numSeps;
       
   309 
       
   310 		// Get the rest of the descriptor without the separator that we have found
       
   311 		desPtr.Set(desPtr.Mid(sepPos + 1));
       
   312 		sepPos = desPtr.Locate(pathSeparator);
       
   313 		}
       
   314 
       
   315 	return numSeps;
       
   316 	}
       
   317 
       
   318 TPtrC8 CExampleCookieManager::RemoveQuotes(const TDesC8& aDes) const
       
   319 	{
       
   320 	TChar quote('"');
       
   321 
       
   322 	if(aDes[0] == TUint(quote))
       
   323 		{
       
   324 		return aDes.Mid(1, aDes.Length() - 2);
       
   325 		}
       
   326 	else
       
   327 		return aDes;
       
   328 	}
       
   329