os/ossrv/genericservices/httputils/UriParser/TEquiv.cpp
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
     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 	}