os/ossrv/genericservices/httputils/UriUtils/UriUtils.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 // Copyright (c) 2001-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 <uriutils.h>
    17 #include <uriutilscommon.h>
    18 #include "UriUtilsInternal.h"
    19 #include <escapeutils.h>
    20 
    21 _LIT8(KDot, ".");
    22 _LIT8(KDotDot, "..");
    23 _LIT8(KDotSlash, "./");
    24 _LIT8(KDotDotSlash, "../");
    25 _LIT8(KSlash, "/");	
    26 _LIT8(KSlashDot, "/.");
    27 _LIT8(KSlashDotDot, "/..");
    28 _LIT8(KSlashDotSlash, "/./");
    29 _LIT8(KSlashDotDotSlash, "/../");
    30 
    31 _LIT(KHexDigit, "0123456789ABCDEF");
    32 _LIT(KUnreserved, "-.~_");
    33 #ifdef _DEBUG
    34 _LIT(KNormalisationUriPanicCategory, "URI-NORMALIZATION");
    35 #endif
    36 const TInt KEscapeIndicator					= '%';
    37 const TInt KEscapeTripleLength				= 3;
    38 const TInt KEscDelimiterPos					= 0;
    39 const TInt KMostSignificantNibblePos		= 1;
    40 const TInt KLeastSignificantNibblePos		= 2;
    41 const TInt KSubstringLength					= 3;
    42 const TInt KUpdateLength					= 2;
    43 const TInt KAttachLength					= 1;
    44 
    45 const TInt KDotLength						= 1;
    46 const TInt KDotDotLength					= 2;
    47 const TInt KDotDotSlashLength				= 3;
    48 const TInt KSlashDotDotSlashLength			= 4;
    49 
    50 //
    51 //
    52 // Implementation of UriUtils
    53 //
    54 //
    55 
    56 /**
    57 	Converts a 16-bit format uri into its internet form. Any Unicode characters 
    58 	are converted into Utf8 representation and then any excluded characters are 
    59 	escape encoded.  Reserved characters specified in RFC2396 will not be escape 
    60 	encoded however, these include ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",". 
    61 	For example http://localhost will not be encoded to http%3A%2F%2Flocalhost.
    62 	
    63 	@since			6.0
    64 	@deprecated	 Deprecated in 9.1
    65 	@leave			KUriUtilsCannotConvert. When the input data cannot be converted.
    66 	@leave			KUriUtilsErr16BitChar. When the input data has a 16-Bit character to be escape encoded.
    67 	@param			aUri	The 16-bit format uri.
    68 	@return			A pointer to a newly created 8-bit uri.
    69  */
    70 EXPORT_C CUri8* UriUtils::ConvertToInternetFormL(const TUriC16& aUri)
    71 	{
    72 	// Need to convert to utf8
    73 	HBufC8* utf8Buf = EscapeUtils::ConvertFromUnicodeToUtf8L(aUri.UriDes());
    74 	CleanupStack::PushL(utf8Buf);
    75 
    76 	// Ok need to parse for the uri without the fragment
    77 	TUriParser8 parser;
    78 	parser.Parse(*utf8Buf);
    79 	TPtrC8 uriNoFragment;
    80 	parser.UriWithoutFragment(uriNoFragment);
    81 
    82 	// Now escape encode the uri without the fragment
    83 	HBufC8* escapedBuf = EscapeUtils::EscapeEncodeL(uriNoFragment, EscapeUtils::EEscapeNormal);
    84 	CleanupStack::PushL(escapedBuf);
    85 
    86 	// Now escape encode the fragment if there is one...
    87 	HBufC8* escapedFragmentBuf = NULL;
    88 	if( parser.IsPresent(EUriFragment) )
    89 		{
    90 		escapedFragmentBuf = EscapeUtils::EscapeEncodeL(parser.Extract(EUriFragment), EscapeUtils::EEscapeNormal);
    91 		CleanupStack::PushL(escapedFragmentBuf);
    92 		}
    93 
    94 	// Parse and then create the CUri8 object
    95 	parser.Parse(*escapedBuf);
    96 	CUri8* netForm = CUri8::NewL(parser);
    97 
    98 	// Set the fragment if there was one...
    99 	if( escapedFragmentBuf != NULL )
   100 		{
   101 		CleanupStack::PushL(netForm);
   102 		netForm->SetComponentL(*escapedFragmentBuf, EUriFragment);
   103 		CleanupStack::Pop(netForm);
   104 		CleanupStack::PopAndDestroy(escapedFragmentBuf);
   105 		}
   106 
   107 	// Cleanup and return
   108 	CleanupStack::PopAndDestroy(2, utf8Buf);	// utf8Buf, escapedBuf
   109 	return netForm;
   110 	}
   111 
   112 /**
   113 	Converts an 8-bit format uri its into display form. Any escape tripes are decoded and 
   114 	sets of Utf8 format characters are converted into Unicode.
   115 	
   116 	@since			6.0
   117 	@deprecated	 Deprecated in 9.1	
   118 	@leave			KUriUtilsCannotConvert. When the input data cannot be converted.
   119 	@param			aUri	The 8-bit format uri.
   120 	@return			A pointer to a newly created 16-bit uri.
   121  */
   122 EXPORT_C CUri16* UriUtils::ConvertToDisplayFormL(const TUriC8& aUri)
   123 	{
   124 	// Need decode escape triples
   125 	HBufC8* unescapedBuf = EscapeUtils::EscapeDecodeL(aUri.UriDes());
   126 	CleanupStack::PushL(unescapedBuf);
   127 
   128 	// Now need to convert utf8 to unicode
   129 	HBufC16* utf8Buf = EscapeUtils::ConvertToUnicodeFromUtf8L(*unescapedBuf);
   130 	CleanupStack::PushL(utf8Buf);
   131 
   132 	// Parse and then create the CUri16 object
   133 	TUriParser16 parser;
   134 	parser.Parse(*utf8Buf);
   135 	CUri16* displayForm = CUri16::NewL(parser);
   136 
   137 	// Cleanup and return
   138 	CleanupStack::PopAndDestroy(2, unescapedBuf);	// unescapedBuf, utf8Buf
   139 	return displayForm;
   140 	}
   141 	
   142 /** 
   143 	Create a new CUri8 object from a Unicode descriptor.
   144 	
   145 	@param aUri a Unicode string containing the URI to parse.
   146 	@return the new CUri8 object
   147 	@leave EUriUtilsParserErrInvalidUri  if the descriptor is an invalid URI.
   148  */
   149 EXPORT_C CUri8* UriUtils::CreateUriL(const TDesC& aUri) 
   150 	{
   151 	// convert to UTF8
   152 	HBufC8* unsafe8 = EscapeUtils::ConvertFromUnicodeToUtf8L(aUri);
   153      	CleanupStack::PushL(unsafe8);
   154 	// escape encode only those characters that cannot be in a URI. assume all %hh are %encoded already
   155 	HBufC8* uri8desc = EscapeUtils::ReEscapeEncodeL(*unsafe8);
   156 	CleanupStack::PopAndDestroy(unsafe8);
   157      	CleanupStack::PushL(uri8desc);
   158 	TUriParser8 parser;
   159 	// parse the descriptor into a URI, Leave if it cannot be parsed
   160 	User::LeaveIfError( parser.Parse(*uri8desc) );
   161 
   162 	CUri8* uri8 = CUri8::NewL(parser);
   163 	CleanupStack::PopAndDestroy(uri8desc);
   164 	return uri8;
   165 	}
   166 
   167 /** 
   168 	Create a new CAuthority8 object from a Unicode descriptor.
   169 	
   170 	@param aAuthority a Unicode string containing the Authority to parse.
   171 	@return the new CAuthority8 object
   172 	@leave EUriUtilsParserErrInvalidUri  if the descriptor is an invalid Authority.
   173  */
   174 EXPORT_C CAuthority8* UriUtils::CreateAuthorityL(const TDesC& aAuthority) 
   175 	{
   176 	// convert to UTF8
   177 	HBufC8* unsafe8 = EscapeUtils::ConvertFromUnicodeToUtf8L(aAuthority);
   178      	CleanupStack::PushL(unsafe8);
   179 	// escape encode only those characters that cannot be in the authority. assume all %s are %encoded already
   180 	HBufC8* authority8desc = EscapeUtils::ReEscapeEncodeL(*unsafe8);
   181 	CleanupStack::PopAndDestroy(unsafe8);
   182      	CleanupStack::PushL(authority8desc);
   183 	TAuthorityParser8 parser;
   184 	// parse the descriptor into the authority, Leave if it cannot be parsed
   185 	User::LeaveIfError( parser.Parse(*authority8desc) );
   186 
   187 	CAuthority8* authority8 = CAuthority8::NewL(parser);
   188 	CleanupStack::PopAndDestroy(authority8desc);
   189 	return authority8;
   190 	}
   191 
   192 /**
   193 	Checks a descriptor for excluded (invalid) characters. Excluded characters include all 
   194 	control characters (values 0x00 to 0x1F and greater than 0x7F), space (0x20), delimiter 
   195 	characters ('<', '>', '#', '%',	'"') and unwise characters ('{', '}', '|', '\', '^', '[', ']', '`').
   196 	
   197 	@since			6.0
   198 	@param			aData	The descriptor to be checked.
   199 	@return			A boolean value of ETrue if the descriptor contains invalid
   200 	characters, otherwise EFalse.
   201  */
   202 EXPORT_C TBool UriUtils::HasInvalidChars(const TDesC8& aData)
   203 	{
   204 	return CheckForExcludedChars(aData);
   205 	}
   206 	
   207 /**
   208 	Checks a descriptor for excluded (invalid) characters. Excluded characters include all 
   209 	control characters (values 0x00 to 0x1F and	greater than 0x7F), space (0x20), delimiter 
   210 	characters ('<', '>', '#', '%','"') and unwise characters ('{', '}', '|', '\', '^', '[', ']', '`').
   211 	
   212 	@since			6.0
   213 	@param			aData	The descriptor to be checked.
   214 	@return			A boolean value of ETrue if the descriptor contains invalid
   215 	characters, otherwise EFalse.
   216  */
   217 EXPORT_C TBool UriUtils::HasInvalidChars(const TDesC16& aData)
   218 	{
   219 	return CheckForExcludedChars(aData);
   220 	}
   221 
   222 /**
   223 	Checks the supplied host for an IPv4, IPv6 or text format host
   224 	
   225 	@since			7.0
   226 	@param			aHost	The descriptor containing the host to check
   227 	@return			A TUriHostType enum of either EIPv6, EIPv4, EText or EUnknown
   228  */
   229 EXPORT_C UriUtils::TUriHostType UriUtils::HostType(const TDesC8& aHost)
   230 	{
   231 	return CheckHostType(aHost);
   232 	}
   233 
   234 /**
   235 	Checks the supplied host for an IPv4, IPv6 or text format host
   236 	
   237 	@since			7.0
   238 	@param			aHost	The descriptor containing the host to check
   239 	@return			A TUriHostType enum of either EIPv6, EIPv4, EText or EUnknown
   240  */
   241 EXPORT_C UriUtils::TUriHostType UriUtils::HostType(const TDesC16& aHost)
   242 	{
   243 	return CheckHostType(aHost);
   244 	}
   245 
   246 
   247 
   248 //
   249 //
   250 // Implementation of component internal functions
   251 //
   252 //
   253 
   254 /**
   255 	@internalComponent
   256 
   257 	Checks whether the given scheme is a network scheme or not
   258 	
   259 	@param aScheme The descriptor with the scheme.
   260 	@return A boolean value of EFalse if the scheme is SIP.	For all other schemes returns ETrue.
   261  */
   262 TBool IsNetworkScheme(const TDesC8& aScheme)
   263 	{
   264 	TUriSchemeType scheme = SchemeType(aScheme);
   265 	if (scheme == ESchemeTypeSip)
   266 		{
   267 		return EFalse;
   268 		}
   269 	return ETrue;
   270 	}
   271 
   272 /**
   273 	@internalComponent
   274 
   275 	Checks whether the given scheme is a network scheme or not
   276 	
   277 	@param aScheme The descriptor with the scheme.
   278 	@return A boolean value of EFalse if the scheme is SIP.	For all other schemes returns ETrue.
   279  */
   280 TBool IsNetworkScheme(const TDesC16& aScheme)
   281 	{
   282 	TUriSchemeType scheme = SchemeType(aScheme);
   283 	if (scheme == ESchemeTypeSip)
   284 		{
   285 		return EFalse;
   286 		}
   287 	return ETrue;
   288 	}
   289 
   290 /**
   291 	@internalComponent
   292 
   293 	Returns the type of the URIs scheme
   294 	
   295 	@param			aScheme	The descriptor with the scheme.
   296 	@return			The scheme type
   297  */
   298 TUriSchemeType SchemeType(const TDesC8& aScheme)
   299 	{
   300 	// Compares the scheme with both sip and sips
   301 	if (aScheme.CompareF(KSipScheme8()) == 0 || aScheme.CompareF(KSipsScheme8()) == 0)
   302 		{
   303 		// there's a match so this is a sip scheme
   304 		return ESchemeTypeSip;
   305 		}
   306 	//Compares the scheme with tel 
   307 	else if (aScheme.CompareF(KTelScheme8()) == 0) 
   308 		{
   309 		return ESchemeTypeTel;
   310 		} 
   311 
   312 	return ESchemeTypeUnknown;
   313 	}
   314 
   315 /**
   316 	@internalComponent
   317 
   318 	Returns the type of the URIs scheme
   319 	
   320 	@param			aScheme	The descriptor with the scheme.
   321 	@return			The scheme type
   322  */
   323 TUriSchemeType SchemeType(const TDesC16& aScheme)
   324 	{
   325 	// Compares the scheme with both sip and sips
   326 	if (aScheme.CompareF(KSipScheme()) == 0 || aScheme.CompareF(KSipsScheme()) == 0)
   327 		{
   328 		// there's a match so this is a sip scheme
   329 		return ESchemeTypeSip;
   330 		}
   331 
   332 	return ESchemeTypeUnknown;
   333 	}
   334 
   335 /**
   336 	@internalComponent
   337 
   338 	Checks that a text host is in a valid form
   339 	
   340 	@param			aHost	The descriptor containing the host to check
   341 	@return			ETrue if the host is valid otherwise EFalse
   342  */
   343 TBool IsTextHostValid(const TDesC8& aHost)
   344 	{
   345 	return CheckValidTextHost(aHost);
   346 	}
   347 
   348 /**
   349 	@internalComponent
   350 
   351 	Checks that a text host is in a valid form
   352 	
   353 	@param			aHost	The descriptor containing the host to check
   354 	@return			ETrue if the host is valid otherwise EFalse
   355  */
   356 TBool IsTextHostValid(const TDesC16& aHost)
   357 	{
   358 	return CheckValidTextHost(aHost);
   359 	}
   360 
   361 
   362 /**
   363 	@internalComponent
   364 
   365 	Parses a segment of the form name=value and returns the name and value parts
   366 	
   367 	@param			aSegment	the name-value segemnt to parse
   368 	@param			aName		the name part that is returned
   369 	@param			aValue		the value part that is returned
   370  */
   371 void GetNameValuePair(const TDesC8& aSegment, TPtrC8& aName, TPtrC8& aValue)
   372 	{
   373 	TPtrC8 value;
   374 	TInt sepPos = aSegment.Locate(KEqualsSeparator);
   375 	if (sepPos != KErrNotFound)
   376 		{
   377 		aName.Set(aSegment.Left(sepPos));
   378 		value.Set(aSegment.Mid(sepPos+1));
   379 		}
   380 	else
   381 		{
   382 		aName.Set(aSegment);
   383 		}
   384 
   385 	aValue.Set(value);
   386 	}
   387 
   388 
   389 //
   390 //
   391 // Implementation of LOCAL functions
   392 //
   393 //
   394 
   395 /**
   396 	Checks the descriptor for any excluded characters. These are characters that 
   397 	should have been escaped encoded or ocnverted to Utf8 from Unicode.
   398 						
   399 	@since			6.0
   400 	@param			aData	The descriptor to be checked.
   401 	@return		A boolean value of ETrue if the descriptor contains excluded
   402 				characters, EFalse if it does not.
   403  */
   404 template<class TDesCType>
   405 LOCAL_C TBool CheckForExcludedChars(const TDesCType& aData)
   406 	{
   407 	// Run through the descriptor
   408 	TBool valid = ETrue;
   409 	const TInt length = aData.Length();
   410 	TInt i=0;
   411 	while( valid && i<length )
   412 		{
   413 		TInt notUsed;
   414 		// See if the character is an excluded one, or is part of an escape triple...
   415 		if( EscapeUtils::IsExcludedChar(aData[i]) && !EscapeUtils::IsEscapeTriple(aData.Mid(i), notUsed) )
   416 			{
   417 			valid = EFalse;
   418 			}
   419 		else
   420 			{
   421 			++i;
   422 			}
   423 		}
   424 	return !valid;
   425 	}
   426 
   427 /**
   428 	Checks the supplied host for an IPv4, IPv6 or text format host
   429 	
   430 	@since			7.0
   431 	@param			aHost	The descriptor containing the host to check
   432 	@return			A TUriHostType enum of either EIPv6, EIPv4, EText or EUnknown
   433  */
   434 template<class TDesCType>
   435 LOCAL_C UriUtils::TUriHostType CheckHostType(const TDesCType& aHost)
   436 	{
   437 	UriUtils::TUriHostType hostType;
   438 
   439 	TInt dotCount=0;
   440 	TBool colonPresent=EFalse;
   441 	TBool numeric=ETrue;
   442 
   443 	TInt len = aHost.Length();
   444 	for (TInt ii=0; ii < len && !colonPresent; ++ii)
   445 		{
   446 		TChar ch(aHost[ii]);
   447 
   448 		// host contains a character that is not '0'..'9' or '.'
   449 		if ((ch < 48 || ch > 57) && ch != 46)
   450 			numeric=EFalse;
   451 
   452 		// need to check that IPv4 address has the 3 dots
   453 		if (ch == 46)
   454 			++dotCount;
   455 		else
   456 			if (ch == 58)
   457 				colonPresent=ETrue;
   458 		}
   459 
   460 	if (colonPresent) // if theres a colon, it has to be an IPv6 address
   461 		hostType = UriUtils::EIPv6Host;
   462 	else
   463 		if (numeric  && (dotCount==3)) // if its numeric only, and has three seperators...
   464 			hostType = UriUtils::EIPv4Host;
   465 		else
   466 			hostType = UriUtils::ETextHost;
   467 
   468 	return hostType;
   469 	}
   470 
   471 /**
   472 	@internalComponent
   473 
   474 	Checks that a text host is in a valid form
   475 	
   476 	@param			aHost	The descriptor containing the host to check
   477 	@return			ETrue if the host is valid otherwise EFalse
   478  */
   479 template<class TDesCType>
   480 LOCAL_C TBool CheckValidTextHost(const TDesCType& aHost)
   481 	{
   482 	TInt len = aHost.Length();
   483 	if (len == 0)
   484 		return EFalse;
   485 
   486 	// host name can't start with a dot or dash
   487 	TChar firstChar(aHost[0]);
   488 	if (firstChar == '-' || firstChar == '.')
   489 		return EFalse;
   490 
   491 	TChar prev = '\0';
   492 	TInt ii;
   493 	for (ii=0; ii < len; ii++)
   494 		{
   495 		TChar ch(aHost[ii]);
   496 
   497 		// Valid characters are a-z, 0-9, '-' and '.'
   498 		if ((ch < 'A' || ch > 'Z') && (ch < 'a' || ch > 'z') && (ch < '0' || ch > '9') && ch != '-' && ch != '.')
   499 			{
   500 			return EFalse;
   501 			}
   502 
   503 		// dot is the section separator. Check the previous section is not empty
   504 		if (ch == '.' && prev == '.')
   505 			{
   506 			// can't have an empty section
   507 			return EFalse;
   508 			}
   509 			prev = ch;
   510 		}
   511 
   512 	// host name can't end with a dot or dash
   513 	if (prev == '-' || prev == '.')
   514 		return EFalse;
   515 
   516 	return ETrue;
   517 	}
   518 
   519 /**
   520 	Supports Syntax-Based Normalization as specifed in section 6.2.2 of RFC3986.
   521 	returns a new CUri8 object containing a normalised URI from a parsed URI object.
   522 	
   523 	@param aUri	A reference to a parsed uri object.
   524 	@return A pointer to a CUri8 object containing normalised URI.
   525 	@leave KErrNoMemory
   526 	@internalAll
   527  */
   528 EXPORT_C CUri8* UriUtils:: NormaliseUriL(const TUriC8& aUri)	
   529 	{
   530 	CUri8* normalisedUri = CUri8::NewLC(aUri);
   531 	PercentEncodeL(normalisedUri); 
   532 	CaseNormaliseL(normalisedUri);
   533 	RemoveDotSegmentsL(normalisedUri);
   534 	CleanupStack::Pop(normalisedUri);
   535 	return normalisedUri;
   536 	}
   537 	
   538 /**
   539 	Performs Case Normalization for CUri8 object as specified 
   540 	in section 6.2.2.1 of RFC3986.
   541 	
   542 	@param aNormalisedUri It is an in-out parameter. aNormalisedUri is a pointer 
   543 	to CUri8 object with an uri needs to be case normalised and returns with 
   544 	case normalised.
   545 	@leave KErrNoMemory
   546  */
   547 void CaseNormaliseL(CUri8* aNormalisedUri )	
   548 	{
   549 	//Case normalise the scheme
   550 	DoCaseNormaliseL(aNormalisedUri, EUriScheme);	
   551 	//Case normalise the Userinfo
   552 	DoCaseNormaliseL(aNormalisedUri, EUriUserinfo);	
   553 	//Case normalise the Host
   554 	DoCaseNormaliseL(aNormalisedUri, EUriHost);	
   555 	//Case normalise the Port
   556 	DoCaseNormaliseL(aNormalisedUri, EUriPort);	
   557 	//Case normalise the Path
   558 	DoCaseNormaliseL(aNormalisedUri, EUriPath);	
   559 	//Case normalise the Query
   560 	DoCaseNormaliseL(aNormalisedUri, EUriQuery);	
   561 	//Case normalise the Fragment
   562 	DoCaseNormaliseL(aNormalisedUri, EUriFragment);	
   563 	}
   564 
   565 /**
   566 	Performs Case Normalization for specified sub component of URI.
   567 	
   568 	@param aNormalisedUri It is an in-out parameter. aNormalisedUri is a pointer 
   569 	to CUri8 object with an uri needs to be case normalised and returns with 
   570 	case normalised for specified sub component.
   571 	@param aComponent Enumeration of TUriComponent.
   572 	@leave KErrNoMemory
   573 */
   574 void DoCaseNormaliseL(CUri8* aNormalisedUri, TUriComponent aComponent)
   575 	{
   576 	const TUriC8& uri(aNormalisedUri->Uri());
   577 	if(!uri.IsPresent(aComponent) )
   578 		{
   579 		return;
   580 		}
   581 	//extracts subcomponent of uri which needs to be case-normalised
   582 	HBufC8* heapBuf = uri.Extract(aComponent).AllocLC(); 	
   583 	TPtr8 normalisedComponent(heapBuf->Des());
   584 	TBool normalised = EFalse;
   585 	if(aComponent == EUriScheme || aComponent == EUriHost )
   586 		{
   587 		//change this component to lower case
   588 		normalisedComponent.LowerCase();
   589 		normalised = ETrue;
   590 		}
   591 	
   592 	TInt len =  normalisedComponent.Length();
   593 	TBuf8<KSubstringLength> subString;
   594 	//case normalise the component
   595 	for (TInt pos = 0; pos < len; pos++)
   596 		{
   597 		if (normalisedComponent[pos] == KEscapeIndicator )
   598 			{
   599 			__ASSERT_DEBUG( ((len-pos) >= KSubstringLength), User::Panic(KNormalisationUriPanicCategory, KUriUtilsErrBadEscapeTriple) );
   600 			TPtrC8 componentBuf(normalisedComponent.Mid(pos,KSubstringLength));
   601 			if (ValidateAndConvertPercentEncodedTriple(componentBuf,subString))
   602 				{
   603 				normalisedComponent.Replace(pos,KSubstringLength,subString);
   604 				pos += KUpdateLength;
   605 				normalised = ETrue;
   606 				subString.Zero();
   607 				}
   608 			}
   609 		}
   610 
   611 	//updating the uri with normalised string
   612 	if( normalised )
   613 		{
   614 		if(aComponent<EUriMaxComponents && aComponent >=EUriScheme)
   615 		   {
   616 		   aNormalisedUri->SetComponentL(normalisedComponent, aComponent);
   617 		   }
   618 		else
   619 		   {
   620 			User::Leave(KErrArgument);	
   621 		   }
   622 
   623 		}
   624 	CleanupStack::PopAndDestroy(heapBuf);
   625 	}
   626 
   627 /**
   628 	Validates and Converts the valid Percent encoded triplets to Uppercase for specified 
   629 	sub component of URI. For eg: Converts %3a to %3A
   630 	
   631 	@param aData A reference to a string to be validated and converted to upper case.
   632 	@param aCaseNormalizedData A reference to a descriptor that is converted to 
   633 	uppercase that is to be returned.
   634 	@return returns a bool whether it is a valid Percent encoded triplet
   635 */
   636 TBool ValidateAndConvertPercentEncodedTriple(TDesC8& aData , TDes8& aCaseNormalizedData )	
   637 	{
   638 	// See if the descriptor is actually long enough and
   639 	// Check that the three characters form an escape triple - first char is '%'
   640 	if( aData.Length() < KEscapeTripleLength || aData[KEscDelimiterPos] != KEscapeIndicator )
   641 		{
   642 		return EFalse;//do nothing
   643 		}
   644 	
   645 	// Check that next two characters are valid
   646 	TInt mostSignificantDigitValue = KHexDigit().LocateF(aData[KMostSignificantNibblePos] );
   647 	TInt leastSignificantDigitValue = KHexDigit().LocateF(aData[KLeastSignificantNibblePos] );
   648 
   649 	if( mostSignificantDigitValue== KErrNotFound || leastSignificantDigitValue == KErrNotFound )
   650 		{
   651 		// Either of the characters were not a valid hex character
   652 		return EFalse;
   653 		}
   654 	aCaseNormalizedData.Zero();
   655 	aCaseNormalizedData.Append(KEscapeIndicator); 
   656 	
   657 	//Coverts most significant hex character to uppercase
   658 	(mostSignificantDigitValue >= 0 && mostSignificantDigitValue <= 0xF) ? 
   659 		aCaseNormalizedData.Append(KHexDigit().Mid(mostSignificantDigitValue,1)) :
   660 		aCaseNormalizedData.Append(KHexDigit().Mid(mostSignificantDigitValue,1));
   661 	
   662 	//Coverts least significant hex character to uppercase
   663 	(leastSignificantDigitValue >= 0 && leastSignificantDigitValue <= 0xF) ? 
   664 		aCaseNormalizedData.Append(KHexDigit().Mid(leastSignificantDigitValue,1)) :
   665 		aCaseNormalizedData.Append(aData[KLeastSignificantNibblePos]);
   666 	
   667 	return ETrue;
   668 	}
   669 
   670 /**
   671 	Performs Percent-Encoding Normalization for CUri8 object as specifed in 
   672 	section 6.2.2.2 of RFC3986.
   673 	
   674 	@param aNormalisedUri It is an in-out parameter. aNormalisedUri is a pointer to 
   675 	CUri8 object with an uri needs to be Percent-Encoded and returns with Percent-Encode 
   676 	normalised form.
   677 	@leave KErrNoMemory
   678  */
   679 void  PercentEncodeL(CUri8* aNormalisedUri)
   680 	{
   681 	//PercentEncode the scheme
   682 	DoPercentEncodeL(aNormalisedUri, EUriScheme);	
   683 	//PercentEncode the Userinfo
   684 	DoPercentEncodeL(aNormalisedUri, EUriUserinfo);	
   685 	//PercentEncode the Host
   686 	DoPercentEncodeL(aNormalisedUri, EUriHost);	
   687 	//PercentEncode the Port
   688 	DoPercentEncodeL(aNormalisedUri, EUriPort);	
   689 	//PercentEncode the Path
   690 	DoPercentEncodeL(aNormalisedUri, EUriPath);	
   691 	//PercentEncode the Query
   692 	DoPercentEncodeL(aNormalisedUri, EUriQuery);	
   693 	//PercentEncode the Fragment
   694 	DoPercentEncodeL(aNormalisedUri, EUriFragment);	
   695 	}
   696 
   697 /**
   698 	Performs Percent-Encoding for specified sub component of URI.
   699 	
   700 	@param aNormalisedUri It is an in-out parameter. aNormalisedUri is a pointer to 
   701 	CUri8 object with an uri needs to be Percent-Encoded and returns with Percent-Encoded 
   702 	for specified sub component.
   703 	@param aComponent Enumeration of TUriComponent.
   704 	@leave KErrNoMemory
   705 */
   706 void DoPercentEncodeL(CUri8* aNormalisedUri, TUriComponent aComponent)
   707 	{
   708 	const TUriC8& uri(aNormalisedUri->Uri());
   709 	if(!uri.IsPresent(aComponent))
   710 		{
   711 		return;
   712 		}
   713 	
   714 	HBufC8* heapBuf = uri.Extract(aComponent).AllocLC();
   715 	TPtr8 percentNormalisedComponent(heapBuf->Des());
   716 	TBool normalised = EFalse;
   717 	TInt len = percentNormalisedComponent.Length();	
   718 	for (TInt pos = 0; pos < len; pos++)
   719 		{
   720 		TInt hex;
   721 		// check for and decode '%' encoded characters
   722 		if (percentNormalisedComponent[pos] == KEscapeIndicator && EscapeUtils::IsEscapeTriple(percentNormalisedComponent.Mid(pos, KSubstringLength), hex))
   723 			{
   724 			TChar replacedChar(hex);
   725 			if( KUnreserved().LocateF(hex) != KErrNotFound || replacedChar.IsAlphaDigit() )
   726 				{
   727 				TBuf8<KAttachLength> subString;
   728 				subString.Append(replacedChar);
   729 				percentNormalisedComponent.Replace(pos, KSubstringLength, subString);
   730 				normalised = ETrue;
   731 				len = percentNormalisedComponent.Length();
   732 				}
   733 			}
   734 		}
   735 	if( normalised )
   736 		{
   737 		if(aComponent<EUriMaxComponents && aComponent >=EUriScheme)
   738 		   {
   739 		    aNormalisedUri->SetComponentL(percentNormalisedComponent, aComponent);
   740 		   }
   741 		else
   742 		   {
   743 			User::Leave(KErrArgument);	
   744 		   }
   745 
   746 		}
   747 	CleanupStack::PopAndDestroy(heapBuf); 	
   748 	}
   749 
   750 /**
   751 	Performs Path Segment Normalization for CUri8 object as specifed in 
   752 	section 6.2.2.3 of RFC3986.
   753 	
   754 	@param aNormalisedUri It is an in-out parameter. aNormalisedUri is a pointer to 
   755 	CUri8 object with uri needs to be Path Segment normalised and returns with 
   756 	Path Segment normalised form.
   757 	@leave KErrNoMemory
   758  */
   759 void  RemoveDotSegmentsL(CUri8* aNormalisedUri)
   760 	{
   761 	const TUriC8& uri( aNormalisedUri->Uri() );
   762 	if(uri.IsPresent(EUriPath))
   763 		{
   764 		HBufC8* dotSegmentsPath = uri.Extract(EUriPath).AllocLC();
   765 		RemoveExtraneousDotSegmentsL(dotSegmentsPath);
   766 		aNormalisedUri->SetComponentL(*dotSegmentsPath, EUriPath);	
   767 		CleanupStack::PopAndDestroy(dotSegmentsPath);	
   768 		}
   769 	}
   770 
   771 /**
   772 	Performs Remove_dot_segments algorithm as specifed in section 5.2.4 of RFC3986.
   773 	
   774 	@param aUriInputPath It is an in-out parameter. aUriInputPath is a pointer to the 
   775 	path descriptor to be normalised for extraneous dot_segments and returns with 
   776 	normalised dot_segments.
   777 	@leave KErrNoMemory
   778 */
   779 void RemoveExtraneousDotSegmentsL(HBufC8* aUriInputPath)
   780 	{
   781 	TPtr8 uriPathBuf(aUriInputPath->Des());
   782 	TInt length = uriPathBuf.Length();	
   783 	HBufC8* path = HBufC8::NewLC(length);
   784 	TPtr8 transitionalBuf(path->Des());
   785 
   786 	while(length > 0)	
   787 		{
   788 		//step a of section 5.2.4 of RFC 3986
   789 		if(length >= KDotDotSlashLength && 
   790 			KDotDotSlash().Compare(uriPathBuf.Mid(0, KDotDotSlashLength)) == 0 )
   791 			{
   792 			uriPathBuf.Delete(0,KDotDotSlashLength);
   793 			}
   794 		//step a of section 5.2.4 of RFC 3986
   795 		else if(length >= KDotDotLength && 
   796 				KDotSlash().Compare(uriPathBuf.Mid(0, KDotDotLength)) == 0)
   797 			{
   798 			uriPathBuf.Delete(0,KDotDotLength);	
   799 			}
   800 		//step b of section 5.2.4 of RFC 3986
   801 		else if(length >= KDotDotSlashLength && 
   802 				KSlashDotSlash().Compare(uriPathBuf.Mid(0, KDotDotSlashLength)) == 0)
   803 			{
   804 			uriPathBuf.Replace(0, KDotDotSlashLength, KSlash);
   805 			}
   806 		//step c of section 5.2.4 of RFC 3986
   807 		else if(length >= KSlashDotDotSlashLength && 
   808 				KSlashDotDotSlash().Compare(uriPathBuf.Mid(0, KSlashDotDotSlashLength)) == 0)
   809 			{
   810 			updateStrings(uriPathBuf, transitionalBuf, KSlashDotDotSlashLength);
   811 			}
   812 		//step c of section 5.2.4 of RFC 3986 --complete path segment
   813 		else if(length == KDotDotSlashLength && 
   814 				KSlashDotDot().Compare(uriPathBuf.Mid(0, KDotDotSlashLength)) == 0)
   815 			{
   816 			updateStrings(uriPathBuf, transitionalBuf, KDotDotSlashLength);
   817 			}
   818 		//step b of section 5.2.4 of RFC 3986--complete path segment
   819 		else if(length == KDotDotLength && 
   820 				KSlashDot().Compare(uriPathBuf.Mid(0, KDotDotLength)) == 0)
   821 			{
   822 			uriPathBuf.Replace(0, KDotDotLength, KSlash);
   823 			}
   824 		//step d of section 5.2.4 of RFC 3986
   825 		else if(length == KDotDotLength && 
   826 				KDotDot().Compare(uriPathBuf.Mid(0)) == 0)
   827 			{
   828 			uriPathBuf.Delete(0,KDotDotLength);	
   829 			}
   830 		//step d of section 5.2.4 of RFC 3986
   831 		else if(length == KDotLength && 
   832 				KDot().Compare(uriPathBuf.Mid(0)) == 0)
   833 			{
   834 			uriPathBuf.Delete(0,KDotLength);	
   835 			}
   836 		//step e of section 5.2.4 of RFC 3986
   837 		else 
   838 			{
   839 			//get the first path segment including initial / (if any)from uriPathBuf
   840 			// till next slash (but not including next slash)..append it to the output Buf	
   841 			TInt substrLength;
   842 			TInt nextSlashPos = uriPathBuf.Find(KSlash);
   843 			if(nextSlashPos == 0 && length > KDotLength)
   844 				//replace with locate next
   845 				{
   846 				nextSlashPos = uriPathBuf.Mid(1).Find(KSlash);
   847 				if(nextSlashPos != KErrNotFound)
   848 					{
   849 					++nextSlashPos;
   850 					}
   851 				}
   852 			if(length == KDotLength)
   853 				//only '/' is exist
   854 				{
   855 				substrLength = length;	
   856 				}
   857 			else
   858 				{
   859 				substrLength = nextSlashPos == KErrNotFound ? length : nextSlashPos ;	
   860 				}
   861 			transitionalBuf.Append(uriPathBuf.Mid(0,substrLength));
   862 			uriPathBuf.Delete(0,substrLength);	
   863 			}
   864 		length = uriPathBuf.Length();
   865 		}
   866 	uriPathBuf.Copy(transitionalBuf);
   867 	CleanupStack::PopAndDestroy(path);
   868 	}
   869 
   870 /**
   871 	Updates the strings specified in step c of section 5.2.4 of RFC 3986
   872 	
   873 	@param aInputBuf A reference to the inputBuf needs to be modified 
   874 	@param aOutPutBuf A reference to the outPutBuf needs to be modified
   875 	@param aLength length of the string to be replaced.
   876  */
   877 void  updateStrings(TPtr8& aInputBuf, TPtr8& aOutPutBuf, TInt aLength)
   878 	{
   879 	aInputBuf.Replace(0,aLength,KSlash);
   880 
   881 	//In outPutBuf to remove the last segment starting with / (if exist)
   882 	//eg: /abc/def/fgh --> /abc/def
   883 	TInt outputBufLength = aOutPutBuf.Length();
   884 	TInt pos = aOutPutBuf.LocateReverse('/');	
   885 	//remove the last segment including '/'
   886 	pos != KErrNotFound ? aOutPutBuf.Delete( pos, outputBufLength - pos ) : aOutPutBuf.Delete( 0,outputBufLength );
   887 	}
   888