javacommons/gcfbase/src.s60/turi.cpp
changeset 21 2a9601315dfc
equal deleted inserted replaced
18:e8e63152f320 21:2a9601315dfc
       
     1 /*
       
     2 * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:  URI parser specific to symbian
       
    15 *
       
    16 */
       
    17 
       
    18 
       
    19 #include "turi.h"
       
    20 
       
    21 
       
    22 
       
    23 const TInt KMinSizeOfEqualsAndValue = 2;
       
    24 const TUint16 KCharColon = ':';
       
    25 const TUint16 KCharSemiColon = ';';
       
    26 const TUint16 KCharForwardSlash = '/';
       
    27 const TUint16 KCharEquals = '=';
       
    28 const TUint16 KCharQuestionMark = '?';
       
    29 _LIT(KSlashes, "//");
       
    30 _LIT(KIPv6PrefixForIPv4MappedAddress, "::ffff:");
       
    31 _LIT(KParamValueTrue, "true");
       
    32 _LIT(KParamValueFalse, "false");
       
    33 
       
    34 
       
    35 
       
    36 // ----------------------------------------------------------------------------
       
    37 // TUri
       
    38 //
       
    39 
       
    40 /**
       
    41 There is not much else to distinguish the most basic URI from other strings,
       
    42 so all we test here is if it contains a colon.
       
    43 */
       
    44 TBool TUri::IsUri(const TDesC16& aName)
       
    45 {
       
    46     return (aName.Locate(KCharColon) > 0);
       
    47 }
       
    48 
       
    49 
       
    50 
       
    51 /**
       
    52 Parses a URI, based on the format detailed in RFC 2396, e.g.
       
    53 <scheme>://<authority><path>?<query>
       
    54 or more generally:
       
    55 <scheme>:<scheme-specific-part>
       
    56 if aCheckForSlashes is ETrue and scheme-specific-part
       
    57 doesn't start with 2 slashes, Parse returns KErrArgument
       
    58 */
       
    59 TInt TUri::Parse(const TDesC16& aDes , TBool aCheckForSlashes)
       
    60 {
       
    61     iScheme.Set(KNullDesC());
       
    62     iSchemeData.Set(KNullDesC());
       
    63     iHost.Set(KNullDesC());
       
    64     iPort.Set(KNullDesC());
       
    65     iPath.Set(KNullDesC());
       
    66     iParameters.Set(KNullDesC());
       
    67     iQuery.Set(KNullDesC());
       
    68 
       
    69     // Set this descriptor to equal the given URI
       
    70     Set(aDes);
       
    71     // Ensure that the colon is present and determine the scheme and scheme-specific
       
    72     // part
       
    73     TInt colonIndex = Locate(KCharColon);
       
    74     // The scheme must not be empty
       
    75     if (colonIndex <= 0)
       
    76     {
       
    77         return KErrArgument;
       
    78     }
       
    79     iScheme.Set(Left(colonIndex));
       
    80     iSchemeData.Set(Mid(colonIndex + 1));
       
    81 
       
    82     // Parse the scheme data further - we assume it is going to start with 2 slashes
       
    83     // and may contain stuff like a host, port, path, parameters. If it does not
       
    84     // have 2 slashes we do no more parsing.
       
    85     if (iSchemeData.Find(KSlashes()) == 0)
       
    86     {
       
    87         TPtrC16 portionToParse(iSchemeData.Mid(KSlashes().Length()));
       
    88 
       
    89         // Parse location (host and port)
       
    90         TInt pathStartIndex = portionToParse.Locate(KCharForwardSlash);
       
    91         TInt parametersStartIndex = portionToParse.Locate(KCharSemiColon);
       
    92         TInt queryStartIndex = portionToParse.Locate(KCharQuestionMark);
       
    93         // Find the length of the location portion of the URI
       
    94         TInt locationLength = portionToParse.Length();
       
    95         if (pathStartIndex != KErrNotFound)
       
    96         {
       
    97             locationLength = pathStartIndex;
       
    98         }
       
    99         else if (parametersStartIndex != KErrNotFound)
       
   100         {
       
   101             locationLength = parametersStartIndex;
       
   102         }
       
   103         else if (queryStartIndex != KErrNotFound)
       
   104         {
       
   105             locationLength = queryStartIndex;
       
   106         }
       
   107         // Extract the host and port from the location portion, separated by a colon
       
   108         const TPtrC16 location(portionToParse.Left(locationLength));
       
   109         // handle the case of an IPv4-mapped address, like ::ffff:10.10.10.10
       
   110         TPtrC16 IPv4Location;
       
   111         TInt prefixLength = 0;
       
   112         if (location.FindF(KIPv6PrefixForIPv4MappedAddress()) == 0)
       
   113         {
       
   114             prefixLength = KIPv6PrefixForIPv4MappedAddress().Length();
       
   115             IPv4Location.Set(location.Mid(prefixLength));
       
   116         }
       
   117         else
       
   118         {
       
   119             IPv4Location.Set(location);
       
   120         }
       
   121         TInt locationColonIndex = IPv4Location.Locate(KCharColon);
       
   122         if (locationColonIndex != KErrNotFound)
       
   123         {
       
   124             iHost.Set(location.Left(prefixLength + locationColonIndex));
       
   125             iPort.Set(IPv4Location.Mid(locationColonIndex + 1));
       
   126         }
       
   127         else
       
   128         {
       
   129             iHost.Set(location);
       
   130         }
       
   131 
       
   132         // Parse path (and Query)
       
   133         if (pathStartIndex != KErrNotFound)
       
   134         {
       
   135             // Skip past the '/' character that marks the start of the path
       
   136             portionToParse.Set(portionToParse.Mid(locationLength + 1));
       
   137         }
       
   138         queryStartIndex = portionToParse.Locate(KCharQuestionMark);
       
   139         if (queryStartIndex != KErrNotFound)
       
   140         {
       
   141             iQuery.Set(portionToParse.Mid(queryStartIndex + 1));
       
   142             portionToParse.Set(portionToParse.Left(queryStartIndex));
       
   143         }
       
   144         if (pathStartIndex != KErrNotFound)
       
   145         {
       
   146             iPath.Set(portionToParse);
       
   147         }
       
   148 
       
   149         // Parse parameters
       
   150         parametersStartIndex = portionToParse.Locate(KCharSemiColon);
       
   151         if (parametersStartIndex != KErrNotFound)
       
   152         {
       
   153             // Do not skip the ';' character that marks the start of the parameters
       
   154             iParameters.Set(portionToParse.Mid(parametersStartIndex));
       
   155         }
       
   156 
       
   157     }
       
   158     else
       
   159     {
       
   160         if (aCheckForSlashes)
       
   161             return KErrArgument;
       
   162         else
       
   163         {
       
   164             //not checking for slashes, but do expect there to be parameters
       
   165             //used for CommConnection URIs
       
   166             TInt parametersStartIndex = iSchemeData.Locate(KCharSemiColon);
       
   167             if (parametersStartIndex != KErrNotFound)
       
   168             {
       
   169                 iPort.Set(iSchemeData.Left(parametersStartIndex));
       
   170                 // Do not skip the ';' character that marks the start of the parameters
       
   171                 iParameters.Set(iSchemeData.Mid(parametersStartIndex));
       
   172             }
       
   173             else
       
   174             {
       
   175                 iPort.Set(iSchemeData);
       
   176             }
       
   177         }
       
   178     }
       
   179     return KErrNone;
       
   180 }
       
   181 
       
   182 
       
   183 
       
   184 TInt TUri::PortAsUint(TUint& aPortNum) const
       
   185 {
       
   186     if (iPort.Length() == 0)
       
   187     {
       
   188         return KErrNotFound;
       
   189     }
       
   190     TLex16 portParser(iPort);
       
   191     TInt error = portParser.Val(aPortNum);
       
   192     // Check that the whole port string was parsed to a number
       
   193     if (error != KErrNone || !portParser.Eos())
       
   194     {
       
   195         return KErrArgument;
       
   196     }
       
   197     return KErrNone;
       
   198 }
       
   199 
       
   200 
       
   201 
       
   202 /**
       
   203 Looks for the boolean value of the named parameter.
       
   204 @param aParamName The name of the boolean parameter.
       
   205 @param aValue The value that is set to the value of the parameter. This is
       
   206 not changed if an error code is returned.
       
   207 @return KErrNotFound if the parameter is not defined, KErrArgument if there
       
   208 is a parsing error, otherwise KErrNone.
       
   209 */
       
   210 TInt TUri::GetParameterValue(const TDesC16& aParamName, TBool& aValue) const
       
   211 {
       
   212     // Assign default value
       
   213     TBool value;
       
   214     TPtrC16 paramValue;
       
   215     TInt error = GetParameterValue(aParamName, paramValue);
       
   216     if (error != KErrNone)
       
   217     {
       
   218         return error;
       
   219     }
       
   220     if (paramValue.CompareF(KParamValueTrue()) == 0)
       
   221     {
       
   222         value = ETrue;
       
   223     }
       
   224     else if (paramValue.CompareF(KParamValueFalse()) == 0)
       
   225     {
       
   226         value = EFalse;
       
   227     }
       
   228     else
       
   229     {
       
   230         return KErrArgument;
       
   231     }
       
   232     aValue = value;
       
   233     return KErrNone;
       
   234 }
       
   235 
       
   236 
       
   237 
       
   238 /**
       
   239 Looks for the integer value of the named parameter. If the parameter is
       
   240 not found, it dos not change the value of aValue.
       
   241 @return KErrNotFound if the parameter is not defined, KErrArgument if there
       
   242 is a parsing error, otherwise KErrNone.
       
   243 */
       
   244 TInt TUri::GetParameterValueInt(const TDesC16& aParamName, TInt& aValue) const
       
   245 {
       
   246     TPtrC16 paramValue;
       
   247     TInt error = GetParameterValue(aParamName, paramValue);
       
   248     if (error != KErrNone)
       
   249     {
       
   250         return error;
       
   251     }
       
   252     TLex16 numberParser(paramValue);
       
   253     TInt value;
       
   254     error = numberParser.Val(value);
       
   255     if (error != KErrNone)
       
   256     {
       
   257         return KErrArgument;
       
   258     }
       
   259     aValue = value;
       
   260     return KErrNone;
       
   261 }
       
   262 
       
   263 
       
   264 
       
   265 TInt TUri::GetParameterValue(const TDesC16& aParamName, TPtrC16& aValue) const
       
   266 {
       
   267     __ASSERT_DEBUG(aParamName.Length() > 0, User::Invariant());
       
   268 
       
   269     TInt index = FindParamNameIndex(aParamName, iParameters);
       
   270     if (index < KErrNone)
       
   271     {
       
   272         return index;
       
   273     }
       
   274     // We know the value is defined in the parameter list
       
   275     // Ensure that the parameter is defined only once in the list
       
   276     TPtrC16 restOfParameterList(iParameters.Mid(index + aParamName.Length()));
       
   277     TInt secondParamIndex = FindParamNameIndex(aParamName, restOfParameterList);
       
   278     if (secondParamIndex >= KErrNone)
       
   279     {
       
   280         // Parameter is defined twice, which is invalid
       
   281         return KErrArgument;
       
   282     }
       
   283     // Skip over the name and equals sign
       
   284     index += aParamName.Length();
       
   285     ++index;
       
   286     // Extract the value itself
       
   287     const TPtrC16 remainder(iParameters.Mid(index));
       
   288     TInt nextSemiColonIndex = remainder.Locate(KCharSemiColon);
       
   289     TInt paramValueLength = (nextSemiColonIndex != KErrNotFound) ?
       
   290                             nextSemiColonIndex : iParameters.Length();
       
   291     aValue.Set(remainder.Left(paramValueLength));
       
   292     return KErrNone;
       
   293 }
       
   294 
       
   295 
       
   296 
       
   297 /**
       
   298 Finds the index of the parameter name. Checks that there are enough characters
       
   299 after the name for the equals sign and a value of length 1, and that the name
       
   300 has a semi-colon in front and an equals after it.
       
   301 */
       
   302 TInt TUri::FindParamNameIndex(const TDesC16& aParamName,
       
   303                               const TDesC16& aParametersSegment) const
       
   304 {
       
   305     TPtrC16 parameters(aParametersSegment);
       
   306     TInt nameIndex = KErrNotFound;
       
   307     TInt paramSegmentIndex = 0;
       
   308     do
       
   309     {
       
   310 //      DEBUG( "TUri::GetParameterValue(): finding param name: %S", &aParamName );
       
   311         // FindF is used because the case is not relevant for data within the URI
       
   312         TInt index = parameters.FindF(aParamName);
       
   313         if (index == KErrNotFound)
       
   314         {
       
   315             return KErrNotFound;
       
   316         }
       
   317 
       
   318         TInt endOfParamNameIndex = index + aParamName.Length();
       
   319         // Check there are enough extra characters after the parameter name for the
       
   320         // equals and value
       
   321         TPtrC16 afterParamNameString(parameters.Mid(endOfParamNameIndex));
       
   322         if (afterParamNameString.Length() < KMinSizeOfEqualsAndValue)
       
   323         {
       
   324             return KErrArgument;
       
   325         }
       
   326 
       
   327         // Check the parameter name found is a complete name and not part of a
       
   328         // larger string, i.e. it has a semi-colon in front and an equals after
       
   329         if (index == 0 || parameters[index - 1] != KCharSemiColon ||
       
   330                 parameters[endOfParamNameIndex] != KCharEquals)
       
   331         {
       
   332             paramSegmentIndex += endOfParamNameIndex;
       
   333             parameters.Set(parameters.Mid(endOfParamNameIndex));
       
   334         }
       
   335         else
       
   336         {
       
   337             nameIndex = paramSegmentIndex + index;
       
   338         }
       
   339     }
       
   340     while (nameIndex == KErrNotFound);
       
   341     return nameIndex;
       
   342 }
       
   343 
       
   344 
       
   345 
       
   346 /**
       
   347 Iterates through the parameters of the URI, checking that each parameter name is
       
   348 present in the supplied list of valid names.
       
   349 @return KErrNone if all parameter names match the legal ones, or if there are
       
   350 no parameters in the URI, as parameters are optional anyway.
       
   351 */
       
   352 TInt TUri::CheckParameterValidity(const RPointerArray<TDesC16>& aLegalParams) const
       
   353 {
       
   354     if (iParameters.Length() == 0)
       
   355     {
       
   356         return KErrNone;
       
   357     }
       
   358     TPtrC16 remainder(iParameters);
       
   359     TInt semiColonIndex = 0;
       
   360     do
       
   361     {
       
   362         remainder.Set(remainder.Mid(semiColonIndex + 1));
       
   363         TInt error = CheckParameter(aLegalParams, remainder);
       
   364         if (error != KErrNone)
       
   365         {
       
   366             return error;
       
   367         }
       
   368         semiColonIndex = remainder.Locate(KCharSemiColon);
       
   369     }
       
   370     while (semiColonIndex != KErrNotFound);
       
   371     return KErrNone;
       
   372 }
       
   373 
       
   374 
       
   375 
       
   376 /**
       
   377 Checks that the parameter name at the start of aRemainder is present in the
       
   378 list of legal parameters.
       
   379 */
       
   380 TInt TUri::CheckParameter(const RPointerArray<TDesC16>& aLegalParams,
       
   381                           const TDesC16& aRemainder) const
       
   382 {
       
   383     // Find the end of the parameter name
       
   384     TInt equalsIndex = aRemainder.Locate(KCharEquals);
       
   385     if (equalsIndex == KErrNotFound)
       
   386     {
       
   387         return KErrArgument;
       
   388     }
       
   389     // Search for the name in the legal names list
       
   390     TPtrC16 paramName(aRemainder.Left(equalsIndex));
       
   391     TIdentityRelation<TDesC16> relation(&TUri::MatchParamName);
       
   392     TInt nameIndex = aLegalParams.Find(&paramName, relation);
       
   393     if (nameIndex == KErrNotFound)
       
   394     {
       
   395         return KErrArgument;
       
   396     }
       
   397     return KErrNone;
       
   398 }
       
   399 
       
   400 
       
   401 
       
   402 /**
       
   403 Utility method for use with RArray::Find().
       
   404 */
       
   405 TBool TUri::MatchParamName(const TDesC16& aName1, const TDesC16& aName2)
       
   406 {
       
   407     return (aName1.CompareF(aName2) == 0);
       
   408 }
       
   409 
       
   410 
       
   411 
       
   412 /**
       
   413 Check there are no duplicate parameters
       
   414 */
       
   415 TInt TUri::CheckNoDuplicateParameters() const
       
   416 {
       
   417     if (iParameters.Length() == 0)
       
   418     {
       
   419         return KErrNone;
       
   420     }
       
   421 
       
   422     RArray<TPtrC16> parameters;
       
   423     TPtrC16 remainder(iParameters);
       
   424     TInt semiColonIndex = 0;
       
   425     do
       
   426     {
       
   427         remainder.Set(remainder.Mid(semiColonIndex + 1));
       
   428 
       
   429         TInt equalsIndex = remainder.Locate(KCharEquals);
       
   430         if (equalsIndex == KErrNotFound)
       
   431         {
       
   432             parameters.Close();
       
   433             return KErrArgument;
       
   434         }
       
   435 
       
   436         TPtrC16 paramName(remainder.Left(equalsIndex));
       
   437 
       
   438         TIdentityRelation<TPtrC16> relation(&TUri::MatchParamNamePtr);
       
   439         TInt nameIndex = parameters.Find(paramName, relation);
       
   440 
       
   441         TInt error = KErrNone;
       
   442         if (nameIndex == KErrNotFound)
       
   443         {
       
   444             error = parameters.Append(paramName);
       
   445         }
       
   446         else if (nameIndex >= 0)
       
   447         {
       
   448             error = KErrAlreadyExists;
       
   449         }
       
   450         else
       
   451         {
       
   452             error = nameIndex;
       
   453         }
       
   454 
       
   455         if (error != KErrNone)
       
   456         {
       
   457             parameters.Close();
       
   458             return error;
       
   459         }
       
   460         semiColonIndex = remainder.Locate(KCharSemiColon);
       
   461     }
       
   462     while (semiColonIndex != KErrNotFound);
       
   463 
       
   464     parameters.Close();
       
   465     return KErrNone;
       
   466 }
       
   467 
       
   468 
       
   469 /**
       
   470 Utility method for use with RArray::Find().
       
   471 */
       
   472 TBool TUri::MatchParamNamePtr(const TPtrC16& aName1, const TPtrC16& aName2)
       
   473 {
       
   474     return (aName1.CompareF(aName2) == 0);
       
   475 }