--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/applayerprotocols/httpexamples/cookies/example/examplecookiemanager.cpp Tue Feb 02 01:09:52 2010 +0200
@@ -0,0 +1,329 @@
+// Copyright (c) 2001-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 "examplecookiemanager.h"
+#include "httpcookieerr.h"
+
+#include <http/ccookie.h>
+#include <http/thttphdrval.h>
+
+EXPORT_C CExampleCookieManager* CExampleCookieManager::NewL(RStringPool aStringPool)
+ {
+ CExampleCookieManager* cookieManager = new(ELeave)CExampleCookieManager(aStringPool);
+ return cookieManager;
+ }
+
+EXPORT_C CExampleCookieManager::~CExampleCookieManager()
+ {
+ // At this point a real cookie manager would go through the list of cookies
+ // and destroy any that don't have an Expires or MaxAge attribute (because they
+ // should only last for the session).
+ // Any remaining ones should be persisted till the next session.
+
+ // However, we don't persist for this implementation
+ iCookies.ResetAndDestroy();
+ }
+
+CExampleCookieManager::CExampleCookieManager(RStringPool aStringPool) :
+ iStringPool(aStringPool)
+ {
+ }
+
+EXPORT_C void CExampleCookieManager::StoreCookieL(CCookie* aCookie, const TUriC8& aUri)
+ {
+ CleanupStack::PushL(aCookie);
+
+ if(ValidateCookieL(*aCookie, aUri))
+ {
+ User::LeaveIfError(iCookies.Append(aCookie));
+ CleanupStack::Pop(aCookie);
+ }
+ else
+ CleanupStack::PopAndDestroy(aCookie);
+ }
+
+EXPORT_C void CExampleCookieManager::GetCookiesL(RHTTPTransaction aTransaction,
+ RArray<CCookie*>& aCookieList,
+ TBool& aCookie2Reqd)
+ {
+ // For comparing cookies to insert them in the correct order to the returned array
+ TLinearOrder<CCookie*> compareFunc(CompareCookiePaths);
+
+ // Ensure the array is empty
+ __ASSERT_DEBUG(aCookieList.Count()==0, HTTPCookiePanic::Panic(HTTPCookiePanic::EGetCookiesArrayNotEmpty));
+
+ const TInt numCookies = iCookies.Count();
+ for (TInt ii=0; ii<numCookies; ++ii)
+ {
+ CCookie* cookie = iCookies[ii];
+ const TUriC8& uri = aTransaction.Request().URI();
+
+ if(CheckDomainMatch(*cookie, uri) &&
+ CheckPathMatch(*cookie, uri) &&
+ CheckPortMatch(*cookie, uri) &&
+ CheckSecureMatch(*cookie, uri))
+ {
+ User::LeaveIfError(aCookieList.InsertInOrderAllowRepeats(cookie, compareFunc));
+
+ if(!cookie->FromCookie2())
+ aCookie2Reqd = ETrue;
+ }
+ }
+ }
+
+TBool CExampleCookieManager::CheckDomainMatch(CCookie& aCookie, const TUriC8& aUri) const
+ {
+ TChar domainSep = '.';
+
+ if(aUri.IsPresent(EUriHost))
+ {
+ THTTPHdrVal attributeVal;
+ aCookie.Attribute(CCookie::EDomain, attributeVal);
+
+ const TDesC8& domain = aUri.Extract(EUriHost);
+ const TPtrC8 cookieDomain = RemoveQuotes(attributeVal.StrF().DesC());
+
+ // Domain matching rules:
+ // if the cookie domain doesn't start with a dot then it must match the uri domain exactly
+ // if it does start with a dot and it
+ TInt matchLoc = domain.FindF(cookieDomain);
+ if((cookieDomain[0] != TUint(domainSep)) &&
+ (matchLoc == 0) &&
+ (domain.Length() == cookieDomain.Length()))
+ return ETrue;
+ else if((matchLoc != KErrNotFound) &&
+ (domain.Left(matchLoc).Locate(domainSep) == KErrNotFound))
+ return ETrue;
+ }
+
+ return EFalse;
+ }
+
+TBool CExampleCookieManager::CheckPathMatch(CCookie& aCookie, const TUriC8& aUri) const
+ {
+ THTTPHdrVal attributeVal;
+ aCookie.Attribute(CCookie::EPath, attributeVal);
+ TPtrC8 cookiePath = RemoveQuotes(attributeVal.StrF().DesC());
+
+ const TDesC8& uriPath = aUri.Extract(EUriPath);
+ if(uriPath.Length() == 0)
+ {
+ // if the uri has no path then it matches against no cookie path
+ // or a cookie path of just a /
+ const TInt pathLength = cookiePath.Length();
+ if(pathLength == 0 || pathLength == 1)
+ return ETrue;
+ }
+ else if(uriPath.FindF(cookiePath) == 0)
+ {
+ TChar separator('/');
+ // Check that the character after the matched bit is a / otherwise
+ // /path would match against /path2
+ const TInt uriLength = uriPath.Length();
+ const TInt cookieLength = cookiePath.Length();
+
+ if(uriLength == cookieLength)
+ return ETrue;
+ else if(uriLength > cookieLength)
+ {
+ if(cookiePath[cookieLength - 1] == TUint(separator))
+ return ETrue;
+ else if(uriPath[cookieLength] == TUint(separator))
+ return ETrue;
+ }
+ }
+
+ return EFalse;
+ }
+
+TBool CExampleCookieManager::CheckPortMatch(CCookie& aCookie, const TUriC8& aUri) const
+ {
+ THTTPHdrVal val;
+ if(aCookie.Attribute(CCookie::EPort, val) == KErrNone)
+ {
+ TChar portSeparator(',');
+ _LIT8(KDefaultPort, "80");
+
+ const TDesC8& port = aUri.IsPresent(EUriPort)? aUri.Extract(EUriPort) : KDefaultPort();
+
+ const TPtrC8& portList = RemoveQuotes(val.StrF().DesC());
+ TInt portPos = portList.FindF(port);
+ // if we do not find the port in the list then do not match
+ if(portPos == KErrNotFound)
+ return EFalse;
+ // if the number was the last in the list then match
+ else if((portPos + port.Length()) == portList.Length())
+ return ETrue;
+ // check that the number is followed by a separator ie do not match 80 with 8000
+ else if(portList[portPos + port.Length()] == TUint(portSeparator))
+ return ETrue;
+ // we have not found a match
+ else
+ return EFalse;
+ }
+
+ // If the cookie does not have a portlist return ETrue to match any port
+ return ETrue;
+ }
+
+TBool CExampleCookieManager::CheckSecureMatch(CCookie& aCookie, const TUriC8& aUri) const
+ {
+ THTTPHdrVal val;
+ TBool secureCookie = aCookie.Attribute(CCookie::ESecure, val) == KErrNone;
+
+ // if the cookie is not secure we don't care about the uri
+ if(!secureCookie)
+ return ETrue;
+
+ // Check if the scheme is https - if there is no scheme then assume not
+ if(aUri.IsPresent(EUriScheme))
+ {
+ _LIT8(KSecureScheme, "https");
+ const TDesC8& scheme = aUri.Extract(EUriScheme);
+ return scheme.CompareF(KSecureScheme()) == 0;
+ }
+
+ // The cookie is secure and we don't have a secure transaction
+ return EFalse;
+ }
+
+TBool CExampleCookieManager::ValidateCookieL(CCookie& aCookie, const TUriC8& aUri)
+ {
+ THTTPHdrVal attributeVal;
+
+ if(aCookie.Attribute(CCookie::EPath, attributeVal) == KErrNone)
+ {
+ // if the path attribute exists check it is a prefix of the path
+ // of the uri that issued it (if not reject)
+ RStringF cookiePath = attributeVal.StrF();
+ const TDesC8& uriPath = aUri.Extract(EUriPath);
+ if(uriPath.FindF(RemoveQuotes(cookiePath.DesC())) != 0)
+ return EFalse;
+ }
+ else
+ {
+ // if the path attribute doesn't exist add it
+ THTTPHdrVal val(iStringPool.OpenFStringL(aUri.Extract(EUriPath)));
+ aCookie.SetAttributeL(CCookie::EPath, val);
+ }
+
+ if(aCookie.Attribute(CCookie::EDomain, attributeVal) == KErrNone)
+ {
+ const TChar dot('.');
+ const TDesC8& cookieDomain = attributeVal.StrF().DesC();
+ const TDesC8& uriDomain = aUri.Extract(EUriHost);
+
+ // if the domain does not exactly match the uri and does not begin
+ // with a dot then add one
+ if((cookieDomain.Compare(uriDomain) != 0) &&
+ (cookieDomain.Locate(dot) != 0))
+ {
+ _LIT8(KAddDotString, ".%S");
+ HBufC8* newDomain = HBufC8::NewLC(cookieDomain.Length() + 1);
+ newDomain->Des().AppendFormat(KAddDotString(), &cookieDomain);
+
+ RStringF domain = iStringPool.OpenFStringL(*newDomain);
+ CleanupStack::PopAndDestroy(newDomain);
+
+ THTTPHdrVal val(domain);
+ aCookie.SetAttributeL(CCookie::EDomain, val);
+ domain.Close();
+ }
+
+ // if the domain does not contain an embedded dot then reject it
+ // ie reject .com or .com.
+ // Start by removing one character from each end. ie start at pos 1 and take a length
+ // which is 2 shorter than the original descriptor
+ TPtrC8 domainMiddle = cookieDomain.Mid(1, cookieDomain.Length() - 2);
+ if(domainMiddle.Locate(dot) == KErrNotFound)
+ return EFalse;
+
+ // Reject the cookie if the domain differs by two or more levels from the uri
+ // ie if uri=www.x.y.com then accept a cookie with .x.y.com but reject .y.com
+ TInt pos = uriDomain.FindF(cookieDomain);
+ if(pos > 2)
+ {
+ const TDesC8& domainDiff = uriDomain.Left(pos);
+
+ // Remove one character from each end. ie start at pos 1 and take a length
+ // which is 2 shorter than the original descriptor
+ const TDesC8& diffMiddle = domainDiff.Mid(1, domainDiff.Length() - 2);
+ if(diffMiddle.Locate(dot) != KErrNotFound)
+ return EFalse;
+ }
+ }
+ else
+ {
+ // if the domain attribute is not found add it
+ THTTPHdrVal val(iStringPool.OpenFStringL(aUri.Extract(EUriHost)));
+ aCookie.SetAttributeL(CCookie::EDomain, val);
+ val.StrF().Close();
+ }
+
+ if(!CheckPortMatch(aCookie, aUri))
+ return EFalse;
+
+ return ETrue;
+ }
+
+TInt CExampleCookieManager::CompareCookiePaths(CCookie* const & aCookie1, CCookie* const & aCookie2)
+ {
+ THTTPHdrVal path1Val;
+ THTTPHdrVal path2Val;
+
+ // if the first cookie has no path then it must be smaller
+ if(aCookie1->Attribute(CCookie::EPath, path1Val) == KErrNotFound)
+ return -1;
+
+ if(aCookie2->Attribute(CCookie::EPath, path2Val) == KErrNotFound)
+ return 1;
+
+ TInt path1Count = CountSeparators(path1Val.StrF().DesC());
+ TInt path2Count = CountSeparators(path2Val.StrF().DesC());
+
+ return path1Count - path2Count;
+ }
+TInt CExampleCookieManager::CountSeparators(const TDesC8& aDes)
+ {
+ const TChar pathSeparator('/');
+ TInt numSeps = 0;
+
+ // Get all the descriptor to start with
+ TPtrC8 desPtr = aDes.Mid(0);
+ TInt sepPos = desPtr.Locate(pathSeparator);
+ while(sepPos != KErrNotFound)
+ {
+ ++numSeps;
+
+ // Get the rest of the descriptor without the separator that we have found
+ desPtr.Set(desPtr.Mid(sepPos + 1));
+ sepPos = desPtr.Locate(pathSeparator);
+ }
+
+ return numSeps;
+ }
+
+TPtrC8 CExampleCookieManager::RemoveQuotes(const TDesC8& aDes) const
+ {
+ TChar quote('"');
+
+ if(aDes[0] == TUint(quote))
+ {
+ return aDes.Mid(1, aDes.Length() - 2);
+ }
+ else
+ return aDes;
+ }
+