os/ossrv/genericservices/httputils/UriParser/TUriParser.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 // System includes
    17 #include <uri8.h>
    18 #include <uri16.h>
    19 #include <uriutils.h>
    20 #include <uriutilscommon.h>
    21 
    22 
    23 //User includes
    24 #include "TUriParserInternal.h"
    25 #include "UriUtilsInternal.h"
    26 #include "TUriCInternal.h"
    27 #include "GenericUriParser.h"
    28 #include "SipUriParser.h"
    29 
    30 
    31 
    32 // Constants
    33 //
    34 
    35 _LIT8(KSIP, "Sip");
    36 _LIT8(KSIPS, "Sips");
    37 
    38 
    39 //
    40 //
    41 // Implementation of TUriParser8
    42 //
    43 //
    44 
    45 /**
    46 	Constructor.
    47 	
    48 	@since			6.0
    49  */
    50 EXPORT_C TUriParser8::TUriParser8()
    51 : TUriC8()
    52 	{
    53 	}
    54 	
    55 /**
    56 	Parses the descriptor aUri into uri components.
    57 	
    58 	@since			6.0
    59 	@param			aUri A reference to a descriptor pointer to be parsed.
    60 	@return			KErrNone if the descriptor has been parsed into uri components.
    61 	KUriUtilsParserErrInvalidUri if the descriptor is an invalid uri.
    62 	KErrNoMemory if out of memory
    63 	@post			The object references the input descriptor.
    64  */
    65 EXPORT_C TInt TUriParser8::Parse(const TDesC8& aUri)
    66 	{
    67 	// Reset the Uri information and then set the Uri
    68 	if( iUriDes.Length() )
    69 		{
    70 		Reset();
    71 		}
    72 	iUriDes.Set(aUri);
    73 
    74 	// Check uri is valid
    75 	if( iUriDes.Length() && iUriDes[0]==KSchemeDelimiter )
    76 		{
    77 		return KUriUtilsErrInvalidUri;
    78 		}
    79 	
    80 	TPtrC8 schemeComponent;
    81 	RetrieveScheme(iUriDes,schemeComponent);
    82 	CGenericUriParser* UriHandler = NULL;
    83 	TInt err=KErrNone;
    84 	if(schemeComponent.CompareF(KSIP()) == 0 || schemeComponent.CompareF(KSIPS()) == 0 )
    85 		{
    86 	    TRAP(err,UriHandler = CSIPUriParser::NewL());
    87 		}
    88 	else
    89 		{
    90 	    TRAP(err,UriHandler = CGenericUriParser::NewL());
    91  		}
    92 	if(UriHandler)
    93 		{
    94 		UriHandler->DoParseUri(iUriDes, iComponent);
    95 		delete UriHandler;
    96 		}
    97        
    98 		return err;      
    99 
   100 	}
   101 
   102 /**
   103 	Parses the descriptor aUri into uri components.
   104 	
   105 	@param			aUri A reference to a descriptor pointer of an Uri.
   106 	@param			aScheme A reference to a descriptor pointer for retieved 
   107 					scheme component.
   108  */
   109 void TUriParser8::RetrieveScheme(const TPtrC8& aUri, TPtrC8& aScheme)
   110 	{
   111 	TInt schemePos = aUri.Locate(KSchemeDelimiter);
   112 	if(schemePos != KErrNotFound)
   113 		{
   114 		// Got a scheme - store information
   115 		aScheme.Set(aUri.Left(schemePos));
   116 		}
   117 	}
   118 
   119 //
   120 //
   121 // Implementation of TUriParser16
   122 //
   123 //
   124 
   125 /**
   126 	Constructor.
   127 	
   128 	@since			6.0
   129 	@deprecated Deprecated in 9.1
   130  */
   131 EXPORT_C TUriParser16::TUriParser16()
   132 : TUriC16()
   133 	{
   134 	}
   135 
   136 /**
   137 	Parses the descriptor aUri into uri components.
   138 	
   139 	@since			6.0
   140 	@deprecated Deprecated in 9.1
   141 	@param			aUri A reference to a descriptor pointer to be parsed.
   142 	@return			KErrNone if the descriptor has been parsed into uri components.
   143 	EUriParserErrInvalidUri if the descriptor is an invalid uri.
   144 	@post			The object references the input descriptor.
   145  */
   146 EXPORT_C TInt TUriParser16::Parse(const TDesC16& aUri)
   147 	{
   148 	// Reset the Uri information and then set the Uri
   149 	if( iUriDes.Length() )
   150 		Reset();
   151 	iUriDes.Set(aUri);
   152 
   153 	// Check uri is valid
   154 	if( iUriDes.Length() && iUriDes[0]==KSchemeDelimiter )
   155 		return KUriUtilsErrInvalidUri;
   156 
   157 	// Parse the uri.
   158 	DoParseUri(iUriDes, iComponent);
   159 	return KErrNone;
   160 	}
   161 
   162 //
   163 //
   164 // Implementation of templated LOCAL functions
   165 //
   166 //
   167 
   168 /**
   169 	Templated function that parses a descriptor into the components of a uri.
   170 						
   171 	@since			6.0
   172 	@param			aUri		The descriptor with the data to parse.
   173 	@param			aComponent	The output array of descriptors of each uri component.
   174 	@pre 			Each descriptor pointer in aComponent has had the pointer to its
   175 					associated descriptor buffer set to NULL.
   176 	@post			The descriptor pointers in aComponent are updated to refer to the 
   177 					appropriate sections of aUri that represent the components of a uri.
   178 */
   179 template<class TPtrCType>
   180 void DoParseUri(const TPtrCType& aUri, TPtrCType aComponent[])
   181 	{
   182 	// Parse the components
   183 	TPtrCType uri = aUri;
   184 	TInt consumed = 0;
   185 	TPtrCType& scheme = aComponent[EUriScheme];
   186 	if( (consumed = ParseScheme(uri, scheme)) > 0 )
   187 		{
   188 		uri.Set(uri.Mid(consumed));
   189 		}
   190 	if( (consumed = ParseAuthority(uri, aComponent[EUriUserinfo], 
   191 		 aComponent[EUriHost], aComponent[EUriPort], IsNetworkScheme(scheme))) > 0 )
   192 		{
   193 		uri.Set(uri.Mid(consumed));
   194 		}
   195 	if( (consumed = ParsePath(uri, aComponent[EUriPath])) > 0 )
   196 		{
   197 		uri.Set(uri.Mid(consumed));
   198 		}
   199 	if( (consumed = ParseQuery(uri, aComponent[EUriQuery])) > 0 )
   200 		{
   201 		uri.Set(uri.Mid(consumed));
   202 		}
   203 	if( (consumed = ParseFragment(uri, aComponent[EUriFragment])) > 0 )
   204 		{
   205 		uri.Set(uri.Mid(consumed));
   206 		}
   207 	}
   208 
   209 /**
   210 	Templated function to parse a descriptor for a scheme component. If a scheme is found 
   211 	then the output argument aScheme is set to refer to it.
   212 						
   213 	@since			6.0
   214 	@param			aUri	The descriptor containing the uri to be parsed for 
   215 	a scheme.
   216 	@param			aScheme	The output descriptor to refer to the scheme
   217 	@return			The number of characters consumed in parsing the scheme.
   218 	@pre 			The output descriptor has been initialized so that the pointer
   219 					to the associated descriptor buffer is NULL. The input descriptor 
   220 					is set to the start of the uri.
   221 	@post			If a scheme component exists then the output descriptor refers
   222 					to it, otherwise the output descriptor is left unchanged.
   223 */
   224 template<class TPtrCType>
   225 TInt ParseScheme(const TPtrCType& aUri, TPtrCType& aScheme)
   226 	{
   227 	// Get the descriptor and look for scheme delimiter
   228 	TInt consumed =0;
   229 	TInt endSchemePos = FindFirstUriDelimiter(aUri, ESchemeDelimiterSearch);
   230 
   231 	if( endSchemePos != KErrNotFound )
   232 		{
   233 		// Got a scheme - store information
   234 		aScheme.Set(aUri.Left(endSchemePos));
   235 
   236 		// Set consumed amount move past scheme delimiter
   237 		consumed = endSchemePos + 1;
   238 		}
   239 	return consumed;
   240 	}
   241 	
   242 /**
   243 	Templated function to parse a descriptor for an authority component. If an authority is 
   244 	found then the output arguments aUserinfo, aHost and aPort are set to refer to those parts 
   245 	of the authority component. If an authority component exists then the host part exists. The 
   246 	userinfo and port parts are optional.
   247 						
   248 	@since			6.0
   249 	@param			aUri		The descriptor containing the uri to be parsed 
   250 					for an authority.
   251 	@param			aUserinfo	The output descriptor for the userinfo component.
   252 	@param			aHost		The output descriptor for the host component.
   253 	@param			aPort		The output descriptor for the port component.
   254 	@param			aUseNetworkDelimiter Whether the scheme uses the network delimeter '//'
   255 	@return			The number of characters consumed in parsing the authority.
   256 	@pre 			The output descriptors have been initialized so that the pointer
   257 					to the their associated descriptor buffers is NULL. The input descriptor 
   258 					is set to the start of the start of the authority component.
   259 	
   260 	@post			If an authority component exists then the output descriptors refer
   261 					to the userinfo part (if exists), the host part and the port part (if exists), 
   262 					otherwise the output descriptors are left unchanged.
   263 */
   264 
   265 template<class TPtrCType> 
   266 TInt ParseAuthority(const TPtrCType& aUri, TPtrCType& aUserinfo, TPtrCType& aHost, TPtrCType& aPort, TBool aUseNetworkDelimiter)
   267 	{
   268 	// Get uri descriptor and see if authority exists - if aUseNetworkDelimiter is true it has to start with '//' 
   269 	TInt consumed =0;
   270 	const TInt prefixLength = aUseNetworkDelimiter ? KUriNetworkAuthorityDelimiterLength : 0;
   271   	if( !aUseNetworkDelimiter || 
   272   		(aUri.Length() >= prefixLength && aUri[0] == KSlashDelimiter && aUri[1] == KSlashDelimiter ))
   273 		{
   274 		// There is an authority
   275 		TPtrCType authority = aUri.Mid(prefixLength);
   276 
   277 		// Authority delimited by '/', '?', '#' or the end of the string
   278 		TInt authorityEndPos = FindFirstUriDelimiter(authority, EAuthDelimiterSearch);
   279 
   280 		// Got authority - parse it for its components
   281 		authority.Set(authority.Left(authorityEndPos));
   282 
   283 		// Get the userinfo...
   284 		TInt userinfoEndPos = authority.Locate(KUserinfoDelimiter);
   285 		if( userinfoEndPos != KErrNotFound )
   286 			{
   287 			// Store the information 
   288 			aUserinfo.Set(authority.Left(userinfoEndPos));
   289 			  
   290 			// Move past the userinfo and the delimiter '@'
   291 			authority.Set(authority.Mid(userinfoEndPos + 1));
   292 			}
   293 
   294 		// Authority is also delimited by ';' but this is valid in the userinfo so can only be checked now
   295 		TInt semicolonPos = FindFirstUriDelimiter(authority, ESemiColonDelimiterFlag);
   296 		if ( semicolonPos != KErrNotFound )
   297 			{
   298 			authority.Set(authority.Left(semicolonPos));
   299 			authorityEndPos = semicolonPos + userinfoEndPos + 1;
   300 			}
   301 		
   302 		// Set consumed amount to move past authority
   303 		consumed += prefixLength + authorityEndPos;
   304 		
   305 		// Check if this is an IPv6 address	by looking for the opening '['
   306 		TInt startHostIPv6 = authority.Locate(KIPv6UriOpenBrace);
   307 
   308 		if (startHostIPv6==KErrNotFound)
   309 			{
   310 			// This isn't an IPv6 address.....
   311 
   312 			// Get host...
   313 			TInt hostEndPos = authority.Locate(KPortDelimiter);
   314 
   315 			// Host also delimited by the end of the authority
   316 			if( hostEndPos == KErrNotFound )
   317 				hostEndPos = authority.Length();
   318 
   319 			// There's always a host, but can be empty - store information
   320 			aHost.Set(authority.Left(hostEndPos));
   321 
   322 			// Move past the host
   323 			authority.Set(authority.Mid(hostEndPos));
   324 			}
   325 		else
   326 			{
   327 		
   328 	    // First, move past the opening brace
   329 	        authority.Set(authority.Mid(startHostIPv6 + 1));
   330 	            // auth now = X:X:X]?????
   331 	            
   332 			// This is an IPv6 address, so it MUST have the closing brace too....
   333 			TInt endIPv6Host = authority.Locate(KIPv6UriCloseBrace);
   334 
   335 			// Return an error if the closing IPv6 delimiter isn't there.
   336 			if (endIPv6Host==KErrNotFound)
   337 				return KUriUtilsErrInvalidUri;
   338 
   339 			// It's an ipv6  address, with an opening and closing brace. So now just extract it
   340 			// auth = [X:X:X]?????
   341 
   342 
   343 			// Set the host, and need to remove the closing brace
   344 			aHost.Set(authority.Left(endIPv6Host));
   345 			// host = X:X:X
   346 
   347 			// Move past the host
   348 			authority.Set(authority.Mid(endIPv6Host + 1 ));
   349 			}
   350 		
   351 		// Get the port...
   352 		TInt portEndPos = authority.Length();
   353 		if( portEndPos )
   354 			{
   355 			// Store the port - remove leading ':'
   356 			aPort.Set(authority.Mid(1, portEndPos - 1));
   357 			}
   358 		}
   359 	return consumed;
   360 	}
   361 
   362 /**
   363 	Templated function to parse a descriptor for a path component.There is always a path component.
   364 	The ouput argument aPath is set to the path component found.
   365 						
   366 	@since			6.0
   367 	@param			aUri	The descriptor containing the uri to be parsed for 
   368 	a path.
   369 	@param			aComponent	The output descriptor to refer to the path.
   370 	@return			The number of characters consumed in parsing the path.
   371 	@pre 			The output descriptor has been initialized so that the pointer
   372 					to the associated descriptor buffer is NULL. The input descriptor 
   373 					is set to the start of the path.
   374 					
   375 	@post			The output descriptor refers to the path component.
   376 */
   377 template<class TPtrCType>
   378 TInt ParsePath(const TPtrCType& aUri, TPtrCType& aComponent)
   379 	{
   380 	// Get descriptor with the path
   381 	TInt consumed =0;
   382 
   383 	// Path is delimited by '?'. '#' or the end of the string
   384 	TInt pathEndPos = FindFirstUriDelimiter(aUri, EPathDelimiterSearch);
   385 
   386 	// Check for presence of path
   387 	if( pathEndPos != KErrNotFound )
   388 		{
   389 		// Got path - store information
   390 		aComponent.Set(aUri.Left(pathEndPos));
   391 	
   392 		// Set consumed amount to move past path
   393 		consumed = pathEndPos;
   394 		}
   395 	return consumed;
   396 	}
   397 
   398 /**
   399 	Templated function to parse a descriptor for a query component.If a query is found then 
   400 	the output argument aQuery is set to refer to it.
   401 						
   402 	@since			6.0
   403 	@param			aUri	The descriptor containing the uri to be parsed for 
   404 	a query.
   405 	@param			aComponent	The output descriptor to refer to the query
   406 	@return			The number of characters consumed in parsing the query.
   407 	@pre 			The output descriptor has been initialized so that the pointer
   408 					to the associated descriptor buffer is NULL. The input descriptor is set to
   409 					the start of the query.
   410 	@post			If a query component exists then the output descriptor refers
   411 					to it, otherwise the output descriptor is left unchanged.
   412 */
   413 template<class TPtrCType>
   414 TInt ParseQuery(const TPtrCType& aUri, TPtrCType& aComponent)
   415 	{
   416 	// Get descriptor with the query
   417 	TInt consumed =0;
   418 
   419 	// Query is delimited by '#' or end of the string 
   420 	TInt queryEndPos = FindFirstUriDelimiter(aUri, EQueryDelimiterSearch);
   421 
   422 	// Check for presence of query
   423 	if( queryEndPos )
   424 		{
   425 		// Got query - store information; need to excluded leading '?'
   426 		aComponent.Set(aUri.Mid(1, queryEndPos - 1));
   427 	
   428 		// Set consumed amount to move past query
   429 		consumed = queryEndPos;
   430 		}
   431 	return consumed;
   432 	}
   433 
   434 /**
   435 	Templated function to parse a descriptor for a fragment component. If a fragment is found then 
   436 	the output argument aFragment is set to refer to it.
   437 						
   438 	@since			6.0
   439 	@param			aUri		The descriptor containing the uri to be parsed for 
   440 					a fragment.
   441 	@param			aComponent	The output descriptor to refer to the fragment.
   442 	@return			The number of characters consumed in parsing the fragment.
   443 	@pre 			The output descriptor has been initialized so that the pointer
   444 					to the associated descriptor buffer is NULL. The input descriptor is set to
   445 					the start of the fragment.
   446 	@post			If a fragment component exists then the output descriptor refers
   447 					to it, otherwise the output descriptor is left unchanged.
   448 */
   449 template<class TPtrCType>
   450 TInt ParseFragment(const TPtrCType& aUri, TPtrCType& aComponent)
   451 	{
   452 	// Get descriptor with the fragment
   453 	TInt consumed =0;
   454 
   455 	// Fragment is delimited by end of the string
   456 	TInt fragmentEndPos = aUri.Length();
   457 
   458 	// Check for presence of fragment
   459 	if( fragmentEndPos )
   460 		{
   461 		// Got fragment - store information; need to excluded leading '#'
   462 		aComponent.Set(aUri.Mid(1, fragmentEndPos - 1));
   463 	
   464 		// Set consumed amount to move past fragment
   465 		consumed = fragmentEndPos;
   466 		}
   467 	return consumed;
   468 	}
   469 	
   470 /**
   471 	Templated function to find the position of the first delimiter in the descriptor specified 
   472 	by the delimiter flags. Note that the end of the descriptor is also a delimiter if there are 
   473 	no others. In the case of the scheme delimiter search, the position returned depends on the 
   474 	position of the colon delimiter with respect to the other delimiters for a scheme.
   475 						
   476 	@since			6.0
   477 	@param			aUri		The descriptor containing the section of a uri to be searched.
   478 	@param			aSearchFlag	The enum specifying the delimiters to search for.
   479 	@return			The position of nearest delimiter to start of the descriptor, where
   480 					zero is the start (left-most) position.
   481 */
   482 template<class TPtrCType> 
   483 TInt FindFirstUriDelimiter(const TPtrCType& aUri, TDelimiterSearchFlag aSearchFlag)
   484 	{
   485 	// Set ultimate delimiter - string length
   486 	TInt endPos = aUri.Length();
   487 	if( aSearchFlag & EHashDelimiterFlag )
   488 		{
   489 		TInt fragmentPos = aUri.Locate(KFragmentDelimiter);
   490 		if( fragmentPos != KErrNotFound && fragmentPos < endPos )
   491 			endPos = fragmentPos;
   492 		}
   493 	if( aSearchFlag & EQueryDelimiterFlag )
   494 		{
   495 		TInt queryPos = aUri.Locate(KQueryDelimiter);
   496 		if( queryPos != KErrNotFound && queryPos < endPos )
   497 			endPos = queryPos;
   498 		}
   499 	if( aSearchFlag & ESlashDelimiterFlag )
   500 		{
   501 		TInt slashPos = aUri.Locate(KSlashDelimiter);
   502 		if( slashPos != KErrNotFound && slashPos < endPos )
   503 			endPos = slashPos;
   504 		}
   505 	if( aSearchFlag & ESemiColonDelimiterFlag )
   506 		{
   507 		TInt semiColonPos = aUri.Locate(KParamDelimiter);
   508 		if( semiColonPos != KErrNotFound && semiColonPos < endPos )
   509 			endPos = semiColonPos;
   510 		}
   511 	if( aSearchFlag & EColonDelimiterFlag )
   512 		{
   513 		TInt schemePos = aUri.Locate(KSchemeDelimiter);
   514 		if( schemePos != KErrNotFound && schemePos < endPos )
   515 			{
   516 			// There is a scheme
   517 			endPos = schemePos;
   518 			}
   519 		else if( aSearchFlag == ESchemeDelimiterSearch )
   520 			{
   521 			// Ok different if looking for scheme delimiter - no scheme, return KErrNotFound
   522 			endPos = KErrNotFound;
   523 			}
   524 		}
   525 	return endPos;
   526 	}