diff -r 000000000000 -r e4d67989cc36 genericservices/httputils/UriParser/TEquiv.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/genericservices/httputils/UriParser/TEquiv.cpp Tue Feb 02 02:01:42 2010 +0200 @@ -0,0 +1,447 @@ +// Copyright (c) 2004-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 "TEquiv.h" +#include +#include +#include "UriUtilsInternal.h" +#include +#include +#include + +_LIT8(KParamUserFull, ";user="); +_LIT8(KParamTtlFull, ";ttl="); +_LIT8(KParamMethodFull, ";method="); +_LIT8(KParamMaddrFull, ";maddr="); +_LIT8(KParamMaddr, "maddr"); + +_LIT8(KHeaderId, "call-id"); +_LIT8(KHeaderIdAbbr, "i"); +_LIT8(KHeaderContact, "contact"); +_LIT8(KHeaderContactAbbr, "m"); +_LIT8(KHeaderEncoding, "content-encoding"); +_LIT8(KHeaderEncodingAbbr, "e"); +_LIT8(KHeaderLength, "content-length"); +_LIT8(KHeaderLengthAbbr, "l"); +_LIT8(KHeaderType, "content-type"); +_LIT8(KHeaderTypeAbbr, "c"); +_LIT8(KHeaderFrom, "from"); +_LIT8(KHeaderFromAbbr, "f"); +_LIT8(KHeaderSubject, "subject"); +_LIT8(KHeaderSubjectAbbr, "s"); +_LIT8(KHeaderTo, "to"); +_LIT8(KHeaderToAbbr, "t"); + +TEquiv::TEquiv(const TUriC8& aLhs, const TUriC8& aRhs) +: iLhs(aLhs), iRhs(aRhs) + { + } + +TBool TEquiv::EquivalentL() const + { + if (!IsMatchSchemeL()) + return KUriUtilsErrDifferentScheme; + + if (!IsMatchUserInfoL()) + return KUriUtilsErrDifferentUserInfo; + + if (!IsMatchHostL()) + return KUriUtilsErrDifferentHost; + + if (!IsMatchPortL()) + return KUriUtilsErrDifferentPort; + + if (!IsMatchPathL()) + return KUriUtilsErrDifferentPath; + + if (!IsMatchQueryL()) + return KUriUtilsErrDifferentQuery; + + if (!IsMatchFragmentL()) + return KUriUtilsErrDifferentFragment; + + return KErrNone; + } + +TBool TEquiv::IsMatchSchemeL() const + { + HBufC8* lhsDes = DecodedSegmentLC(iLhs, EUriScheme); + HBufC8* rhsDes = DecodedSegmentLC(iRhs, EUriScheme); + TBool result = IsMatchCaseless(*lhsDes, *rhsDes); + CleanupStack::PopAndDestroy(2); + return result; + } + +TBool TEquiv::IsMatchUserInfoL() const + { + HBufC8* lhsDes = DecodedSegmentLC(iLhs, EUriUserinfo); + HBufC8* rhsDes = DecodedSegmentLC(iRhs, EUriUserinfo); + TBool result = IsMatchCaseSensitive(*lhsDes, *rhsDes); + CleanupStack::PopAndDestroy(2); + return result; + } + +TBool TEquiv::IsMatchHostL() const + { + HBufC8* lhsDes = DecodedSegmentLC(iLhs, EUriHost); + HBufC8* rhsDes = DecodedSegmentLC(iRhs, EUriHost); + TBool result = IsMatchCaseless(*lhsDes, *rhsDes); + CleanupStack::PopAndDestroy(2); + return result; + } + +TBool TEquiv::IsMatchPortL() const + { + HBufC8* lhsDes = DecodedSegmentLC(iLhs, EUriPort); + HBufC8* rhsDes = DecodedSegmentLC(iRhs, EUriPort); + TBool result = IsMatchCaseSensitive(*lhsDes, *rhsDes); + CleanupStack::PopAndDestroy(2); + return result; + } + +TBool TEquiv::IsMatchPathL() const + { + HBufC8* lhsDes = DecodedSegmentLC(iLhs, EUriPath); + HBufC8* rhsDes = DecodedSegmentLC(iRhs, EUriPath); + TBool result = IsMatchCaseSensitive(*lhsDes, *rhsDes); + CleanupStack::PopAndDestroy(2); + return result; + } + +TBool TEquiv::IsMatchQueryL() const + { + HBufC8* lhsDes = DecodedSegmentLC(iLhs, EUriQuery); + HBufC8* rhsDes = DecodedSegmentLC(iRhs, EUriQuery); + TBool result = IsMatchCaseSensitive(*lhsDes, *rhsDes); + CleanupStack::PopAndDestroy(2); + return result; + } + +TBool TEquiv::IsMatchFragmentL() const + { + HBufC8* lhsDes = DecodedSegmentLC(iLhs, EUriFragment); + HBufC8* rhsDes = DecodedSegmentLC(iRhs, EUriFragment); + TBool result = IsMatchCaseSensitive(*lhsDes, *rhsDes); + CleanupStack::PopAndDestroy(2); + return result; + } + +HBufC8* TEquiv::DecodedSegmentLC(const TUriC8& aUri, TUriComponent aSegmentType) const + { + HBufC8* decoded = EscapeUtils::EscapeDecodeL(aUri.Extract(aSegmentType)); + CleanupStack::PushL(decoded); + return decoded; + } + +TEquivSip::TEquivSip(const TUriC8& aLhs, const TUriC8& aRhs) +: TEquiv(aLhs, aRhs) + { + } + +void TEquivSip::RemoveLeadingZeros(TPtr8 aHost) const + { + for (TInt i=0; i < aHost.Length(); i++) + { + TBool startOfNumber = (i == 0 || aHost[i-1] < '0' || aHost[i-1] > '9'); + if (aHost[i] == '0' && startOfNumber) + { + // The character is a zero and is either at the start of the string + // or the fist number in a sequence. + aHost.Delete(i--,1); + } + } + } + +TBool TEquivSip::IsMatchHostL(const TDesC8& aLhs, const TDesC8& aRhs) const + { + UriUtils::TUriHostType lhsType = UriUtils::HostType(aLhs); + UriUtils::TUriHostType rhsType = UriUtils::HostType(aRhs); + if (lhsType != rhsType) + return EFalse; + if (lhsType != UriUtils::ETextHost) + { + // Host is IPv4 or IPv6 + // Create a copy of the hosts and remove any leading '0's + HBufC8* lhsCopy = aLhs.AllocLC(); + HBufC8* rhsCopy = aRhs.AllocLC(); + RemoveLeadingZeros(lhsCopy->Des()); + RemoveLeadingZeros(rhsCopy->Des()); + TBool result = IsMatchCaseSensitive(*lhsCopy, *rhsCopy); + CleanupStack::PopAndDestroy(2); + return result; + } + + return IsMatchCaseless(aLhs, aRhs); + } + +TBool TEquivSip::IsMatchHostL() const + { + HBufC8* lhsDes = DecodedSegmentLC(iLhs, EUriHost); + HBufC8* rhsDes = DecodedSegmentLC(iRhs, EUriHost); + TBool result = IsMatchHostL(*lhsDes, *rhsDes); + CleanupStack::PopAndDestroy(2); + return result; + } + +TBool TEquivSip::IsParamCompatibleL(const TDesC8& aLhsName, const TDesC8& aLhsValue, const TDesC8& aRhsName, const TDesC8& aRhsValue) const + { + // Were're just checking that if the segments have the same name part + // that their values are the same. This method only returns false if the lhs and rhs + // have the same name but their values are different. + if (!IsMatchCaseless(aLhsName, aRhsName)) + { + // Names don't match so we're OK + return ETrue; + } + + // The maddr parameter needs to be handled differently from the others + // The address is checked for equivalence not just a straight string compare. + if (IsMatchCaseless(aLhsName, KParamMaddr)) + { + return IsMatchHostL(aLhsValue, aRhsValue); + } + else + { + if (!IsMatchCaseless(aLhsValue, aRhsValue)) + { + // Names are the same but the values are different + // We have a incompatible parameter + return EFalse; + } + } + + return ETrue; + } + +TBool TEquivSip::IsParamListCompatibleL(const TDelimitedParserBase8& aLhsParser, const TDelimitedParserBase8& aRhsParser) const + + { + TPtrC8 lhsName; + TPtrC8 lhsValue; + TPtrC8 rhsName; + TPtrC8 rhsValue; + + TPtrC8 lhsSegment; + TPtrC8 rhsSegment; + + // roll back to the start of the lhs segment parser + aLhsParser.Reset(); + + while( aLhsParser.GetNext(lhsSegment) == KErrNone ) + { + // roll back to the start of the rhs segment parser + aRhsParser.Reset(); + + GetNameValuePair(lhsSegment, lhsName, lhsValue); + while( aRhsParser.GetNext(rhsSegment) == KErrNone ) + { + GetNameValuePair(rhsSegment, rhsName, rhsValue); + if (!IsParamCompatibleL(lhsName, lhsValue, rhsName, rhsValue)) + return EFalse; + } + } + + return ETrue; + } + +TInt TEquivSip::ListLength(const TDelimitedParserBase8& aParser) const + { + aParser.Reset(); + + TInt result = 0; + while (!aParser.Eos()) + { + aParser.Inc(); + ++result; + } + + aParser.Reset(); + return result; + } + +TBool TEquivSip::IsMatchPathL() const + { + HBufC8* lhs = DecodedSegmentLC(iLhs, EUriPath); + HBufC8* rhs = DecodedSegmentLC(iRhs, EUriPath); + + TDelimitedPathSegmentParser8 lhsParser; + lhsParser.Parse(*lhs); + TDelimitedPathSegmentParser8 rhsParser; + rhsParser.Parse(*rhs); + + // Check each parameter in the lhs parameter list with those in + // the rhs parameter list. If at any point a parameter is incompatible + // we'll return false. + TBool result = ETrue; + + // Alway check the parameter list with the most parameters against the other + // so that we don't miss any + TInt lhsLength = ListLength(lhsParser); + TInt rhsLength = ListLength(rhsParser); + + if (lhsLength > rhsLength) + { + result = IsParamListCompatibleL(lhsParser, rhsParser); + } + else + { + result = IsParamListCompatibleL(rhsParser, lhsParser); + } + + // check that the special parameters, if present, are present in both + if (result) + { + if ((lhs->Find(KParamUserFull) == KErrNotFound) != (rhs->Find(KParamUserFull) == KErrNotFound) || + (lhs->Find(KParamTtlFull) == KErrNotFound) != (rhs->Find(KParamTtlFull) == KErrNotFound) || + (lhs->Find(KParamMethodFull) == KErrNotFound) != (rhs->Find(KParamMethodFull) == KErrNotFound) || + (lhs->Find(KParamMaddrFull) == KErrNotFound) != (rhs->Find(KParamMaddrFull) == KErrNotFound) ) + { + result = EFalse; + } + } + + CleanupStack::PopAndDestroy(2); + return result; + } + + +TEquivSip::THeaderType TEquivSip::HeaderType(const TDesC8& aHeaderName) const + { + if (IsMatchCaseless(aHeaderName, KHeaderId) || IsMatchCaseless(aHeaderName, KHeaderIdAbbr)) + return EHeaderId; + if (IsMatchCaseless(aHeaderName, KHeaderContact) || IsMatchCaseless(aHeaderName, KHeaderContactAbbr)) + return EHeaderContact; + if (IsMatchCaseless(aHeaderName, KHeaderEncoding) || IsMatchCaseless(aHeaderName, KHeaderEncodingAbbr)) + return EHeaderEncoding; + if (IsMatchCaseless(aHeaderName, KHeaderLength) || IsMatchCaseless(aHeaderName, KHeaderLengthAbbr)) + return EHeaderLength; + if (IsMatchCaseless(aHeaderName, KHeaderType) || IsMatchCaseless(aHeaderName, KHeaderTypeAbbr)) + return EHeaderType; + if (IsMatchCaseless(aHeaderName, KHeaderFrom) || IsMatchCaseless(aHeaderName, KHeaderFromAbbr)) + return EHeaderFrom; + if (IsMatchCaseless(aHeaderName, KHeaderSubject) || IsMatchCaseless(aHeaderName, KHeaderSubjectAbbr)) + return EHeaderSubject; + if (IsMatchCaseless(aHeaderName, KHeaderTo) || IsMatchCaseless(aHeaderName, KHeaderToAbbr)) + return EHeaderTo; + + return EHeaderNormal; + } + +TBool TEquivSip::IsMatchHeader(const TDesC8& aLhs, const TDesC8& aRhs) const + { + if (IsMatchCaseless(aLhs, aRhs)) + { + // identical headers are always OK + return ETrue; + } + + // We now need to check for abbreviated headers + TPtrC8 lhsName; + TPtrC8 lhsValue; + TPtrC8 rhsName; + TPtrC8 rhsValue; + + GetNameValuePair(aLhs, lhsName, lhsValue); + GetNameValuePair(aRhs, rhsName, rhsValue); + + if (!IsMatchCaseless(lhsValue, rhsValue)) + { + // headers with different values can never match + return EFalse; + } + + // We now have only those with different header names but with the same value + // The last check is to see if the headers are in abbreviated forms + THeaderType lhsType = HeaderType(lhsName); + THeaderType rhsType = HeaderType(rhsName); + if (lhsType != EHeaderNormal && (lhsType == rhsType)) + { + // They are both special headers of the same type + // Everything matches + return ETrue; + } + + return EFalse; + } + +TBool TEquivSip::IsQueryListCompatible(const TDelimitedParserBase8& aLhsParser, const TDelimitedParserBase8& aRhsParser) const + + { + TPtrC8 lhsSegment; + TPtrC8 rhsSegment; + + TBool found = EFalse; + // roll back to the start of the lhs segment parser + aLhsParser.Reset(); + + while( aLhsParser.GetNext(lhsSegment) == KErrNone ) + { + // roll back to the start of the rhs segment parser + aRhsParser.Reset(); + + found = EFalse; + + while( aRhsParser.GetNext(rhsSegment) == KErrNone ) + { + if (IsMatchHeader(lhsSegment, rhsSegment)) + { + // a match has been found for this header so move to the next + // header in the lhs list + found = ETrue; + break; + } + } + if (!found) + { + // no match has been found so the headers are not equvalent + return EFalse; + } + } + + return ETrue; + } + +TBool TEquivSip::IsMatchQueryL() const + { + HBufC8* lhs = DecodedSegmentLC(iLhs, EUriQuery); + HBufC8* rhs = DecodedSegmentLC(iRhs, EUriQuery); + + TDelimitedQueryParser8 lhsParser; + lhsParser.Parse(*lhs); + TDelimitedQueryParser8 rhsParser; + rhsParser.Parse(*rhs); + + TBool result = EFalse; + + // first check that the number of headers are the same in both lists. + TInt lhsLength = ListLength(lhsParser); + TInt rhsLength = ListLength(rhsParser); + if (lhsLength == rhsLength) + { + // Check each parameter in the lhs parameter list with those in + // the rhs parameter list. If at any point a parameter is incompatible + // we'll return false. + result = IsQueryListCompatible(lhsParser, rhsParser); + } + + CleanupStack::PopAndDestroy(2); + return result; + } + +TBool TEquivSip::IsMatchFragmentL() const + { + // We don't care about the fragment for SIP URIs + return ETrue; + }