--- /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 );
+ }
+