genericservices/httputils/UriUtils/UriUtils.cpp
changeset 0 e4d67989cc36
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/genericservices/httputils/UriUtils/UriUtils.cpp	Tue Feb 02 02:01:42 2010 +0200
@@ -0,0 +1,888 @@
+// Copyright (c) 2001-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+//
+
+#include <uriutils.h>
+#include <uriutilscommon.h>
+#include "UriUtilsInternal.h"
+#include <escapeutils.h>
+
+_LIT8(KDot, ".");
+_LIT8(KDotDot, "..");
+_LIT8(KDotSlash, "./");
+_LIT8(KDotDotSlash, "../");
+_LIT8(KSlash, "/");	
+_LIT8(KSlashDot, "/.");
+_LIT8(KSlashDotDot, "/..");
+_LIT8(KSlashDotSlash, "/./");
+_LIT8(KSlashDotDotSlash, "/../");
+
+_LIT(KHexDigit, "0123456789ABCDEF");
+_LIT(KUnreserved, "-.~_");
+#ifdef _DEBUG
+_LIT(KNormalisationUriPanicCategory, "URI-NORMALIZATION");
+#endif
+const TInt KEscapeIndicator					= '%';
+const TInt KEscapeTripleLength				= 3;
+const TInt KEscDelimiterPos					= 0;
+const TInt KMostSignificantNibblePos		= 1;
+const TInt KLeastSignificantNibblePos		= 2;
+const TInt KSubstringLength					= 3;
+const TInt KUpdateLength					= 2;
+const TInt KAttachLength					= 1;
+
+const TInt KDotLength						= 1;
+const TInt KDotDotLength					= 2;
+const TInt KDotDotSlashLength				= 3;
+const TInt KSlashDotDotSlashLength			= 4;
+
+//
+//
+// Implementation of UriUtils
+//
+//
+
+/**
+	Converts a 16-bit format uri into its internet form. Any Unicode characters 
+	are converted into Utf8 representation and then any excluded characters are 
+	escape encoded.  Reserved characters specified in RFC2396 will not be escape 
+	encoded however, these include ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",". 
+	For example http://localhost will not be encoded to http%3A%2F%2Flocalhost.
+	
+	@since			6.0
+	@deprecated	 Deprecated in 9.1
+	@leave			KUriUtilsCannotConvert. When the input data cannot be converted.
+	@leave			KUriUtilsErr16BitChar. When the input data has a 16-Bit character to be escape encoded.
+	@param			aUri	The 16-bit format uri.
+	@return			A pointer to a newly created 8-bit uri.
+ */
+EXPORT_C CUri8* UriUtils::ConvertToInternetFormL(const TUriC16& aUri)
+	{
+	// Need to convert to utf8
+	HBufC8* utf8Buf = EscapeUtils::ConvertFromUnicodeToUtf8L(aUri.UriDes());
+	CleanupStack::PushL(utf8Buf);
+
+	// Ok need to parse for the uri without the fragment
+	TUriParser8 parser;
+	parser.Parse(*utf8Buf);
+	TPtrC8 uriNoFragment;
+	parser.UriWithoutFragment(uriNoFragment);
+
+	// Now escape encode the uri without the fragment
+	HBufC8* escapedBuf = EscapeUtils::EscapeEncodeL(uriNoFragment, EscapeUtils::EEscapeNormal);
+	CleanupStack::PushL(escapedBuf);
+
+	// Now escape encode the fragment if there is one...
+	HBufC8* escapedFragmentBuf = NULL;
+	if( parser.IsPresent(EUriFragment) )
+		{
+		escapedFragmentBuf = EscapeUtils::EscapeEncodeL(parser.Extract(EUriFragment), EscapeUtils::EEscapeNormal);
+		CleanupStack::PushL(escapedFragmentBuf);
+		}
+
+	// Parse and then create the CUri8 object
+	parser.Parse(*escapedBuf);
+	CUri8* netForm = CUri8::NewL(parser);
+
+	// Set the fragment if there was one...
+	if( escapedFragmentBuf != NULL )
+		{
+		CleanupStack::PushL(netForm);
+		netForm->SetComponentL(*escapedFragmentBuf, EUriFragment);
+		CleanupStack::Pop(netForm);
+		CleanupStack::PopAndDestroy(escapedFragmentBuf);
+		}
+
+	// Cleanup and return
+	CleanupStack::PopAndDestroy(2, utf8Buf);	// utf8Buf, escapedBuf
+	return netForm;
+	}
+
+/**
+	Converts an 8-bit format uri its into display form. Any escape tripes are decoded and 
+	sets of Utf8 format characters are converted into Unicode.
+	
+	@since			6.0
+	@deprecated	 Deprecated in 9.1	
+	@leave			KUriUtilsCannotConvert. When the input data cannot be converted.
+	@param			aUri	The 8-bit format uri.
+	@return			A pointer to a newly created 16-bit uri.
+ */
+EXPORT_C CUri16* UriUtils::ConvertToDisplayFormL(const TUriC8& aUri)
+	{
+	// Need decode escape triples
+	HBufC8* unescapedBuf = EscapeUtils::EscapeDecodeL(aUri.UriDes());
+	CleanupStack::PushL(unescapedBuf);
+
+	// Now need to convert utf8 to unicode
+	HBufC16* utf8Buf = EscapeUtils::ConvertToUnicodeFromUtf8L(*unescapedBuf);
+	CleanupStack::PushL(utf8Buf);
+
+	// Parse and then create the CUri16 object
+	TUriParser16 parser;
+	parser.Parse(*utf8Buf);
+	CUri16* displayForm = CUri16::NewL(parser);
+
+	// Cleanup and return
+	CleanupStack::PopAndDestroy(2, unescapedBuf);	// unescapedBuf, utf8Buf
+	return displayForm;
+	}
+	
+/** 
+	Create a new CUri8 object from a Unicode descriptor.
+	
+	@param aUri a Unicode string containing the URI to parse.
+	@return the new CUri8 object
+	@leave EUriUtilsParserErrInvalidUri  if the descriptor is an invalid URI.
+ */
+EXPORT_C CUri8* UriUtils::CreateUriL(const TDesC& aUri) 
+	{
+	// convert to UTF8
+	HBufC8* unsafe8 = EscapeUtils::ConvertFromUnicodeToUtf8L(aUri);
+     	CleanupStack::PushL(unsafe8);
+	// escape encode only those characters that cannot be in a URI. assume all %hh are %encoded already
+	HBufC8* uri8desc = EscapeUtils::ReEscapeEncodeL(*unsafe8);
+	CleanupStack::PopAndDestroy(unsafe8);
+     	CleanupStack::PushL(uri8desc);
+	TUriParser8 parser;
+	// parse the descriptor into a URI, Leave if it cannot be parsed
+	User::LeaveIfError( parser.Parse(*uri8desc) );
+
+	CUri8* uri8 = CUri8::NewL(parser);
+	CleanupStack::PopAndDestroy(uri8desc);
+	return uri8;
+	}
+
+/** 
+	Create a new CAuthority8 object from a Unicode descriptor.
+	
+	@param aAuthority a Unicode string containing the Authority to parse.
+	@return the new CAuthority8 object
+	@leave EUriUtilsParserErrInvalidUri  if the descriptor is an invalid Authority.
+ */
+EXPORT_C CAuthority8* UriUtils::CreateAuthorityL(const TDesC& aAuthority) 
+	{
+	// convert to UTF8
+	HBufC8* unsafe8 = EscapeUtils::ConvertFromUnicodeToUtf8L(aAuthority);
+     	CleanupStack::PushL(unsafe8);
+	// escape encode only those characters that cannot be in the authority. assume all %s are %encoded already
+	HBufC8* authority8desc = EscapeUtils::ReEscapeEncodeL(*unsafe8);
+	CleanupStack::PopAndDestroy(unsafe8);
+     	CleanupStack::PushL(authority8desc);
+	TAuthorityParser8 parser;
+	// parse the descriptor into the authority, Leave if it cannot be parsed
+	User::LeaveIfError( parser.Parse(*authority8desc) );
+
+	CAuthority8* authority8 = CAuthority8::NewL(parser);
+	CleanupStack::PopAndDestroy(authority8desc);
+	return authority8;
+	}
+
+/**
+	Checks a descriptor for excluded (invalid) characters. Excluded characters include all 
+	control characters (values 0x00 to 0x1F and greater than 0x7F), space (0x20), delimiter 
+	characters ('<', '>', '#', '%',	'"') and unwise characters ('{', '}', '|', '\', '^', '[', ']', '`').
+	
+	@since			6.0
+	@param			aData	The descriptor to be checked.
+	@return			A boolean value of ETrue if the descriptor contains invalid
+	characters, otherwise EFalse.
+ */
+EXPORT_C TBool UriUtils::HasInvalidChars(const TDesC8& aData)
+	{
+	return CheckForExcludedChars(aData);
+	}
+	
+/**
+	Checks a descriptor for excluded (invalid) characters. Excluded characters include all 
+	control characters (values 0x00 to 0x1F and	greater than 0x7F), space (0x20), delimiter 
+	characters ('<', '>', '#', '%','"') and unwise characters ('{', '}', '|', '\', '^', '[', ']', '`').
+	
+	@since			6.0
+	@param			aData	The descriptor to be checked.
+	@return			A boolean value of ETrue if the descriptor contains invalid
+	characters, otherwise EFalse.
+ */
+EXPORT_C TBool UriUtils::HasInvalidChars(const TDesC16& aData)
+	{
+	return CheckForExcludedChars(aData);
+	}
+
+/**
+	Checks the supplied host for an IPv4, IPv6 or text format host
+	
+	@since			7.0
+	@param			aHost	The descriptor containing the host to check
+	@return			A TUriHostType enum of either EIPv6, EIPv4, EText or EUnknown
+ */
+EXPORT_C UriUtils::TUriHostType UriUtils::HostType(const TDesC8& aHost)
+	{
+	return CheckHostType(aHost);
+	}
+
+/**
+	Checks the supplied host for an IPv4, IPv6 or text format host
+	
+	@since			7.0
+	@param			aHost	The descriptor containing the host to check
+	@return			A TUriHostType enum of either EIPv6, EIPv4, EText or EUnknown
+ */
+EXPORT_C UriUtils::TUriHostType UriUtils::HostType(const TDesC16& aHost)
+	{
+	return CheckHostType(aHost);
+	}
+
+
+
+//
+//
+// Implementation of component internal functions
+//
+//
+
+/**
+	@internalComponent
+
+	Checks whether the given scheme is a network scheme or not
+	
+	@param aScheme The descriptor with the scheme.
+	@return A boolean value of EFalse if the scheme is SIP.	For all other schemes returns ETrue.
+ */
+TBool IsNetworkScheme(const TDesC8& aScheme)
+	{
+	TUriSchemeType scheme = SchemeType(aScheme);
+	if (scheme == ESchemeTypeSip)
+		{
+		return EFalse;
+		}
+	return ETrue;
+	}
+
+/**
+	@internalComponent
+
+	Checks whether the given scheme is a network scheme or not
+	
+	@param aScheme The descriptor with the scheme.
+	@return A boolean value of EFalse if the scheme is SIP.	For all other schemes returns ETrue.
+ */
+TBool IsNetworkScheme(const TDesC16& aScheme)
+	{
+	TUriSchemeType scheme = SchemeType(aScheme);
+	if (scheme == ESchemeTypeSip)
+		{
+		return EFalse;
+		}
+	return ETrue;
+	}
+
+/**
+	@internalComponent
+
+	Returns the type of the URIs scheme
+	
+	@param			aScheme	The descriptor with the scheme.
+	@return			The scheme type
+ */
+TUriSchemeType SchemeType(const TDesC8& aScheme)
+	{
+	// Compares the scheme with both sip and sips
+	if (aScheme.CompareF(KSipScheme8()) == 0 || aScheme.CompareF(KSipsScheme8()) == 0)
+		{
+		// there's a match so this is a sip scheme
+		return ESchemeTypeSip;
+		}
+	//Compares the scheme with tel 
+	else if (aScheme.CompareF(KTelScheme8()) == 0) 
+		{
+		return ESchemeTypeTel;
+		} 
+
+	return ESchemeTypeUnknown;
+	}
+
+/**
+	@internalComponent
+
+	Returns the type of the URIs scheme
+	
+	@param			aScheme	The descriptor with the scheme.
+	@return			The scheme type
+ */
+TUriSchemeType SchemeType(const TDesC16& aScheme)
+	{
+	// Compares the scheme with both sip and sips
+	if (aScheme.CompareF(KSipScheme()) == 0 || aScheme.CompareF(KSipsScheme()) == 0)
+		{
+		// there's a match so this is a sip scheme
+		return ESchemeTypeSip;
+		}
+
+	return ESchemeTypeUnknown;
+	}
+
+/**
+	@internalComponent
+
+	Checks that a text host is in a valid form
+	
+	@param			aHost	The descriptor containing the host to check
+	@return			ETrue if the host is valid otherwise EFalse
+ */
+TBool IsTextHostValid(const TDesC8& aHost)
+	{
+	return CheckValidTextHost(aHost);
+	}
+
+/**
+	@internalComponent
+
+	Checks that a text host is in a valid form
+	
+	@param			aHost	The descriptor containing the host to check
+	@return			ETrue if the host is valid otherwise EFalse
+ */
+TBool IsTextHostValid(const TDesC16& aHost)
+	{
+	return CheckValidTextHost(aHost);
+	}
+
+
+/**
+	@internalComponent
+
+	Parses a segment of the form name=value and returns the name and value parts
+	
+	@param			aSegment	the name-value segemnt to parse
+	@param			aName		the name part that is returned
+	@param			aValue		the value part that is returned
+ */
+void GetNameValuePair(const TDesC8& aSegment, TPtrC8& aName, TPtrC8& aValue)
+	{
+	TPtrC8 value;
+	TInt sepPos = aSegment.Locate(KEqualsSeparator);
+	if (sepPos != KErrNotFound)
+		{
+		aName.Set(aSegment.Left(sepPos));
+		value.Set(aSegment.Mid(sepPos+1));
+		}
+	else
+		{
+		aName.Set(aSegment);
+		}
+
+	aValue.Set(value);
+	}
+
+
+//
+//
+// Implementation of LOCAL functions
+//
+//
+
+/**
+	Checks the descriptor for any excluded characters. These are characters that 
+	should have been escaped encoded or ocnverted to Utf8 from Unicode.
+						
+	@since			6.0
+	@param			aData	The descriptor to be checked.
+	@return		A boolean value of ETrue if the descriptor contains excluded
+				characters, EFalse if it does not.
+ */
+template<class TDesCType>
+LOCAL_C TBool CheckForExcludedChars(const TDesCType& aData)
+	{
+	// Run through the descriptor
+	TBool valid = ETrue;
+	const TInt length = aData.Length();
+	TInt i=0;
+	while( valid && i<length )
+		{
+		TInt notUsed;
+		// See if the character is an excluded one, or is part of an escape triple...
+		if( EscapeUtils::IsExcludedChar(aData[i]) && !EscapeUtils::IsEscapeTriple(aData.Mid(i), notUsed) )
+			{
+			valid = EFalse;
+			}
+		else
+			{
+			++i;
+			}
+		}
+	return !valid;
+	}
+
+/**
+	Checks the supplied host for an IPv4, IPv6 or text format host
+	
+	@since			7.0
+	@param			aHost	The descriptor containing the host to check
+	@return			A TUriHostType enum of either EIPv6, EIPv4, EText or EUnknown
+ */
+template<class TDesCType>
+LOCAL_C UriUtils::TUriHostType CheckHostType(const TDesCType& aHost)
+	{
+	UriUtils::TUriHostType hostType;
+
+	TInt dotCount=0;
+	TBool colonPresent=EFalse;
+	TBool numeric=ETrue;
+
+	TInt len = aHost.Length();
+	for (TInt ii=0; ii < len && !colonPresent; ++ii)
+		{
+		TChar ch(aHost[ii]);
+
+		// host contains a character that is not '0'..'9' or '.'
+		if ((ch < 48 || ch > 57) && ch != 46)
+			numeric=EFalse;
+
+		// need to check that IPv4 address has the 3 dots
+		if (ch == 46)
+			++dotCount;
+		else
+			if (ch == 58)
+				colonPresent=ETrue;
+		}
+
+	if (colonPresent) // if theres a colon, it has to be an IPv6 address
+		hostType = UriUtils::EIPv6Host;
+	else
+		if (numeric  && (dotCount==3)) // if its numeric only, and has three seperators...
+			hostType = UriUtils::EIPv4Host;
+		else
+			hostType = UriUtils::ETextHost;
+
+	return hostType;
+	}
+
+/**
+	@internalComponent
+
+	Checks that a text host is in a valid form
+	
+	@param			aHost	The descriptor containing the host to check
+	@return			ETrue if the host is valid otherwise EFalse
+ */
+template<class TDesCType>
+LOCAL_C TBool CheckValidTextHost(const TDesCType& aHost)
+	{
+	TInt len = aHost.Length();
+	if (len == 0)
+		return EFalse;
+
+	// host name can't start with a dot or dash
+	TChar firstChar(aHost[0]);
+	if (firstChar == '-' || firstChar == '.')
+		return EFalse;
+
+	TChar prev = '\0';
+	TInt ii;
+	for (ii=0; ii < len; ii++)
+		{
+		TChar ch(aHost[ii]);
+
+		// Valid characters are a-z, 0-9, '-' and '.'
+		if ((ch < 'A' || ch > 'Z') && (ch < 'a' || ch > 'z') && (ch < '0' || ch > '9') && ch != '-' && ch != '.')
+			{
+			return EFalse;
+			}
+
+		// dot is the section separator. Check the previous section is not empty
+		if (ch == '.' && prev == '.')
+			{
+			// can't have an empty section
+			return EFalse;
+			}
+			prev = ch;
+		}
+
+	// host name can't end with a dot or dash
+	if (prev == '-' || prev == '.')
+		return EFalse;
+
+	return ETrue;
+	}
+
+/**
+	Supports Syntax-Based Normalization as specifed in section 6.2.2 of RFC3986.
+	returns a new CUri8 object containing a normalised URI from a parsed URI object.
+	
+	@param aUri	A reference to a parsed uri object.
+	@return A pointer to a CUri8 object containing normalised URI.
+	@leave KErrNoMemory
+	@internalAll
+ */
+EXPORT_C CUri8* UriUtils:: NormaliseUriL(const TUriC8& aUri)	
+	{
+	CUri8* normalisedUri = CUri8::NewLC(aUri);
+	PercentEncodeL(normalisedUri); 
+	CaseNormaliseL(normalisedUri);
+	RemoveDotSegmentsL(normalisedUri);
+	CleanupStack::Pop(normalisedUri);
+	return normalisedUri;
+	}
+	
+/**
+	Performs Case Normalization for CUri8 object as specified 
+	in section 6.2.2.1 of RFC3986.
+	
+	@param aNormalisedUri It is an in-out parameter. aNormalisedUri is a pointer 
+	to CUri8 object with an uri needs to be case normalised and returns with 
+	case normalised.
+	@leave KErrNoMemory
+ */
+void CaseNormaliseL(CUri8* aNormalisedUri )	
+	{
+	//Case normalise the scheme
+	DoCaseNormaliseL(aNormalisedUri, EUriScheme);	
+	//Case normalise the Userinfo
+	DoCaseNormaliseL(aNormalisedUri, EUriUserinfo);	
+	//Case normalise the Host
+	DoCaseNormaliseL(aNormalisedUri, EUriHost);	
+	//Case normalise the Port
+	DoCaseNormaliseL(aNormalisedUri, EUriPort);	
+	//Case normalise the Path
+	DoCaseNormaliseL(aNormalisedUri, EUriPath);	
+	//Case normalise the Query
+	DoCaseNormaliseL(aNormalisedUri, EUriQuery);	
+	//Case normalise the Fragment
+	DoCaseNormaliseL(aNormalisedUri, EUriFragment);	
+	}
+
+/**
+	Performs Case Normalization for specified sub component of URI.
+	
+	@param aNormalisedUri It is an in-out parameter. aNormalisedUri is a pointer 
+	to CUri8 object with an uri needs to be case normalised and returns with 
+	case normalised for specified sub component.
+	@param aComponent Enumeration of TUriComponent.
+	@leave KErrNoMemory
+*/
+void DoCaseNormaliseL(CUri8* aNormalisedUri, TUriComponent aComponent)
+	{
+	const TUriC8& uri(aNormalisedUri->Uri());
+	if(!uri.IsPresent(aComponent) )
+		{
+		return;
+		}
+	//extracts subcomponent of uri which needs to be case-normalised
+	HBufC8* heapBuf = uri.Extract(aComponent).AllocLC(); 	
+	TPtr8 normalisedComponent(heapBuf->Des());
+	TBool normalised = EFalse;
+	if(aComponent == EUriScheme || aComponent == EUriHost )
+		{
+		//change this component to lower case
+		normalisedComponent.LowerCase();
+		normalised = ETrue;
+		}
+	
+	TInt len =  normalisedComponent.Length();
+	TBuf8<KSubstringLength> subString;
+	//case normalise the component
+	for (TInt pos = 0; pos < len; pos++)
+		{
+		if (normalisedComponent[pos] == KEscapeIndicator )
+			{
+			__ASSERT_DEBUG( ((len-pos) >= KSubstringLength), User::Panic(KNormalisationUriPanicCategory, KUriUtilsErrBadEscapeTriple) );
+			TPtrC8 componentBuf(normalisedComponent.Mid(pos,KSubstringLength));
+			if (ValidateAndConvertPercentEncodedTriple(componentBuf,subString))
+				{
+				normalisedComponent.Replace(pos,KSubstringLength,subString);
+				pos += KUpdateLength;
+				normalised = ETrue;
+				subString.Zero();
+				}
+			}
+		}
+
+	//updating the uri with normalised string
+	if( normalised )
+		{
+		if(aComponent<EUriMaxComponents && aComponent >=EUriScheme)
+		   {
+		   aNormalisedUri->SetComponentL(normalisedComponent, aComponent);
+		   }
+		else
+		   {
+			User::Leave(KErrArgument);	
+		   }
+
+		}
+	CleanupStack::PopAndDestroy(heapBuf);
+	}
+
+/**
+	Validates and Converts the valid Percent encoded triplets to Uppercase for specified 
+	sub component of URI. For eg: Converts %3a to %3A
+	
+	@param aData A reference to a string to be validated and converted to upper case.
+	@param aCaseNormalizedData A reference to a descriptor that is converted to 
+	uppercase that is to be returned.
+	@return returns a bool whether it is a valid Percent encoded triplet
+*/
+TBool ValidateAndConvertPercentEncodedTriple(TDesC8& aData , TDes8& aCaseNormalizedData )	
+	{
+	// See if the descriptor is actually long enough and
+	// Check that the three characters form an escape triple - first char is '%'
+	if( aData.Length() < KEscapeTripleLength || aData[KEscDelimiterPos] != KEscapeIndicator )
+		{
+		return EFalse;//do nothing
+		}
+	
+	// Check that next two characters are valid
+	TInt mostSignificantDigitValue = KHexDigit().LocateF(aData[KMostSignificantNibblePos] );
+	TInt leastSignificantDigitValue = KHexDigit().LocateF(aData[KLeastSignificantNibblePos] );
+
+	if( mostSignificantDigitValue== KErrNotFound || leastSignificantDigitValue == KErrNotFound )
+		{
+		// Either of the characters were not a valid hex character
+		return EFalse;
+		}
+	aCaseNormalizedData.Zero();
+	aCaseNormalizedData.Append(KEscapeIndicator); 
+	
+	//Coverts most significant hex character to uppercase
+	(mostSignificantDigitValue >= 0 && mostSignificantDigitValue <= 0xF) ? 
+		aCaseNormalizedData.Append(KHexDigit().Mid(mostSignificantDigitValue,1)) :
+		aCaseNormalizedData.Append(KHexDigit().Mid(mostSignificantDigitValue,1));
+	
+	//Coverts least significant hex character to uppercase
+	(leastSignificantDigitValue >= 0 && leastSignificantDigitValue <= 0xF) ? 
+		aCaseNormalizedData.Append(KHexDigit().Mid(leastSignificantDigitValue,1)) :
+		aCaseNormalizedData.Append(aData[KLeastSignificantNibblePos]);
+	
+	return ETrue;
+	}
+
+/**
+	Performs Percent-Encoding Normalization for CUri8 object as specifed in 
+	section 6.2.2.2 of RFC3986.
+	
+	@param aNormalisedUri It is an in-out parameter. aNormalisedUri is a pointer to 
+	CUri8 object with an uri needs to be Percent-Encoded and returns with Percent-Encode 
+	normalised form.
+	@leave KErrNoMemory
+ */
+void  PercentEncodeL(CUri8* aNormalisedUri)
+	{
+	//PercentEncode the scheme
+	DoPercentEncodeL(aNormalisedUri, EUriScheme);	
+	//PercentEncode the Userinfo
+	DoPercentEncodeL(aNormalisedUri, EUriUserinfo);	
+	//PercentEncode the Host
+	DoPercentEncodeL(aNormalisedUri, EUriHost);	
+	//PercentEncode the Port
+	DoPercentEncodeL(aNormalisedUri, EUriPort);	
+	//PercentEncode the Path
+	DoPercentEncodeL(aNormalisedUri, EUriPath);	
+	//PercentEncode the Query
+	DoPercentEncodeL(aNormalisedUri, EUriQuery);	
+	//PercentEncode the Fragment
+	DoPercentEncodeL(aNormalisedUri, EUriFragment);	
+	}
+
+/**
+	Performs Percent-Encoding for specified sub component of URI.
+	
+	@param aNormalisedUri It is an in-out parameter. aNormalisedUri is a pointer to 
+	CUri8 object with an uri needs to be Percent-Encoded and returns with Percent-Encoded 
+	for specified sub component.
+	@param aComponent Enumeration of TUriComponent.
+	@leave KErrNoMemory
+*/
+void DoPercentEncodeL(CUri8* aNormalisedUri, TUriComponent aComponent)
+	{
+	const TUriC8& uri(aNormalisedUri->Uri());
+	if(!uri.IsPresent(aComponent))
+		{
+		return;
+		}
+	
+	HBufC8* heapBuf = uri.Extract(aComponent).AllocLC();
+	TPtr8 percentNormalisedComponent(heapBuf->Des());
+	TBool normalised = EFalse;
+	TInt len = percentNormalisedComponent.Length();	
+	for (TInt pos = 0; pos < len; pos++)
+		{
+		TInt hex;
+		// check for and decode '%' encoded characters
+		if (percentNormalisedComponent[pos] == KEscapeIndicator && EscapeUtils::IsEscapeTriple(percentNormalisedComponent.Mid(pos, KSubstringLength), hex))
+			{
+			TChar replacedChar(hex);
+			if( KUnreserved().LocateF(hex) != KErrNotFound || replacedChar.IsAlphaDigit() )
+				{
+				TBuf8<KAttachLength> subString;
+				subString.Append(replacedChar);
+				percentNormalisedComponent.Replace(pos, KSubstringLength, subString);
+				normalised = ETrue;
+				len = percentNormalisedComponent.Length();
+				}
+			}
+		}
+	if( normalised )
+		{
+		if(aComponent<EUriMaxComponents && aComponent >=EUriScheme)
+		   {
+		    aNormalisedUri->SetComponentL(percentNormalisedComponent, aComponent);
+		   }
+		else
+		   {
+			User::Leave(KErrArgument);	
+		   }
+
+		}
+	CleanupStack::PopAndDestroy(heapBuf); 	
+	}
+
+/**
+	Performs Path Segment Normalization for CUri8 object as specifed in 
+	section 6.2.2.3 of RFC3986.
+	
+	@param aNormalisedUri It is an in-out parameter. aNormalisedUri is a pointer to 
+	CUri8 object with uri needs to be Path Segment normalised and returns with 
+	Path Segment normalised form.
+	@leave KErrNoMemory
+ */
+void  RemoveDotSegmentsL(CUri8* aNormalisedUri)
+	{
+	const TUriC8& uri( aNormalisedUri->Uri() );
+	if(uri.IsPresent(EUriPath))
+		{
+		HBufC8* dotSegmentsPath = uri.Extract(EUriPath).AllocLC();
+		RemoveExtraneousDotSegmentsL(dotSegmentsPath);
+		aNormalisedUri->SetComponentL(*dotSegmentsPath, EUriPath);	
+		CleanupStack::PopAndDestroy(dotSegmentsPath);	
+		}
+	}
+
+/**
+	Performs Remove_dot_segments algorithm as specifed in section 5.2.4 of RFC3986.
+	
+	@param aUriInputPath It is an in-out parameter. aUriInputPath is a pointer to the 
+	path descriptor to be normalised for extraneous dot_segments and returns with 
+	normalised dot_segments.
+	@leave KErrNoMemory
+*/
+void RemoveExtraneousDotSegmentsL(HBufC8* aUriInputPath)
+	{
+	TPtr8 uriPathBuf(aUriInputPath->Des());
+	TInt length = uriPathBuf.Length();	
+	HBufC8* path = HBufC8::NewLC(length);
+	TPtr8 transitionalBuf(path->Des());
+
+	while(length > 0)	
+		{
+		//step a of section 5.2.4 of RFC 3986
+		if(length >= KDotDotSlashLength && 
+			KDotDotSlash().Compare(uriPathBuf.Mid(0, KDotDotSlashLength)) == 0 )
+			{
+			uriPathBuf.Delete(0,KDotDotSlashLength);
+			}
+		//step a of section 5.2.4 of RFC 3986
+		else if(length >= KDotDotLength && 
+				KDotSlash().Compare(uriPathBuf.Mid(0, KDotDotLength)) == 0)
+			{
+			uriPathBuf.Delete(0,KDotDotLength);	
+			}
+		//step b of section 5.2.4 of RFC 3986
+		else if(length >= KDotDotSlashLength && 
+				KSlashDotSlash().Compare(uriPathBuf.Mid(0, KDotDotSlashLength)) == 0)
+			{
+			uriPathBuf.Replace(0, KDotDotSlashLength, KSlash);
+			}
+		//step c of section 5.2.4 of RFC 3986
+		else if(length >= KSlashDotDotSlashLength && 
+				KSlashDotDotSlash().Compare(uriPathBuf.Mid(0, KSlashDotDotSlashLength)) == 0)
+			{
+			updateStrings(uriPathBuf, transitionalBuf, KSlashDotDotSlashLength);
+			}
+		//step c of section 5.2.4 of RFC 3986 --complete path segment
+		else if(length == KDotDotSlashLength && 
+				KSlashDotDot().Compare(uriPathBuf.Mid(0, KDotDotSlashLength)) == 0)
+			{
+			updateStrings(uriPathBuf, transitionalBuf, KDotDotSlashLength);
+			}
+		//step b of section 5.2.4 of RFC 3986--complete path segment
+		else if(length == KDotDotLength && 
+				KSlashDot().Compare(uriPathBuf.Mid(0, KDotDotLength)) == 0)
+			{
+			uriPathBuf.Replace(0, KDotDotLength, KSlash);
+			}
+		//step d of section 5.2.4 of RFC 3986
+		else if(length == KDotDotLength && 
+				KDotDot().Compare(uriPathBuf.Mid(0)) == 0)
+			{
+			uriPathBuf.Delete(0,KDotDotLength);	
+			}
+		//step d of section 5.2.4 of RFC 3986
+		else if(length == KDotLength && 
+				KDot().Compare(uriPathBuf.Mid(0)) == 0)
+			{
+			uriPathBuf.Delete(0,KDotLength);	
+			}
+		//step e of section 5.2.4 of RFC 3986
+		else 
+			{
+			//get the first path segment including initial / (if any)from uriPathBuf
+			// till next slash (but not including next slash)..append it to the output Buf	
+			TInt substrLength;
+			TInt nextSlashPos = uriPathBuf.Find(KSlash);
+			if(nextSlashPos == 0 && length > KDotLength)
+				//replace with locate next
+				{
+				nextSlashPos = uriPathBuf.Mid(1).Find(KSlash);
+				if(nextSlashPos != KErrNotFound)
+					{
+					++nextSlashPos;
+					}
+				}
+			if(length == KDotLength)
+				//only '/' is exist
+				{
+				substrLength = length;	
+				}
+			else
+				{
+				substrLength = nextSlashPos == KErrNotFound ? length : nextSlashPos ;	
+				}
+			transitionalBuf.Append(uriPathBuf.Mid(0,substrLength));
+			uriPathBuf.Delete(0,substrLength);	
+			}
+		length = uriPathBuf.Length();
+		}
+	uriPathBuf.Copy(transitionalBuf);
+	CleanupStack::PopAndDestroy(path);
+	}
+
+/**
+	Updates the strings specified in step c of section 5.2.4 of RFC 3986
+	
+	@param aInputBuf A reference to the inputBuf needs to be modified 
+	@param aOutPutBuf A reference to the outPutBuf needs to be modified
+	@param aLength length of the string to be replaced.
+ */
+void  updateStrings(TPtr8& aInputBuf, TPtr8& aOutPutBuf, TInt aLength)
+	{
+	aInputBuf.Replace(0,aLength,KSlash);
+
+	//In outPutBuf to remove the last segment starting with / (if exist)
+	//eg: /abc/def/fgh --> /abc/def
+	TInt outputBufLength = aOutPutBuf.Length();
+	TInt pos = aOutPutBuf.LocateReverse('/');	
+	//remove the last segment including '/'
+	pos != KErrNotFound ? aOutPutBuf.Delete( pos, outputBufLength - pos ) : aOutPutBuf.Delete( 0,outputBufLength );
+	}
+