genericservices/httputils/UriParser/TEquiv.cpp
changeset 0 e4d67989cc36
equal deleted inserted replaced
-1:000000000000 0:e4d67989cc36
       
     1 // Copyright (c) 2004-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 "TEquiv.h"
       
    17 #include <uriutils.h>
       
    18 #include <uriutilscommon.h>
       
    19 #include "UriUtilsInternal.h"
       
    20 #include <delimitedpathsegment8.h>
       
    21 #include <delimitedquery8.h>
       
    22 #include <escapeutils.h>
       
    23 
       
    24 _LIT8(KParamUserFull,	";user=");
       
    25 _LIT8(KParamTtlFull,	";ttl=");
       
    26 _LIT8(KParamMethodFull,	";method=");
       
    27 _LIT8(KParamMaddrFull,	";maddr=");
       
    28 _LIT8(KParamMaddr,		"maddr");
       
    29 
       
    30 _LIT8(KHeaderId, "call-id");
       
    31 _LIT8(KHeaderIdAbbr, "i");
       
    32 _LIT8(KHeaderContact, "contact");
       
    33 _LIT8(KHeaderContactAbbr, "m");
       
    34 _LIT8(KHeaderEncoding, "content-encoding");
       
    35 _LIT8(KHeaderEncodingAbbr, "e");
       
    36 _LIT8(KHeaderLength, "content-length");
       
    37 _LIT8(KHeaderLengthAbbr, "l");
       
    38 _LIT8(KHeaderType, "content-type");
       
    39 _LIT8(KHeaderTypeAbbr, "c");
       
    40 _LIT8(KHeaderFrom, "from");
       
    41 _LIT8(KHeaderFromAbbr, "f");
       
    42 _LIT8(KHeaderSubject, "subject");
       
    43 _LIT8(KHeaderSubjectAbbr, "s");
       
    44 _LIT8(KHeaderTo, "to");
       
    45 _LIT8(KHeaderToAbbr, "t");
       
    46 
       
    47 TEquiv::TEquiv(const TUriC8& aLhs, const TUriC8& aRhs)
       
    48 : iLhs(aLhs), iRhs(aRhs)
       
    49 	{
       
    50 	}
       
    51 
       
    52 TBool TEquiv::EquivalentL() const
       
    53 	{
       
    54 	if (!IsMatchSchemeL())
       
    55 		return KUriUtilsErrDifferentScheme;
       
    56 	
       
    57 	if (!IsMatchUserInfoL())
       
    58 		return KUriUtilsErrDifferentUserInfo;
       
    59 	
       
    60 	if (!IsMatchHostL())
       
    61 		return KUriUtilsErrDifferentHost;
       
    62 	
       
    63 	if (!IsMatchPortL())
       
    64 		return KUriUtilsErrDifferentPort;
       
    65 	
       
    66 	if (!IsMatchPathL())
       
    67 		return KUriUtilsErrDifferentPath;
       
    68 	
       
    69 	if (!IsMatchQueryL())
       
    70 		return KUriUtilsErrDifferentQuery;
       
    71 	
       
    72 	if (!IsMatchFragmentL())
       
    73 		return KUriUtilsErrDifferentFragment;
       
    74 	
       
    75 	return KErrNone;
       
    76 	}
       
    77 
       
    78 TBool TEquiv::IsMatchSchemeL() const
       
    79 	{
       
    80 	HBufC8* lhsDes = DecodedSegmentLC(iLhs, EUriScheme);
       
    81 	HBufC8* rhsDes = DecodedSegmentLC(iRhs, EUriScheme);
       
    82 	TBool result = IsMatchCaseless(*lhsDes, *rhsDes);
       
    83 	CleanupStack::PopAndDestroy(2);
       
    84 	return result;
       
    85 	}
       
    86 
       
    87 TBool TEquiv::IsMatchUserInfoL() const
       
    88 	{
       
    89 	HBufC8* lhsDes = DecodedSegmentLC(iLhs, EUriUserinfo);
       
    90 	HBufC8* rhsDes = DecodedSegmentLC(iRhs, EUriUserinfo);
       
    91 	TBool result = IsMatchCaseSensitive(*lhsDes, *rhsDes);
       
    92 	CleanupStack::PopAndDestroy(2);
       
    93 	return result;
       
    94 	}
       
    95 
       
    96 TBool TEquiv::IsMatchHostL() const
       
    97 	{
       
    98 	HBufC8* lhsDes = DecodedSegmentLC(iLhs, EUriHost);
       
    99 	HBufC8* rhsDes = DecodedSegmentLC(iRhs, EUriHost);
       
   100 	TBool result = IsMatchCaseless(*lhsDes, *rhsDes);
       
   101 	CleanupStack::PopAndDestroy(2);
       
   102 	return result;
       
   103 	}
       
   104 
       
   105 TBool TEquiv::IsMatchPortL() const
       
   106 	{
       
   107 	HBufC8* lhsDes = DecodedSegmentLC(iLhs, EUriPort);
       
   108 	HBufC8* rhsDes = DecodedSegmentLC(iRhs, EUriPort);
       
   109 	TBool result = IsMatchCaseSensitive(*lhsDes, *rhsDes);
       
   110 	CleanupStack::PopAndDestroy(2);
       
   111 	return result;
       
   112 	}
       
   113 
       
   114 TBool TEquiv::IsMatchPathL() const
       
   115 	{
       
   116 	HBufC8* lhsDes = DecodedSegmentLC(iLhs, EUriPath);
       
   117 	HBufC8* rhsDes = DecodedSegmentLC(iRhs, EUriPath);
       
   118 	TBool result = IsMatchCaseSensitive(*lhsDes, *rhsDes);
       
   119 	CleanupStack::PopAndDestroy(2);
       
   120 	return result;
       
   121 	}
       
   122 
       
   123 TBool TEquiv::IsMatchQueryL() const
       
   124 	{
       
   125 	HBufC8* lhsDes = DecodedSegmentLC(iLhs, EUriQuery);
       
   126 	HBufC8* rhsDes = DecodedSegmentLC(iRhs, EUriQuery);
       
   127 	TBool result = IsMatchCaseSensitive(*lhsDes, *rhsDes);
       
   128 	CleanupStack::PopAndDestroy(2);
       
   129 	return result;
       
   130 	}
       
   131 
       
   132 TBool TEquiv::IsMatchFragmentL() const
       
   133 	{
       
   134 	HBufC8* lhsDes = DecodedSegmentLC(iLhs, EUriFragment);
       
   135 	HBufC8* rhsDes = DecodedSegmentLC(iRhs, EUriFragment);
       
   136 	TBool result = IsMatchCaseSensitive(*lhsDes, *rhsDes);
       
   137 	CleanupStack::PopAndDestroy(2);
       
   138 	return result;
       
   139 	}
       
   140 
       
   141 HBufC8* TEquiv::DecodedSegmentLC(const TUriC8& aUri, TUriComponent aSegmentType) const
       
   142 	{
       
   143 	HBufC8* decoded = EscapeUtils::EscapeDecodeL(aUri.Extract(aSegmentType));
       
   144 	CleanupStack::PushL(decoded);
       
   145 	return decoded;
       
   146 	}
       
   147 
       
   148 TEquivSip::TEquivSip(const TUriC8& aLhs, const TUriC8& aRhs)
       
   149 : TEquiv(aLhs, aRhs)
       
   150 	{
       
   151 	}
       
   152 
       
   153 void TEquivSip::RemoveLeadingZeros(TPtr8 aHost) const
       
   154 	{
       
   155 	for (TInt i=0; i < aHost.Length(); i++)
       
   156 		{
       
   157 		TBool startOfNumber = (i == 0 || aHost[i-1] < '0' || aHost[i-1] > '9');
       
   158 		if (aHost[i] == '0' && startOfNumber)
       
   159 			{
       
   160 			// The character is a zero and is either at the start of the string
       
   161 			// or the fist number in a sequence.
       
   162 			aHost.Delete(i--,1);
       
   163 			}
       
   164 		}
       
   165 	}
       
   166 
       
   167 TBool TEquivSip::IsMatchHostL(const TDesC8& aLhs, const TDesC8& aRhs) const
       
   168 	{
       
   169 	UriUtils::TUriHostType lhsType = UriUtils::HostType(aLhs);
       
   170 	UriUtils::TUriHostType rhsType = UriUtils::HostType(aRhs);
       
   171 	if (lhsType != rhsType)
       
   172 		return EFalse;
       
   173 	if (lhsType != UriUtils::ETextHost)
       
   174 		{
       
   175 		// Host is IPv4 or IPv6
       
   176 		// Create a copy of the hosts and remove any leading '0's
       
   177 		HBufC8* lhsCopy = aLhs.AllocLC();
       
   178 		HBufC8* rhsCopy = aRhs.AllocLC();
       
   179 		RemoveLeadingZeros(lhsCopy->Des());
       
   180 		RemoveLeadingZeros(rhsCopy->Des());
       
   181 		TBool result = IsMatchCaseSensitive(*lhsCopy, *rhsCopy);
       
   182 		CleanupStack::PopAndDestroy(2);
       
   183 		return result;
       
   184 		}
       
   185 
       
   186 	return IsMatchCaseless(aLhs, aRhs);
       
   187 	}
       
   188 
       
   189 TBool TEquivSip::IsMatchHostL() const
       
   190 	{
       
   191 	HBufC8* lhsDes = DecodedSegmentLC(iLhs, EUriHost);
       
   192 	HBufC8* rhsDes = DecodedSegmentLC(iRhs, EUriHost);
       
   193 	TBool result = IsMatchHostL(*lhsDes, *rhsDes);
       
   194 	CleanupStack::PopAndDestroy(2);
       
   195 	return result;
       
   196 	}
       
   197 
       
   198 TBool TEquivSip::IsParamCompatibleL(const TDesC8& aLhsName, const TDesC8& aLhsValue, const TDesC8& aRhsName, const TDesC8& aRhsValue) const
       
   199 	{
       
   200 	// Were're just checking that if the segments have the same name part
       
   201 	// that their values are the same. This method only returns false if the lhs and rhs
       
   202 	// have the same name but their values are different.
       
   203 	if (!IsMatchCaseless(aLhsName, aRhsName))
       
   204 		{
       
   205 		// Names don't match so we're OK
       
   206 		return ETrue;
       
   207 		}
       
   208 
       
   209 	// The maddr parameter needs to be handled differently from the others
       
   210 	// The address is checked for equivalence not just a straight string compare.
       
   211 	if (IsMatchCaseless(aLhsName, KParamMaddr))
       
   212 		{
       
   213 			return IsMatchHostL(aLhsValue, aRhsValue);
       
   214 		}
       
   215 	else
       
   216 		{
       
   217 		if (!IsMatchCaseless(aLhsValue, aRhsValue))
       
   218 			{
       
   219 			// Names are the same but the values are different
       
   220 			// We have a incompatible parameter
       
   221 			return EFalse;
       
   222 			}
       
   223 		}
       
   224 
       
   225 	return ETrue;
       
   226 	}
       
   227 
       
   228 TBool TEquivSip::IsParamListCompatibleL(const TDelimitedParserBase8& aLhsParser, const TDelimitedParserBase8& aRhsParser) const
       
   229 
       
   230 	{
       
   231 	TPtrC8 lhsName;
       
   232 	TPtrC8 lhsValue;
       
   233 	TPtrC8 rhsName;
       
   234 	TPtrC8 rhsValue;
       
   235 
       
   236 	TPtrC8 lhsSegment;
       
   237 	TPtrC8 rhsSegment;
       
   238 
       
   239 	// roll back to the start of the lhs segment parser
       
   240 	aLhsParser.Reset();
       
   241 	
       
   242 	while( aLhsParser.GetNext(lhsSegment) == KErrNone )
       
   243 		{
       
   244 		// roll back to the start of the rhs segment parser
       
   245 		aRhsParser.Reset();
       
   246 
       
   247 		GetNameValuePair(lhsSegment, lhsName, lhsValue);
       
   248 		while( aRhsParser.GetNext(rhsSegment) == KErrNone )
       
   249 			{
       
   250 			GetNameValuePair(rhsSegment, rhsName, rhsValue);
       
   251 			if (!IsParamCompatibleL(lhsName, lhsValue, rhsName, rhsValue))
       
   252 				return EFalse;
       
   253 			}
       
   254 		}
       
   255 
       
   256 	return ETrue;
       
   257 	}
       
   258 
       
   259 TInt TEquivSip::ListLength(const TDelimitedParserBase8& aParser) const
       
   260 	{
       
   261 	aParser.Reset();
       
   262 	
       
   263 	TInt result = 0;
       
   264 	while (!aParser.Eos())
       
   265 		{
       
   266 		aParser.Inc();
       
   267 		++result;
       
   268 		}
       
   269 		
       
   270 	aParser.Reset();
       
   271 	return result;
       
   272 	}
       
   273 
       
   274 TBool TEquivSip::IsMatchPathL() const
       
   275 	{
       
   276 	HBufC8* lhs = DecodedSegmentLC(iLhs, EUriPath);
       
   277 	HBufC8* rhs = DecodedSegmentLC(iRhs, EUriPath);
       
   278 
       
   279 	TDelimitedPathSegmentParser8 lhsParser;
       
   280 	lhsParser.Parse(*lhs);
       
   281 	TDelimitedPathSegmentParser8 rhsParser;
       
   282 	rhsParser.Parse(*rhs);
       
   283 	
       
   284 	// Check each parameter in the lhs parameter list with those in
       
   285 	// the rhs parameter list. If at any point a parameter is incompatible
       
   286 	// we'll return false.
       
   287 	TBool result = ETrue;
       
   288 	
       
   289 	// Alway check the parameter list with the most parameters against the other
       
   290 	// so that we don't miss any
       
   291 	TInt lhsLength = ListLength(lhsParser);
       
   292 	TInt rhsLength = ListLength(rhsParser);
       
   293 	
       
   294 	if (lhsLength > rhsLength)
       
   295 		{
       
   296 		result = IsParamListCompatibleL(lhsParser, rhsParser);
       
   297 		}
       
   298 	else
       
   299 		{
       
   300 		result = IsParamListCompatibleL(rhsParser, lhsParser);
       
   301 		}
       
   302 
       
   303 	// check that the special parameters, if present, are present in both
       
   304 	if (result)
       
   305 		{
       
   306 		if ((lhs->Find(KParamUserFull) == KErrNotFound) != (rhs->Find(KParamUserFull) == KErrNotFound) ||
       
   307 		    (lhs->Find(KParamTtlFull) == KErrNotFound) != (rhs->Find(KParamTtlFull) == KErrNotFound) ||
       
   308 		    (lhs->Find(KParamMethodFull) == KErrNotFound) != (rhs->Find(KParamMethodFull) == KErrNotFound) ||
       
   309 		    (lhs->Find(KParamMaddrFull) == KErrNotFound) != (rhs->Find(KParamMaddrFull) == KErrNotFound) )
       
   310 			{
       
   311 			result = EFalse;
       
   312 			}
       
   313 		}
       
   314 	
       
   315 	CleanupStack::PopAndDestroy(2);
       
   316 	return result;
       
   317 	}
       
   318 
       
   319 
       
   320 TEquivSip::THeaderType TEquivSip::HeaderType(const TDesC8& aHeaderName) const
       
   321 	{
       
   322 	if (IsMatchCaseless(aHeaderName, KHeaderId) || IsMatchCaseless(aHeaderName, KHeaderIdAbbr))
       
   323 		return EHeaderId;
       
   324 	if (IsMatchCaseless(aHeaderName, KHeaderContact) || IsMatchCaseless(aHeaderName, KHeaderContactAbbr))
       
   325 		return EHeaderContact;
       
   326 	if (IsMatchCaseless(aHeaderName, KHeaderEncoding) || IsMatchCaseless(aHeaderName, KHeaderEncodingAbbr))
       
   327 		return EHeaderEncoding;
       
   328 	if (IsMatchCaseless(aHeaderName, KHeaderLength) || IsMatchCaseless(aHeaderName, KHeaderLengthAbbr))
       
   329 		return EHeaderLength;
       
   330 	if (IsMatchCaseless(aHeaderName, KHeaderType) || IsMatchCaseless(aHeaderName, KHeaderTypeAbbr))
       
   331 		return EHeaderType;
       
   332 	if (IsMatchCaseless(aHeaderName, KHeaderFrom) || IsMatchCaseless(aHeaderName, KHeaderFromAbbr))
       
   333 		return EHeaderFrom;
       
   334 	if (IsMatchCaseless(aHeaderName, KHeaderSubject) || IsMatchCaseless(aHeaderName, KHeaderSubjectAbbr))
       
   335 		return EHeaderSubject;
       
   336 	if (IsMatchCaseless(aHeaderName, KHeaderTo) || IsMatchCaseless(aHeaderName, KHeaderToAbbr))
       
   337 		return EHeaderTo;
       
   338 
       
   339 	return EHeaderNormal;
       
   340 	}
       
   341 
       
   342 TBool TEquivSip::IsMatchHeader(const TDesC8& aLhs, const TDesC8& aRhs) const
       
   343 	{
       
   344 	if (IsMatchCaseless(aLhs, aRhs))
       
   345 		{
       
   346 		// identical headers are always OK
       
   347 		return ETrue;
       
   348 		}
       
   349 
       
   350 	// We now need to check for abbreviated headers
       
   351 	TPtrC8 lhsName;
       
   352 	TPtrC8 lhsValue;
       
   353 	TPtrC8 rhsName;
       
   354 	TPtrC8 rhsValue;
       
   355 
       
   356 	GetNameValuePair(aLhs, lhsName, lhsValue);
       
   357 	GetNameValuePair(aRhs, rhsName, rhsValue);
       
   358 
       
   359 	if (!IsMatchCaseless(lhsValue, rhsValue))
       
   360 		{
       
   361 		// headers with different values can never match
       
   362 		return EFalse;
       
   363 		}
       
   364 
       
   365 	// We now have only those with different header names but with the same value
       
   366 	// The last check is to see if the headers are in abbreviated forms
       
   367 	THeaderType lhsType = HeaderType(lhsName);
       
   368 	THeaderType rhsType = HeaderType(rhsName);
       
   369 	if (lhsType != EHeaderNormal && (lhsType == rhsType))
       
   370 		{
       
   371 		// They are both special headers of the same type
       
   372 		// Everything matches
       
   373 		return ETrue;
       
   374 		}
       
   375 
       
   376 	return EFalse;
       
   377 	}
       
   378 
       
   379 TBool TEquivSip::IsQueryListCompatible(const TDelimitedParserBase8& aLhsParser, const TDelimitedParserBase8& aRhsParser) const
       
   380 
       
   381 	{
       
   382 	TPtrC8 lhsSegment;
       
   383 	TPtrC8 rhsSegment;
       
   384 
       
   385 	TBool found = EFalse;
       
   386 	// roll back to the start of the lhs segment parser
       
   387 	aLhsParser.Reset();
       
   388 
       
   389 	while( aLhsParser.GetNext(lhsSegment) == KErrNone )
       
   390 		{
       
   391 		// roll back to the start of the rhs segment parser
       
   392 		aRhsParser.Reset();
       
   393 		
       
   394 		found = EFalse;
       
   395 
       
   396 		while( aRhsParser.GetNext(rhsSegment) == KErrNone )
       
   397 			{
       
   398 			if (IsMatchHeader(lhsSegment, rhsSegment))
       
   399 				{
       
   400 				// a match has been found for this header so move to the next
       
   401 				// header in the lhs list
       
   402 				found = ETrue;
       
   403 				break;
       
   404 				}
       
   405 			}
       
   406 		if (!found)
       
   407 			{
       
   408 			// no match has been found so the headers are not equvalent
       
   409 			return EFalse;
       
   410 			}
       
   411 		}
       
   412 
       
   413 	return ETrue;
       
   414 	}
       
   415 
       
   416 TBool TEquivSip::IsMatchQueryL() const
       
   417 	{
       
   418 	HBufC8* lhs = DecodedSegmentLC(iLhs, EUriQuery);
       
   419 	HBufC8* rhs = DecodedSegmentLC(iRhs, EUriQuery);
       
   420 
       
   421 	TDelimitedQueryParser8 lhsParser;
       
   422 	lhsParser.Parse(*lhs);
       
   423 	TDelimitedQueryParser8 rhsParser;
       
   424 	rhsParser.Parse(*rhs);
       
   425 
       
   426 	TBool result = EFalse;
       
   427 	
       
   428 	// first check that the number of headers are the same in both lists.
       
   429 	TInt lhsLength = ListLength(lhsParser);
       
   430 	TInt rhsLength = ListLength(rhsParser);
       
   431 	if (lhsLength == rhsLength)
       
   432 		{
       
   433 		// Check each parameter in the lhs parameter list with those in
       
   434 		// the rhs parameter list. If at any point a parameter is incompatible
       
   435 		// we'll return false.
       
   436 		result = IsQueryListCompatible(lhsParser, rhsParser);
       
   437 		}
       
   438 	
       
   439 	CleanupStack::PopAndDestroy(2);
       
   440 	return result;
       
   441 	}
       
   442 
       
   443 TBool TEquivSip::IsMatchFragmentL() const
       
   444 	{
       
   445 	// We don't care about the fragment for SIP URIs
       
   446 	return ETrue;
       
   447 	}