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".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
18 #include <uriutilscommon.h>
19 #include "UriUtilsInternal.h"
20 #include <delimitedpathsegment8.h>
21 #include <delimitedquery8.h>
22 #include <escapeutils.h>
24 _LIT8(KParamUserFull, ";user=");
25 _LIT8(KParamTtlFull, ";ttl=");
26 _LIT8(KParamMethodFull, ";method=");
27 _LIT8(KParamMaddrFull, ";maddr=");
28 _LIT8(KParamMaddr, "maddr");
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");
47 TEquiv::TEquiv(const TUriC8& aLhs, const TUriC8& aRhs)
48 : iLhs(aLhs), iRhs(aRhs)
52 TBool TEquiv::EquivalentL() const
54 if (!IsMatchSchemeL())
55 return KUriUtilsErrDifferentScheme;
57 if (!IsMatchUserInfoL())
58 return KUriUtilsErrDifferentUserInfo;
61 return KUriUtilsErrDifferentHost;
64 return KUriUtilsErrDifferentPort;
67 return KUriUtilsErrDifferentPath;
70 return KUriUtilsErrDifferentQuery;
72 if (!IsMatchFragmentL())
73 return KUriUtilsErrDifferentFragment;
78 TBool TEquiv::IsMatchSchemeL() const
80 HBufC8* lhsDes = DecodedSegmentLC(iLhs, EUriScheme);
81 HBufC8* rhsDes = DecodedSegmentLC(iRhs, EUriScheme);
82 TBool result = IsMatchCaseless(*lhsDes, *rhsDes);
83 CleanupStack::PopAndDestroy(2);
87 TBool TEquiv::IsMatchUserInfoL() const
89 HBufC8* lhsDes = DecodedSegmentLC(iLhs, EUriUserinfo);
90 HBufC8* rhsDes = DecodedSegmentLC(iRhs, EUriUserinfo);
91 TBool result = IsMatchCaseSensitive(*lhsDes, *rhsDes);
92 CleanupStack::PopAndDestroy(2);
96 TBool TEquiv::IsMatchHostL() const
98 HBufC8* lhsDes = DecodedSegmentLC(iLhs, EUriHost);
99 HBufC8* rhsDes = DecodedSegmentLC(iRhs, EUriHost);
100 TBool result = IsMatchCaseless(*lhsDes, *rhsDes);
101 CleanupStack::PopAndDestroy(2);
105 TBool TEquiv::IsMatchPortL() const
107 HBufC8* lhsDes = DecodedSegmentLC(iLhs, EUriPort);
108 HBufC8* rhsDes = DecodedSegmentLC(iRhs, EUriPort);
109 TBool result = IsMatchCaseSensitive(*lhsDes, *rhsDes);
110 CleanupStack::PopAndDestroy(2);
114 TBool TEquiv::IsMatchPathL() const
116 HBufC8* lhsDes = DecodedSegmentLC(iLhs, EUriPath);
117 HBufC8* rhsDes = DecodedSegmentLC(iRhs, EUriPath);
118 TBool result = IsMatchCaseSensitive(*lhsDes, *rhsDes);
119 CleanupStack::PopAndDestroy(2);
123 TBool TEquiv::IsMatchQueryL() const
125 HBufC8* lhsDes = DecodedSegmentLC(iLhs, EUriQuery);
126 HBufC8* rhsDes = DecodedSegmentLC(iRhs, EUriQuery);
127 TBool result = IsMatchCaseSensitive(*lhsDes, *rhsDes);
128 CleanupStack::PopAndDestroy(2);
132 TBool TEquiv::IsMatchFragmentL() const
134 HBufC8* lhsDes = DecodedSegmentLC(iLhs, EUriFragment);
135 HBufC8* rhsDes = DecodedSegmentLC(iRhs, EUriFragment);
136 TBool result = IsMatchCaseSensitive(*lhsDes, *rhsDes);
137 CleanupStack::PopAndDestroy(2);
141 HBufC8* TEquiv::DecodedSegmentLC(const TUriC8& aUri, TUriComponent aSegmentType) const
143 HBufC8* decoded = EscapeUtils::EscapeDecodeL(aUri.Extract(aSegmentType));
144 CleanupStack::PushL(decoded);
148 TEquivSip::TEquivSip(const TUriC8& aLhs, const TUriC8& aRhs)
153 void TEquivSip::RemoveLeadingZeros(TPtr8 aHost) const
155 for (TInt i=0; i < aHost.Length(); i++)
157 TBool startOfNumber = (i == 0 || aHost[i-1] < '0' || aHost[i-1] > '9');
158 if (aHost[i] == '0' && startOfNumber)
160 // The character is a zero and is either at the start of the string
161 // or the fist number in a sequence.
167 TBool TEquivSip::IsMatchHostL(const TDesC8& aLhs, const TDesC8& aRhs) const
169 UriUtils::TUriHostType lhsType = UriUtils::HostType(aLhs);
170 UriUtils::TUriHostType rhsType = UriUtils::HostType(aRhs);
171 if (lhsType != rhsType)
173 if (lhsType != UriUtils::ETextHost)
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);
186 return IsMatchCaseless(aLhs, aRhs);
189 TBool TEquivSip::IsMatchHostL() const
191 HBufC8* lhsDes = DecodedSegmentLC(iLhs, EUriHost);
192 HBufC8* rhsDes = DecodedSegmentLC(iRhs, EUriHost);
193 TBool result = IsMatchHostL(*lhsDes, *rhsDes);
194 CleanupStack::PopAndDestroy(2);
198 TBool TEquivSip::IsParamCompatibleL(const TDesC8& aLhsName, const TDesC8& aLhsValue, const TDesC8& aRhsName, const TDesC8& aRhsValue) const
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))
205 // Names don't match so we're OK
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))
213 return IsMatchHostL(aLhsValue, aRhsValue);
217 if (!IsMatchCaseless(aLhsValue, aRhsValue))
219 // Names are the same but the values are different
220 // We have a incompatible parameter
228 TBool TEquivSip::IsParamListCompatibleL(const TDelimitedParserBase8& aLhsParser, const TDelimitedParserBase8& aRhsParser) const
239 // roll back to the start of the lhs segment parser
242 while( aLhsParser.GetNext(lhsSegment) == KErrNone )
244 // roll back to the start of the rhs segment parser
247 GetNameValuePair(lhsSegment, lhsName, lhsValue);
248 while( aRhsParser.GetNext(rhsSegment) == KErrNone )
250 GetNameValuePair(rhsSegment, rhsName, rhsValue);
251 if (!IsParamCompatibleL(lhsName, lhsValue, rhsName, rhsValue))
259 TInt TEquivSip::ListLength(const TDelimitedParserBase8& aParser) const
264 while (!aParser.Eos())
274 TBool TEquivSip::IsMatchPathL() const
276 HBufC8* lhs = DecodedSegmentLC(iLhs, EUriPath);
277 HBufC8* rhs = DecodedSegmentLC(iRhs, EUriPath);
279 TDelimitedPathSegmentParser8 lhsParser;
280 lhsParser.Parse(*lhs);
281 TDelimitedPathSegmentParser8 rhsParser;
282 rhsParser.Parse(*rhs);
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;
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);
294 if (lhsLength > rhsLength)
296 result = IsParamListCompatibleL(lhsParser, rhsParser);
300 result = IsParamListCompatibleL(rhsParser, lhsParser);
303 // check that the special parameters, if present, are present in both
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) )
315 CleanupStack::PopAndDestroy(2);
320 TEquivSip::THeaderType TEquivSip::HeaderType(const TDesC8& aHeaderName) const
322 if (IsMatchCaseless(aHeaderName, KHeaderId) || IsMatchCaseless(aHeaderName, KHeaderIdAbbr))
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))
332 if (IsMatchCaseless(aHeaderName, KHeaderFrom) || IsMatchCaseless(aHeaderName, KHeaderFromAbbr))
334 if (IsMatchCaseless(aHeaderName, KHeaderSubject) || IsMatchCaseless(aHeaderName, KHeaderSubjectAbbr))
335 return EHeaderSubject;
336 if (IsMatchCaseless(aHeaderName, KHeaderTo) || IsMatchCaseless(aHeaderName, KHeaderToAbbr))
339 return EHeaderNormal;
342 TBool TEquivSip::IsMatchHeader(const TDesC8& aLhs, const TDesC8& aRhs) const
344 if (IsMatchCaseless(aLhs, aRhs))
346 // identical headers are always OK
350 // We now need to check for abbreviated headers
356 GetNameValuePair(aLhs, lhsName, lhsValue);
357 GetNameValuePair(aRhs, rhsName, rhsValue);
359 if (!IsMatchCaseless(lhsValue, rhsValue))
361 // headers with different values can never match
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))
371 // They are both special headers of the same type
372 // Everything matches
379 TBool TEquivSip::IsQueryListCompatible(const TDelimitedParserBase8& aLhsParser, const TDelimitedParserBase8& aRhsParser) const
385 TBool found = EFalse;
386 // roll back to the start of the lhs segment parser
389 while( aLhsParser.GetNext(lhsSegment) == KErrNone )
391 // roll back to the start of the rhs segment parser
396 while( aRhsParser.GetNext(rhsSegment) == KErrNone )
398 if (IsMatchHeader(lhsSegment, rhsSegment))
400 // a match has been found for this header so move to the next
401 // header in the lhs list
408 // no match has been found so the headers are not equvalent
416 TBool TEquivSip::IsMatchQueryL() const
418 HBufC8* lhs = DecodedSegmentLC(iLhs, EUriQuery);
419 HBufC8* rhs = DecodedSegmentLC(iRhs, EUriQuery);
421 TDelimitedQueryParser8 lhsParser;
422 lhsParser.Parse(*lhs);
423 TDelimitedQueryParser8 rhsParser;
424 rhsParser.Parse(*rhs);
426 TBool result = EFalse;
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)
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);
439 CleanupStack::PopAndDestroy(2);
443 TBool TEquivSip::IsMatchFragmentL() const
445 // We don't care about the fragment for SIP URIs