1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/ossrv/genericservices/httputils/UriParser/TUriParser.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,526 @@
1.4 +// Copyright (c) 2001-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +//
1.18 +
1.19 +// System includes
1.20 +#include <uri8.h>
1.21 +#include <uri16.h>
1.22 +#include <uriutils.h>
1.23 +#include <uriutilscommon.h>
1.24 +
1.25 +
1.26 +//User includes
1.27 +#include "TUriParserInternal.h"
1.28 +#include "UriUtilsInternal.h"
1.29 +#include "TUriCInternal.h"
1.30 +#include "GenericUriParser.h"
1.31 +#include "SipUriParser.h"
1.32 +
1.33 +
1.34 +
1.35 +// Constants
1.36 +//
1.37 +
1.38 +_LIT8(KSIP, "Sip");
1.39 +_LIT8(KSIPS, "Sips");
1.40 +
1.41 +
1.42 +//
1.43 +//
1.44 +// Implementation of TUriParser8
1.45 +//
1.46 +//
1.47 +
1.48 +/**
1.49 + Constructor.
1.50 +
1.51 + @since 6.0
1.52 + */
1.53 +EXPORT_C TUriParser8::TUriParser8()
1.54 +: TUriC8()
1.55 + {
1.56 + }
1.57 +
1.58 +/**
1.59 + Parses the descriptor aUri into uri components.
1.60 +
1.61 + @since 6.0
1.62 + @param aUri A reference to a descriptor pointer to be parsed.
1.63 + @return KErrNone if the descriptor has been parsed into uri components.
1.64 + KUriUtilsParserErrInvalidUri if the descriptor is an invalid uri.
1.65 + KErrNoMemory if out of memory
1.66 + @post The object references the input descriptor.
1.67 + */
1.68 +EXPORT_C TInt TUriParser8::Parse(const TDesC8& aUri)
1.69 + {
1.70 + // Reset the Uri information and then set the Uri
1.71 + if( iUriDes.Length() )
1.72 + {
1.73 + Reset();
1.74 + }
1.75 + iUriDes.Set(aUri);
1.76 +
1.77 + // Check uri is valid
1.78 + if( iUriDes.Length() && iUriDes[0]==KSchemeDelimiter )
1.79 + {
1.80 + return KUriUtilsErrInvalidUri;
1.81 + }
1.82 +
1.83 + TPtrC8 schemeComponent;
1.84 + RetrieveScheme(iUriDes,schemeComponent);
1.85 + CGenericUriParser* UriHandler = NULL;
1.86 + TInt err=KErrNone;
1.87 + if(schemeComponent.CompareF(KSIP()) == 0 || schemeComponent.CompareF(KSIPS()) == 0 )
1.88 + {
1.89 + TRAP(err,UriHandler = CSIPUriParser::NewL());
1.90 + }
1.91 + else
1.92 + {
1.93 + TRAP(err,UriHandler = CGenericUriParser::NewL());
1.94 + }
1.95 + if(UriHandler)
1.96 + {
1.97 + UriHandler->DoParseUri(iUriDes, iComponent);
1.98 + delete UriHandler;
1.99 + }
1.100 +
1.101 + return err;
1.102 +
1.103 + }
1.104 +
1.105 +/**
1.106 + Parses the descriptor aUri into uri components.
1.107 +
1.108 + @param aUri A reference to a descriptor pointer of an Uri.
1.109 + @param aScheme A reference to a descriptor pointer for retieved
1.110 + scheme component.
1.111 + */
1.112 +void TUriParser8::RetrieveScheme(const TPtrC8& aUri, TPtrC8& aScheme)
1.113 + {
1.114 + TInt schemePos = aUri.Locate(KSchemeDelimiter);
1.115 + if(schemePos != KErrNotFound)
1.116 + {
1.117 + // Got a scheme - store information
1.118 + aScheme.Set(aUri.Left(schemePos));
1.119 + }
1.120 + }
1.121 +
1.122 +//
1.123 +//
1.124 +// Implementation of TUriParser16
1.125 +//
1.126 +//
1.127 +
1.128 +/**
1.129 + Constructor.
1.130 +
1.131 + @since 6.0
1.132 + @deprecated Deprecated in 9.1
1.133 + */
1.134 +EXPORT_C TUriParser16::TUriParser16()
1.135 +: TUriC16()
1.136 + {
1.137 + }
1.138 +
1.139 +/**
1.140 + Parses the descriptor aUri into uri components.
1.141 +
1.142 + @since 6.0
1.143 + @deprecated Deprecated in 9.1
1.144 + @param aUri A reference to a descriptor pointer to be parsed.
1.145 + @return KErrNone if the descriptor has been parsed into uri components.
1.146 + EUriParserErrInvalidUri if the descriptor is an invalid uri.
1.147 + @post The object references the input descriptor.
1.148 + */
1.149 +EXPORT_C TInt TUriParser16::Parse(const TDesC16& aUri)
1.150 + {
1.151 + // Reset the Uri information and then set the Uri
1.152 + if( iUriDes.Length() )
1.153 + Reset();
1.154 + iUriDes.Set(aUri);
1.155 +
1.156 + // Check uri is valid
1.157 + if( iUriDes.Length() && iUriDes[0]==KSchemeDelimiter )
1.158 + return KUriUtilsErrInvalidUri;
1.159 +
1.160 + // Parse the uri.
1.161 + DoParseUri(iUriDes, iComponent);
1.162 + return KErrNone;
1.163 + }
1.164 +
1.165 +//
1.166 +//
1.167 +// Implementation of templated LOCAL functions
1.168 +//
1.169 +//
1.170 +
1.171 +/**
1.172 + Templated function that parses a descriptor into the components of a uri.
1.173 +
1.174 + @since 6.0
1.175 + @param aUri The descriptor with the data to parse.
1.176 + @param aComponent The output array of descriptors of each uri component.
1.177 + @pre Each descriptor pointer in aComponent has had the pointer to its
1.178 + associated descriptor buffer set to NULL.
1.179 + @post The descriptor pointers in aComponent are updated to refer to the
1.180 + appropriate sections of aUri that represent the components of a uri.
1.181 +*/
1.182 +template<class TPtrCType>
1.183 +void DoParseUri(const TPtrCType& aUri, TPtrCType aComponent[])
1.184 + {
1.185 + // Parse the components
1.186 + TPtrCType uri = aUri;
1.187 + TInt consumed = 0;
1.188 + TPtrCType& scheme = aComponent[EUriScheme];
1.189 + if( (consumed = ParseScheme(uri, scheme)) > 0 )
1.190 + {
1.191 + uri.Set(uri.Mid(consumed));
1.192 + }
1.193 + if( (consumed = ParseAuthority(uri, aComponent[EUriUserinfo],
1.194 + aComponent[EUriHost], aComponent[EUriPort], IsNetworkScheme(scheme))) > 0 )
1.195 + {
1.196 + uri.Set(uri.Mid(consumed));
1.197 + }
1.198 + if( (consumed = ParsePath(uri, aComponent[EUriPath])) > 0 )
1.199 + {
1.200 + uri.Set(uri.Mid(consumed));
1.201 + }
1.202 + if( (consumed = ParseQuery(uri, aComponent[EUriQuery])) > 0 )
1.203 + {
1.204 + uri.Set(uri.Mid(consumed));
1.205 + }
1.206 + if( (consumed = ParseFragment(uri, aComponent[EUriFragment])) > 0 )
1.207 + {
1.208 + uri.Set(uri.Mid(consumed));
1.209 + }
1.210 + }
1.211 +
1.212 +/**
1.213 + Templated function to parse a descriptor for a scheme component. If a scheme is found
1.214 + then the output argument aScheme is set to refer to it.
1.215 +
1.216 + @since 6.0
1.217 + @param aUri The descriptor containing the uri to be parsed for
1.218 + a scheme.
1.219 + @param aScheme The output descriptor to refer to the scheme
1.220 + @return The number of characters consumed in parsing the scheme.
1.221 + @pre The output descriptor has been initialized so that the pointer
1.222 + to the associated descriptor buffer is NULL. The input descriptor
1.223 + is set to the start of the uri.
1.224 + @post If a scheme component exists then the output descriptor refers
1.225 + to it, otherwise the output descriptor is left unchanged.
1.226 +*/
1.227 +template<class TPtrCType>
1.228 +TInt ParseScheme(const TPtrCType& aUri, TPtrCType& aScheme)
1.229 + {
1.230 + // Get the descriptor and look for scheme delimiter
1.231 + TInt consumed =0;
1.232 + TInt endSchemePos = FindFirstUriDelimiter(aUri, ESchemeDelimiterSearch);
1.233 +
1.234 + if( endSchemePos != KErrNotFound )
1.235 + {
1.236 + // Got a scheme - store information
1.237 + aScheme.Set(aUri.Left(endSchemePos));
1.238 +
1.239 + // Set consumed amount move past scheme delimiter
1.240 + consumed = endSchemePos + 1;
1.241 + }
1.242 + return consumed;
1.243 + }
1.244 +
1.245 +/**
1.246 + Templated function to parse a descriptor for an authority component. If an authority is
1.247 + found then the output arguments aUserinfo, aHost and aPort are set to refer to those parts
1.248 + of the authority component. If an authority component exists then the host part exists. The
1.249 + userinfo and port parts are optional.
1.250 +
1.251 + @since 6.0
1.252 + @param aUri The descriptor containing the uri to be parsed
1.253 + for an authority.
1.254 + @param aUserinfo The output descriptor for the userinfo component.
1.255 + @param aHost The output descriptor for the host component.
1.256 + @param aPort The output descriptor for the port component.
1.257 + @param aUseNetworkDelimiter Whether the scheme uses the network delimeter '//'
1.258 + @return The number of characters consumed in parsing the authority.
1.259 + @pre The output descriptors have been initialized so that the pointer
1.260 + to the their associated descriptor buffers is NULL. The input descriptor
1.261 + is set to the start of the start of the authority component.
1.262 +
1.263 + @post If an authority component exists then the output descriptors refer
1.264 + to the userinfo part (if exists), the host part and the port part (if exists),
1.265 + otherwise the output descriptors are left unchanged.
1.266 +*/
1.267 +
1.268 +template<class TPtrCType>
1.269 +TInt ParseAuthority(const TPtrCType& aUri, TPtrCType& aUserinfo, TPtrCType& aHost, TPtrCType& aPort, TBool aUseNetworkDelimiter)
1.270 + {
1.271 + // Get uri descriptor and see if authority exists - if aUseNetworkDelimiter is true it has to start with '//'
1.272 + TInt consumed =0;
1.273 + const TInt prefixLength = aUseNetworkDelimiter ? KUriNetworkAuthorityDelimiterLength : 0;
1.274 + if( !aUseNetworkDelimiter ||
1.275 + (aUri.Length() >= prefixLength && aUri[0] == KSlashDelimiter && aUri[1] == KSlashDelimiter ))
1.276 + {
1.277 + // There is an authority
1.278 + TPtrCType authority = aUri.Mid(prefixLength);
1.279 +
1.280 + // Authority delimited by '/', '?', '#' or the end of the string
1.281 + TInt authorityEndPos = FindFirstUriDelimiter(authority, EAuthDelimiterSearch);
1.282 +
1.283 + // Got authority - parse it for its components
1.284 + authority.Set(authority.Left(authorityEndPos));
1.285 +
1.286 + // Get the userinfo...
1.287 + TInt userinfoEndPos = authority.Locate(KUserinfoDelimiter);
1.288 + if( userinfoEndPos != KErrNotFound )
1.289 + {
1.290 + // Store the information
1.291 + aUserinfo.Set(authority.Left(userinfoEndPos));
1.292 +
1.293 + // Move past the userinfo and the delimiter '@'
1.294 + authority.Set(authority.Mid(userinfoEndPos + 1));
1.295 + }
1.296 +
1.297 + // Authority is also delimited by ';' but this is valid in the userinfo so can only be checked now
1.298 + TInt semicolonPos = FindFirstUriDelimiter(authority, ESemiColonDelimiterFlag);
1.299 + if ( semicolonPos != KErrNotFound )
1.300 + {
1.301 + authority.Set(authority.Left(semicolonPos));
1.302 + authorityEndPos = semicolonPos + userinfoEndPos + 1;
1.303 + }
1.304 +
1.305 + // Set consumed amount to move past authority
1.306 + consumed += prefixLength + authorityEndPos;
1.307 +
1.308 + // Check if this is an IPv6 address by looking for the opening '['
1.309 + TInt startHostIPv6 = authority.Locate(KIPv6UriOpenBrace);
1.310 +
1.311 + if (startHostIPv6==KErrNotFound)
1.312 + {
1.313 + // This isn't an IPv6 address.....
1.314 +
1.315 + // Get host...
1.316 + TInt hostEndPos = authority.Locate(KPortDelimiter);
1.317 +
1.318 + // Host also delimited by the end of the authority
1.319 + if( hostEndPos == KErrNotFound )
1.320 + hostEndPos = authority.Length();
1.321 +
1.322 + // There's always a host, but can be empty - store information
1.323 + aHost.Set(authority.Left(hostEndPos));
1.324 +
1.325 + // Move past the host
1.326 + authority.Set(authority.Mid(hostEndPos));
1.327 + }
1.328 + else
1.329 + {
1.330 +
1.331 + // First, move past the opening brace
1.332 + authority.Set(authority.Mid(startHostIPv6 + 1));
1.333 + // auth now = X:X:X]?????
1.334 +
1.335 + // This is an IPv6 address, so it MUST have the closing brace too....
1.336 + TInt endIPv6Host = authority.Locate(KIPv6UriCloseBrace);
1.337 +
1.338 + // Return an error if the closing IPv6 delimiter isn't there.
1.339 + if (endIPv6Host==KErrNotFound)
1.340 + return KUriUtilsErrInvalidUri;
1.341 +
1.342 + // It's an ipv6 address, with an opening and closing brace. So now just extract it
1.343 + // auth = [X:X:X]?????
1.344 +
1.345 +
1.346 + // Set the host, and need to remove the closing brace
1.347 + aHost.Set(authority.Left(endIPv6Host));
1.348 + // host = X:X:X
1.349 +
1.350 + // Move past the host
1.351 + authority.Set(authority.Mid(endIPv6Host + 1 ));
1.352 + }
1.353 +
1.354 + // Get the port...
1.355 + TInt portEndPos = authority.Length();
1.356 + if( portEndPos )
1.357 + {
1.358 + // Store the port - remove leading ':'
1.359 + aPort.Set(authority.Mid(1, portEndPos - 1));
1.360 + }
1.361 + }
1.362 + return consumed;
1.363 + }
1.364 +
1.365 +/**
1.366 + Templated function to parse a descriptor for a path component.There is always a path component.
1.367 + The ouput argument aPath is set to the path component found.
1.368 +
1.369 + @since 6.0
1.370 + @param aUri The descriptor containing the uri to be parsed for
1.371 + a path.
1.372 + @param aComponent The output descriptor to refer to the path.
1.373 + @return The number of characters consumed in parsing the path.
1.374 + @pre The output descriptor has been initialized so that the pointer
1.375 + to the associated descriptor buffer is NULL. The input descriptor
1.376 + is set to the start of the path.
1.377 +
1.378 + @post The output descriptor refers to the path component.
1.379 +*/
1.380 +template<class TPtrCType>
1.381 +TInt ParsePath(const TPtrCType& aUri, TPtrCType& aComponent)
1.382 + {
1.383 + // Get descriptor with the path
1.384 + TInt consumed =0;
1.385 +
1.386 + // Path is delimited by '?'. '#' or the end of the string
1.387 + TInt pathEndPos = FindFirstUriDelimiter(aUri, EPathDelimiterSearch);
1.388 +
1.389 + // Check for presence of path
1.390 + if( pathEndPos != KErrNotFound )
1.391 + {
1.392 + // Got path - store information
1.393 + aComponent.Set(aUri.Left(pathEndPos));
1.394 +
1.395 + // Set consumed amount to move past path
1.396 + consumed = pathEndPos;
1.397 + }
1.398 + return consumed;
1.399 + }
1.400 +
1.401 +/**
1.402 + Templated function to parse a descriptor for a query component.If a query is found then
1.403 + the output argument aQuery is set to refer to it.
1.404 +
1.405 + @since 6.0
1.406 + @param aUri The descriptor containing the uri to be parsed for
1.407 + a query.
1.408 + @param aComponent The output descriptor to refer to the query
1.409 + @return The number of characters consumed in parsing the query.
1.410 + @pre The output descriptor has been initialized so that the pointer
1.411 + to the associated descriptor buffer is NULL. The input descriptor is set to
1.412 + the start of the query.
1.413 + @post If a query component exists then the output descriptor refers
1.414 + to it, otherwise the output descriptor is left unchanged.
1.415 +*/
1.416 +template<class TPtrCType>
1.417 +TInt ParseQuery(const TPtrCType& aUri, TPtrCType& aComponent)
1.418 + {
1.419 + // Get descriptor with the query
1.420 + TInt consumed =0;
1.421 +
1.422 + // Query is delimited by '#' or end of the string
1.423 + TInt queryEndPos = FindFirstUriDelimiter(aUri, EQueryDelimiterSearch);
1.424 +
1.425 + // Check for presence of query
1.426 + if( queryEndPos )
1.427 + {
1.428 + // Got query - store information; need to excluded leading '?'
1.429 + aComponent.Set(aUri.Mid(1, queryEndPos - 1));
1.430 +
1.431 + // Set consumed amount to move past query
1.432 + consumed = queryEndPos;
1.433 + }
1.434 + return consumed;
1.435 + }
1.436 +
1.437 +/**
1.438 + Templated function to parse a descriptor for a fragment component. If a fragment is found then
1.439 + the output argument aFragment is set to refer to it.
1.440 +
1.441 + @since 6.0
1.442 + @param aUri The descriptor containing the uri to be parsed for
1.443 + a fragment.
1.444 + @param aComponent The output descriptor to refer to the fragment.
1.445 + @return The number of characters consumed in parsing the fragment.
1.446 + @pre The output descriptor has been initialized so that the pointer
1.447 + to the associated descriptor buffer is NULL. The input descriptor is set to
1.448 + the start of the fragment.
1.449 + @post If a fragment component exists then the output descriptor refers
1.450 + to it, otherwise the output descriptor is left unchanged.
1.451 +*/
1.452 +template<class TPtrCType>
1.453 +TInt ParseFragment(const TPtrCType& aUri, TPtrCType& aComponent)
1.454 + {
1.455 + // Get descriptor with the fragment
1.456 + TInt consumed =0;
1.457 +
1.458 + // Fragment is delimited by end of the string
1.459 + TInt fragmentEndPos = aUri.Length();
1.460 +
1.461 + // Check for presence of fragment
1.462 + if( fragmentEndPos )
1.463 + {
1.464 + // Got fragment - store information; need to excluded leading '#'
1.465 + aComponent.Set(aUri.Mid(1, fragmentEndPos - 1));
1.466 +
1.467 + // Set consumed amount to move past fragment
1.468 + consumed = fragmentEndPos;
1.469 + }
1.470 + return consumed;
1.471 + }
1.472 +
1.473 +/**
1.474 + Templated function to find the position of the first delimiter in the descriptor specified
1.475 + by the delimiter flags. Note that the end of the descriptor is also a delimiter if there are
1.476 + no others. In the case of the scheme delimiter search, the position returned depends on the
1.477 + position of the colon delimiter with respect to the other delimiters for a scheme.
1.478 +
1.479 + @since 6.0
1.480 + @param aUri The descriptor containing the section of a uri to be searched.
1.481 + @param aSearchFlag The enum specifying the delimiters to search for.
1.482 + @return The position of nearest delimiter to start of the descriptor, where
1.483 + zero is the start (left-most) position.
1.484 +*/
1.485 +template<class TPtrCType>
1.486 +TInt FindFirstUriDelimiter(const TPtrCType& aUri, TDelimiterSearchFlag aSearchFlag)
1.487 + {
1.488 + // Set ultimate delimiter - string length
1.489 + TInt endPos = aUri.Length();
1.490 + if( aSearchFlag & EHashDelimiterFlag )
1.491 + {
1.492 + TInt fragmentPos = aUri.Locate(KFragmentDelimiter);
1.493 + if( fragmentPos != KErrNotFound && fragmentPos < endPos )
1.494 + endPos = fragmentPos;
1.495 + }
1.496 + if( aSearchFlag & EQueryDelimiterFlag )
1.497 + {
1.498 + TInt queryPos = aUri.Locate(KQueryDelimiter);
1.499 + if( queryPos != KErrNotFound && queryPos < endPos )
1.500 + endPos = queryPos;
1.501 + }
1.502 + if( aSearchFlag & ESlashDelimiterFlag )
1.503 + {
1.504 + TInt slashPos = aUri.Locate(KSlashDelimiter);
1.505 + if( slashPos != KErrNotFound && slashPos < endPos )
1.506 + endPos = slashPos;
1.507 + }
1.508 + if( aSearchFlag & ESemiColonDelimiterFlag )
1.509 + {
1.510 + TInt semiColonPos = aUri.Locate(KParamDelimiter);
1.511 + if( semiColonPos != KErrNotFound && semiColonPos < endPos )
1.512 + endPos = semiColonPos;
1.513 + }
1.514 + if( aSearchFlag & EColonDelimiterFlag )
1.515 + {
1.516 + TInt schemePos = aUri.Locate(KSchemeDelimiter);
1.517 + if( schemePos != KErrNotFound && schemePos < endPos )
1.518 + {
1.519 + // There is a scheme
1.520 + endPos = schemePos;
1.521 + }
1.522 + else if( aSearchFlag == ESchemeDelimiterSearch )
1.523 + {
1.524 + // Ok different if looking for scheme delimiter - no scheme, return KErrNotFound
1.525 + endPos = KErrNotFound;
1.526 + }
1.527 + }
1.528 + return endPos;
1.529 + }