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 + }