os/ossrv/genericservices/httputils/UriParser/TEquiv.cpp
changeset 0 bde4ae8d615e
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/os/ossrv/genericservices/httputils/UriParser/TEquiv.cpp	Fri Jun 15 03:10:57 2012 +0200
     1.3 @@ -0,0 +1,447 @@
     1.4 +// Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies).
     1.5 +// All rights reserved.
     1.6 +// This component and the accompanying materials are made available
     1.7 +// under the terms of "Eclipse Public License v1.0"
     1.8 +// which accompanies this distribution, and is available
     1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
    1.10 +//
    1.11 +// Initial Contributors:
    1.12 +// Nokia Corporation - initial contribution.
    1.13 +//
    1.14 +// Contributors:
    1.15 +//
    1.16 +// Description:
    1.17 +//
    1.18 +
    1.19 +#include "TEquiv.h"
    1.20 +#include <uriutils.h>
    1.21 +#include <uriutilscommon.h>
    1.22 +#include "UriUtilsInternal.h"
    1.23 +#include <delimitedpathsegment8.h>
    1.24 +#include <delimitedquery8.h>
    1.25 +#include <escapeutils.h>
    1.26 +
    1.27 +_LIT8(KParamUserFull,	";user=");
    1.28 +_LIT8(KParamTtlFull,	";ttl=");
    1.29 +_LIT8(KParamMethodFull,	";method=");
    1.30 +_LIT8(KParamMaddrFull,	";maddr=");
    1.31 +_LIT8(KParamMaddr,		"maddr");
    1.32 +
    1.33 +_LIT8(KHeaderId, "call-id");
    1.34 +_LIT8(KHeaderIdAbbr, "i");
    1.35 +_LIT8(KHeaderContact, "contact");
    1.36 +_LIT8(KHeaderContactAbbr, "m");
    1.37 +_LIT8(KHeaderEncoding, "content-encoding");
    1.38 +_LIT8(KHeaderEncodingAbbr, "e");
    1.39 +_LIT8(KHeaderLength, "content-length");
    1.40 +_LIT8(KHeaderLengthAbbr, "l");
    1.41 +_LIT8(KHeaderType, "content-type");
    1.42 +_LIT8(KHeaderTypeAbbr, "c");
    1.43 +_LIT8(KHeaderFrom, "from");
    1.44 +_LIT8(KHeaderFromAbbr, "f");
    1.45 +_LIT8(KHeaderSubject, "subject");
    1.46 +_LIT8(KHeaderSubjectAbbr, "s");
    1.47 +_LIT8(KHeaderTo, "to");
    1.48 +_LIT8(KHeaderToAbbr, "t");
    1.49 +
    1.50 +TEquiv::TEquiv(const TUriC8& aLhs, const TUriC8& aRhs)
    1.51 +: iLhs(aLhs), iRhs(aRhs)
    1.52 +	{
    1.53 +	}
    1.54 +
    1.55 +TBool TEquiv::EquivalentL() const
    1.56 +	{
    1.57 +	if (!IsMatchSchemeL())
    1.58 +		return KUriUtilsErrDifferentScheme;
    1.59 +	
    1.60 +	if (!IsMatchUserInfoL())
    1.61 +		return KUriUtilsErrDifferentUserInfo;
    1.62 +	
    1.63 +	if (!IsMatchHostL())
    1.64 +		return KUriUtilsErrDifferentHost;
    1.65 +	
    1.66 +	if (!IsMatchPortL())
    1.67 +		return KUriUtilsErrDifferentPort;
    1.68 +	
    1.69 +	if (!IsMatchPathL())
    1.70 +		return KUriUtilsErrDifferentPath;
    1.71 +	
    1.72 +	if (!IsMatchQueryL())
    1.73 +		return KUriUtilsErrDifferentQuery;
    1.74 +	
    1.75 +	if (!IsMatchFragmentL())
    1.76 +		return KUriUtilsErrDifferentFragment;
    1.77 +	
    1.78 +	return KErrNone;
    1.79 +	}
    1.80 +
    1.81 +TBool TEquiv::IsMatchSchemeL() const
    1.82 +	{
    1.83 +	HBufC8* lhsDes = DecodedSegmentLC(iLhs, EUriScheme);
    1.84 +	HBufC8* rhsDes = DecodedSegmentLC(iRhs, EUriScheme);
    1.85 +	TBool result = IsMatchCaseless(*lhsDes, *rhsDes);
    1.86 +	CleanupStack::PopAndDestroy(2);
    1.87 +	return result;
    1.88 +	}
    1.89 +
    1.90 +TBool TEquiv::IsMatchUserInfoL() const
    1.91 +	{
    1.92 +	HBufC8* lhsDes = DecodedSegmentLC(iLhs, EUriUserinfo);
    1.93 +	HBufC8* rhsDes = DecodedSegmentLC(iRhs, EUriUserinfo);
    1.94 +	TBool result = IsMatchCaseSensitive(*lhsDes, *rhsDes);
    1.95 +	CleanupStack::PopAndDestroy(2);
    1.96 +	return result;
    1.97 +	}
    1.98 +
    1.99 +TBool TEquiv::IsMatchHostL() const
   1.100 +	{
   1.101 +	HBufC8* lhsDes = DecodedSegmentLC(iLhs, EUriHost);
   1.102 +	HBufC8* rhsDes = DecodedSegmentLC(iRhs, EUriHost);
   1.103 +	TBool result = IsMatchCaseless(*lhsDes, *rhsDes);
   1.104 +	CleanupStack::PopAndDestroy(2);
   1.105 +	return result;
   1.106 +	}
   1.107 +
   1.108 +TBool TEquiv::IsMatchPortL() const
   1.109 +	{
   1.110 +	HBufC8* lhsDes = DecodedSegmentLC(iLhs, EUriPort);
   1.111 +	HBufC8* rhsDes = DecodedSegmentLC(iRhs, EUriPort);
   1.112 +	TBool result = IsMatchCaseSensitive(*lhsDes, *rhsDes);
   1.113 +	CleanupStack::PopAndDestroy(2);
   1.114 +	return result;
   1.115 +	}
   1.116 +
   1.117 +TBool TEquiv::IsMatchPathL() const
   1.118 +	{
   1.119 +	HBufC8* lhsDes = DecodedSegmentLC(iLhs, EUriPath);
   1.120 +	HBufC8* rhsDes = DecodedSegmentLC(iRhs, EUriPath);
   1.121 +	TBool result = IsMatchCaseSensitive(*lhsDes, *rhsDes);
   1.122 +	CleanupStack::PopAndDestroy(2);
   1.123 +	return result;
   1.124 +	}
   1.125 +
   1.126 +TBool TEquiv::IsMatchQueryL() const
   1.127 +	{
   1.128 +	HBufC8* lhsDes = DecodedSegmentLC(iLhs, EUriQuery);
   1.129 +	HBufC8* rhsDes = DecodedSegmentLC(iRhs, EUriQuery);
   1.130 +	TBool result = IsMatchCaseSensitive(*lhsDes, *rhsDes);
   1.131 +	CleanupStack::PopAndDestroy(2);
   1.132 +	return result;
   1.133 +	}
   1.134 +
   1.135 +TBool TEquiv::IsMatchFragmentL() const
   1.136 +	{
   1.137 +	HBufC8* lhsDes = DecodedSegmentLC(iLhs, EUriFragment);
   1.138 +	HBufC8* rhsDes = DecodedSegmentLC(iRhs, EUriFragment);
   1.139 +	TBool result = IsMatchCaseSensitive(*lhsDes, *rhsDes);
   1.140 +	CleanupStack::PopAndDestroy(2);
   1.141 +	return result;
   1.142 +	}
   1.143 +
   1.144 +HBufC8* TEquiv::DecodedSegmentLC(const TUriC8& aUri, TUriComponent aSegmentType) const
   1.145 +	{
   1.146 +	HBufC8* decoded = EscapeUtils::EscapeDecodeL(aUri.Extract(aSegmentType));
   1.147 +	CleanupStack::PushL(decoded);
   1.148 +	return decoded;
   1.149 +	}
   1.150 +
   1.151 +TEquivSip::TEquivSip(const TUriC8& aLhs, const TUriC8& aRhs)
   1.152 +: TEquiv(aLhs, aRhs)
   1.153 +	{
   1.154 +	}
   1.155 +
   1.156 +void TEquivSip::RemoveLeadingZeros(TPtr8 aHost) const
   1.157 +	{
   1.158 +	for (TInt i=0; i < aHost.Length(); i++)
   1.159 +		{
   1.160 +		TBool startOfNumber = (i == 0 || aHost[i-1] < '0' || aHost[i-1] > '9');
   1.161 +		if (aHost[i] == '0' && startOfNumber)
   1.162 +			{
   1.163 +			// The character is a zero and is either at the start of the string
   1.164 +			// or the fist number in a sequence.
   1.165 +			aHost.Delete(i--,1);
   1.166 +			}
   1.167 +		}
   1.168 +	}
   1.169 +
   1.170 +TBool TEquivSip::IsMatchHostL(const TDesC8& aLhs, const TDesC8& aRhs) const
   1.171 +	{
   1.172 +	UriUtils::TUriHostType lhsType = UriUtils::HostType(aLhs);
   1.173 +	UriUtils::TUriHostType rhsType = UriUtils::HostType(aRhs);
   1.174 +	if (lhsType != rhsType)
   1.175 +		return EFalse;
   1.176 +	if (lhsType != UriUtils::ETextHost)
   1.177 +		{
   1.178 +		// Host is IPv4 or IPv6
   1.179 +		// Create a copy of the hosts and remove any leading '0's
   1.180 +		HBufC8* lhsCopy = aLhs.AllocLC();
   1.181 +		HBufC8* rhsCopy = aRhs.AllocLC();
   1.182 +		RemoveLeadingZeros(lhsCopy->Des());
   1.183 +		RemoveLeadingZeros(rhsCopy->Des());
   1.184 +		TBool result = IsMatchCaseSensitive(*lhsCopy, *rhsCopy);
   1.185 +		CleanupStack::PopAndDestroy(2);
   1.186 +		return result;
   1.187 +		}
   1.188 +
   1.189 +	return IsMatchCaseless(aLhs, aRhs);
   1.190 +	}
   1.191 +
   1.192 +TBool TEquivSip::IsMatchHostL() const
   1.193 +	{
   1.194 +	HBufC8* lhsDes = DecodedSegmentLC(iLhs, EUriHost);
   1.195 +	HBufC8* rhsDes = DecodedSegmentLC(iRhs, EUriHost);
   1.196 +	TBool result = IsMatchHostL(*lhsDes, *rhsDes);
   1.197 +	CleanupStack::PopAndDestroy(2);
   1.198 +	return result;
   1.199 +	}
   1.200 +
   1.201 +TBool TEquivSip::IsParamCompatibleL(const TDesC8& aLhsName, const TDesC8& aLhsValue, const TDesC8& aRhsName, const TDesC8& aRhsValue) const
   1.202 +	{
   1.203 +	// Were're just checking that if the segments have the same name part
   1.204 +	// that their values are the same. This method only returns false if the lhs and rhs
   1.205 +	// have the same name but their values are different.
   1.206 +	if (!IsMatchCaseless(aLhsName, aRhsName))
   1.207 +		{
   1.208 +		// Names don't match so we're OK
   1.209 +		return ETrue;
   1.210 +		}
   1.211 +
   1.212 +	// The maddr parameter needs to be handled differently from the others
   1.213 +	// The address is checked for equivalence not just a straight string compare.
   1.214 +	if (IsMatchCaseless(aLhsName, KParamMaddr))
   1.215 +		{
   1.216 +			return IsMatchHostL(aLhsValue, aRhsValue);
   1.217 +		}
   1.218 +	else
   1.219 +		{
   1.220 +		if (!IsMatchCaseless(aLhsValue, aRhsValue))
   1.221 +			{
   1.222 +			// Names are the same but the values are different
   1.223 +			// We have a incompatible parameter
   1.224 +			return EFalse;
   1.225 +			}
   1.226 +		}
   1.227 +
   1.228 +	return ETrue;
   1.229 +	}
   1.230 +
   1.231 +TBool TEquivSip::IsParamListCompatibleL(const TDelimitedParserBase8& aLhsParser, const TDelimitedParserBase8& aRhsParser) const
   1.232 +
   1.233 +	{
   1.234 +	TPtrC8 lhsName;
   1.235 +	TPtrC8 lhsValue;
   1.236 +	TPtrC8 rhsName;
   1.237 +	TPtrC8 rhsValue;
   1.238 +
   1.239 +	TPtrC8 lhsSegment;
   1.240 +	TPtrC8 rhsSegment;
   1.241 +
   1.242 +	// roll back to the start of the lhs segment parser
   1.243 +	aLhsParser.Reset();
   1.244 +	
   1.245 +	while( aLhsParser.GetNext(lhsSegment) == KErrNone )
   1.246 +		{
   1.247 +		// roll back to the start of the rhs segment parser
   1.248 +		aRhsParser.Reset();
   1.249 +
   1.250 +		GetNameValuePair(lhsSegment, lhsName, lhsValue);
   1.251 +		while( aRhsParser.GetNext(rhsSegment) == KErrNone )
   1.252 +			{
   1.253 +			GetNameValuePair(rhsSegment, rhsName, rhsValue);
   1.254 +			if (!IsParamCompatibleL(lhsName, lhsValue, rhsName, rhsValue))
   1.255 +				return EFalse;
   1.256 +			}
   1.257 +		}
   1.258 +
   1.259 +	return ETrue;
   1.260 +	}
   1.261 +
   1.262 +TInt TEquivSip::ListLength(const TDelimitedParserBase8& aParser) const
   1.263 +	{
   1.264 +	aParser.Reset();
   1.265 +	
   1.266 +	TInt result = 0;
   1.267 +	while (!aParser.Eos())
   1.268 +		{
   1.269 +		aParser.Inc();
   1.270 +		++result;
   1.271 +		}
   1.272 +		
   1.273 +	aParser.Reset();
   1.274 +	return result;
   1.275 +	}
   1.276 +
   1.277 +TBool TEquivSip::IsMatchPathL() const
   1.278 +	{
   1.279 +	HBufC8* lhs = DecodedSegmentLC(iLhs, EUriPath);
   1.280 +	HBufC8* rhs = DecodedSegmentLC(iRhs, EUriPath);
   1.281 +
   1.282 +	TDelimitedPathSegmentParser8 lhsParser;
   1.283 +	lhsParser.Parse(*lhs);
   1.284 +	TDelimitedPathSegmentParser8 rhsParser;
   1.285 +	rhsParser.Parse(*rhs);
   1.286 +	
   1.287 +	// Check each parameter in the lhs parameter list with those in
   1.288 +	// the rhs parameter list. If at any point a parameter is incompatible
   1.289 +	// we'll return false.
   1.290 +	TBool result = ETrue;
   1.291 +	
   1.292 +	// Alway check the parameter list with the most parameters against the other
   1.293 +	// so that we don't miss any
   1.294 +	TInt lhsLength = ListLength(lhsParser);
   1.295 +	TInt rhsLength = ListLength(rhsParser);
   1.296 +	
   1.297 +	if (lhsLength > rhsLength)
   1.298 +		{
   1.299 +		result = IsParamListCompatibleL(lhsParser, rhsParser);
   1.300 +		}
   1.301 +	else
   1.302 +		{
   1.303 +		result = IsParamListCompatibleL(rhsParser, lhsParser);
   1.304 +		}
   1.305 +
   1.306 +	// check that the special parameters, if present, are present in both
   1.307 +	if (result)
   1.308 +		{
   1.309 +		if ((lhs->Find(KParamUserFull) == KErrNotFound) != (rhs->Find(KParamUserFull) == KErrNotFound) ||
   1.310 +		    (lhs->Find(KParamTtlFull) == KErrNotFound) != (rhs->Find(KParamTtlFull) == KErrNotFound) ||
   1.311 +		    (lhs->Find(KParamMethodFull) == KErrNotFound) != (rhs->Find(KParamMethodFull) == KErrNotFound) ||
   1.312 +		    (lhs->Find(KParamMaddrFull) == KErrNotFound) != (rhs->Find(KParamMaddrFull) == KErrNotFound) )
   1.313 +			{
   1.314 +			result = EFalse;
   1.315 +			}
   1.316 +		}
   1.317 +	
   1.318 +	CleanupStack::PopAndDestroy(2);
   1.319 +	return result;
   1.320 +	}
   1.321 +
   1.322 +
   1.323 +TEquivSip::THeaderType TEquivSip::HeaderType(const TDesC8& aHeaderName) const
   1.324 +	{
   1.325 +	if (IsMatchCaseless(aHeaderName, KHeaderId) || IsMatchCaseless(aHeaderName, KHeaderIdAbbr))
   1.326 +		return EHeaderId;
   1.327 +	if (IsMatchCaseless(aHeaderName, KHeaderContact) || IsMatchCaseless(aHeaderName, KHeaderContactAbbr))
   1.328 +		return EHeaderContact;
   1.329 +	if (IsMatchCaseless(aHeaderName, KHeaderEncoding) || IsMatchCaseless(aHeaderName, KHeaderEncodingAbbr))
   1.330 +		return EHeaderEncoding;
   1.331 +	if (IsMatchCaseless(aHeaderName, KHeaderLength) || IsMatchCaseless(aHeaderName, KHeaderLengthAbbr))
   1.332 +		return EHeaderLength;
   1.333 +	if (IsMatchCaseless(aHeaderName, KHeaderType) || IsMatchCaseless(aHeaderName, KHeaderTypeAbbr))
   1.334 +		return EHeaderType;
   1.335 +	if (IsMatchCaseless(aHeaderName, KHeaderFrom) || IsMatchCaseless(aHeaderName, KHeaderFromAbbr))
   1.336 +		return EHeaderFrom;
   1.337 +	if (IsMatchCaseless(aHeaderName, KHeaderSubject) || IsMatchCaseless(aHeaderName, KHeaderSubjectAbbr))
   1.338 +		return EHeaderSubject;
   1.339 +	if (IsMatchCaseless(aHeaderName, KHeaderTo) || IsMatchCaseless(aHeaderName, KHeaderToAbbr))
   1.340 +		return EHeaderTo;
   1.341 +
   1.342 +	return EHeaderNormal;
   1.343 +	}
   1.344 +
   1.345 +TBool TEquivSip::IsMatchHeader(const TDesC8& aLhs, const TDesC8& aRhs) const
   1.346 +	{
   1.347 +	if (IsMatchCaseless(aLhs, aRhs))
   1.348 +		{
   1.349 +		// identical headers are always OK
   1.350 +		return ETrue;
   1.351 +		}
   1.352 +
   1.353 +	// We now need to check for abbreviated headers
   1.354 +	TPtrC8 lhsName;
   1.355 +	TPtrC8 lhsValue;
   1.356 +	TPtrC8 rhsName;
   1.357 +	TPtrC8 rhsValue;
   1.358 +
   1.359 +	GetNameValuePair(aLhs, lhsName, lhsValue);
   1.360 +	GetNameValuePair(aRhs, rhsName, rhsValue);
   1.361 +
   1.362 +	if (!IsMatchCaseless(lhsValue, rhsValue))
   1.363 +		{
   1.364 +		// headers with different values can never match
   1.365 +		return EFalse;
   1.366 +		}
   1.367 +
   1.368 +	// We now have only those with different header names but with the same value
   1.369 +	// The last check is to see if the headers are in abbreviated forms
   1.370 +	THeaderType lhsType = HeaderType(lhsName);
   1.371 +	THeaderType rhsType = HeaderType(rhsName);
   1.372 +	if (lhsType != EHeaderNormal && (lhsType == rhsType))
   1.373 +		{
   1.374 +		// They are both special headers of the same type
   1.375 +		// Everything matches
   1.376 +		return ETrue;
   1.377 +		}
   1.378 +
   1.379 +	return EFalse;
   1.380 +	}
   1.381 +
   1.382 +TBool TEquivSip::IsQueryListCompatible(const TDelimitedParserBase8& aLhsParser, const TDelimitedParserBase8& aRhsParser) const
   1.383 +
   1.384 +	{
   1.385 +	TPtrC8 lhsSegment;
   1.386 +	TPtrC8 rhsSegment;
   1.387 +
   1.388 +	TBool found = EFalse;
   1.389 +	// roll back to the start of the lhs segment parser
   1.390 +	aLhsParser.Reset();
   1.391 +
   1.392 +	while( aLhsParser.GetNext(lhsSegment) == KErrNone )
   1.393 +		{
   1.394 +		// roll back to the start of the rhs segment parser
   1.395 +		aRhsParser.Reset();
   1.396 +		
   1.397 +		found = EFalse;
   1.398 +
   1.399 +		while( aRhsParser.GetNext(rhsSegment) == KErrNone )
   1.400 +			{
   1.401 +			if (IsMatchHeader(lhsSegment, rhsSegment))
   1.402 +				{
   1.403 +				// a match has been found for this header so move to the next
   1.404 +				// header in the lhs list
   1.405 +				found = ETrue;
   1.406 +				break;
   1.407 +				}
   1.408 +			}
   1.409 +		if (!found)
   1.410 +			{
   1.411 +			// no match has been found so the headers are not equvalent
   1.412 +			return EFalse;
   1.413 +			}
   1.414 +		}
   1.415 +
   1.416 +	return ETrue;
   1.417 +	}
   1.418 +
   1.419 +TBool TEquivSip::IsMatchQueryL() const
   1.420 +	{
   1.421 +	HBufC8* lhs = DecodedSegmentLC(iLhs, EUriQuery);
   1.422 +	HBufC8* rhs = DecodedSegmentLC(iRhs, EUriQuery);
   1.423 +
   1.424 +	TDelimitedQueryParser8 lhsParser;
   1.425 +	lhsParser.Parse(*lhs);
   1.426 +	TDelimitedQueryParser8 rhsParser;
   1.427 +	rhsParser.Parse(*rhs);
   1.428 +
   1.429 +	TBool result = EFalse;
   1.430 +	
   1.431 +	// first check that the number of headers are the same in both lists.
   1.432 +	TInt lhsLength = ListLength(lhsParser);
   1.433 +	TInt rhsLength = ListLength(rhsParser);
   1.434 +	if (lhsLength == rhsLength)
   1.435 +		{
   1.436 +		// Check each parameter in the lhs parameter list with those in
   1.437 +		// the rhs parameter list. If at any point a parameter is incompatible
   1.438 +		// we'll return false.
   1.439 +		result = IsQueryListCompatible(lhsParser, rhsParser);
   1.440 +		}
   1.441 +	
   1.442 +	CleanupStack::PopAndDestroy(2);
   1.443 +	return result;
   1.444 +	}
   1.445 +
   1.446 +TBool TEquivSip::IsMatchFragmentL() const
   1.447 +	{
   1.448 +	// We don't care about the fragment for SIP URIs
   1.449 +	return ETrue;
   1.450 +	}