Example #1
0
void
parseTcpSocketAddress(const StaticString &address, string &host, unsigned short &port) {
	if (getSocketAddressType(address) != SAT_TCP) {
		throw ArgumentException("Not a valid TCP socket address");
	}

	StaticString hostAndPort(address.data() + sizeof("tcp://") - 1,
		address.size() - sizeof("tcp://") + 1);
	if (hostAndPort.empty()) {
		throw ArgumentException("Not a valid TCP socket address");
	}

	if (hostAndPort[0] == '[') {
		// IPv6 address, e.g.:
		// [::1]:3000
		const char *hostEnd = (const char *) memchr(hostAndPort.data(), ']',
			hostAndPort.size());
		if (hostEnd == NULL || hostAndPort.size() <= string::size_type(hostEnd - hostAndPort.data()) + 3) {
			throw ArgumentException("Not a valid TCP socket address");
		}

		const char *sep = hostEnd + 1;
		host.assign(hostAndPort.data() + 1, hostEnd - hostAndPort.data() - 1);
		port = stringToUint(StaticString(
			sep + 1,
			hostAndPort.data() + hostAndPort.size() - sep - 1
		));

	} else {
		// IPv4 address, e.g.:
		// 127.0.0.1:3000
		const char *sep = (const char *) memchr(hostAndPort.data(), ':', hostAndPort.size());
		if (sep == NULL || hostAndPort.size() <= string::size_type(sep - hostAndPort.data()) + 2) {
			throw ArgumentException("Not a valid TCP socket address");
		}

		host.assign(hostAndPort.data(), sep - hostAndPort.data());
		port = stringToUint(StaticString(
			sep + 1,
			hostAndPort.data() + hostAndPort.size() - sep - 1
		));
	}
}
Example #2
0
void Url::parseString(const char* urlString, UtlBoolean isAddrSpec)
{
   // If isAddrSpec:
   //                userinfo@hostport;uriParameters?headerParameters
   // If !isAddrSpec:
   //    DisplayName<userinfo@hostport;urlParameters?headerParameters>;fieldParameters

#  ifdef TIME_PARSE
   OsTimeLog timeLog;
   LOG_TIME("start    ");
#  endif

   // Try to catch when a name-addr is passed but we are expecting an
   // addr-spec -- many name-addr's start with '<' or '"'.
   if (isAddrSpec && (urlString[0] == '<' || urlString[0] == '"'))
   {
      OsSysLog::add(FAC_SIP, PRI_ERR,
                    "Url::parseString Invalid addr-spec found (probably name-addr format): '%s'",
                    urlString);
   }

   int workingOffset = 0; // begin at the beginning...
   
   size_t afterAngleBrackets = UTL_NOT_FOUND;
   
   if (isAddrSpec)
   {
      mAngleBracketsIncluded = FALSE; 
   }
   else // ! addr-spec
   {
      // Is there a display name on the front?
      mDisplayName.remove(0);
      LOG_TIME("display   <");
      RegEx displayName(DisplayName);
      if (displayName.SearchAt(urlString, workingOffset))
      {
         LOG_TIME("display   > ");
         switch (displayName.Matches() /* number of substrings that matched */)
         {
         case 2: // matched unquoted sequence of tokens
            displayName.MatchString(&mDisplayName, 1);
            break;
            
         case 3: // matched a double quoted string
            // see performance note on DisplayName
            mDisplayName.append("\"");
            displayName.MatchString(&mDisplayName, 2);
            mDisplayName.append("\"");
            break;

         default:
            assert(false);
         }

         // does not include whitespace or the '<'
         workingOffset = displayName.AfterMatch(0);
      }

      // Are there angle brackets around the URI?
      LOG_TIME("angles   < ");
      RegEx angleBrackets(AngleBrackets);
      if (angleBrackets.SearchAt(urlString, workingOffset))
      {
         LOG_TIME("angles   > ");
         // yes, there are angle brackets
         workingOffset = angleBrackets.MatchStart(1); // inside the angle brackets
         afterAngleBrackets = angleBrackets.AfterMatch(0); // following the '>'
         
         /*
          * Note: We do not set mAngleBracketsIncluded just because we saw them
          *       That is only used for explicit control from the outside.
          *       The local knowledge of whether or not there are angle brackets
          *       is whether or not afterAngleBrackets == UTL_NOT_FOUND
          */
      }
   }

      /*
       * AMBIGUITY - there is a potential ambiguity when parsing real URLs.
       *
       * Consider the url 'foo:333' - it could be:
       *       scheme 'foo' host '333' ('333' is a valid local host name - bad idea, but legal)
       *   or  host   'foo' port '333' (and scheme 'sip' is implied)
       *
       * Now make it worse by using 'sips' as a hostname:
       *   'sips:333'     
       *       scheme 'sips' host '333'
       *   or  host   'sips' port '333' (and scheme 'sip' is implied)
       *
       * We resolve the first case by treating anything left of the colon as a scheme if
       * it is one of the supported schemes.  Otherwise, we set the scheme to the
       * default (sip) and go on so that it will be parsed as a hostname.  This does not
       * do the right thing for the (scheme 'sips' host '333') case, but they get what
       * they deserve.
       */
   
   // Parse the scheme (aka url type)
   LOG_TIME("scheme   < ");
   RegEx supportedScheme(SupportedScheme);
   if (   (supportedScheme.SearchAt(urlString,workingOffset))
       && (supportedScheme.MatchStart(0) == workingOffset)
       )
      {
      LOG_TIME("scheme   > ");
      // the scheme name matches one of the supported schemes
      mScheme = static_cast<Scheme>(supportedScheme.Matches()-1);
      workingOffset = supportedScheme.AfterMatch(0); // past the ':'
   }
   else
   {
      /*
       * It did not match one of the supported scheme names
       * so proceed on the assumption that it's a host and "sip:" is implied
       * Leave the workingOffset where it is (before the token).
       * The code below, through the parsing of host and port
       * treats this as an implicit 'sip:' url; if it parses ok
       * up to that point, it resets the scheme to SipsUrlScheme
       */
      mScheme = UnknownUrlScheme;
   }


   // skip over any '//' following the scheme for the ones we know use that
   switch (mScheme)
   {
   case FileUrlScheme:
   case FtpUrlScheme:
   case HttpUrlScheme:
   case HttpsUrlScheme:
   case RtspUrlScheme:
      if (0==strncmp("//", urlString+workingOffset, 2))
      {
         workingOffset += 2;
      }
      break;

   case UnknownUrlScheme:
   case SipUrlScheme:
   case SipsUrlScheme:
   case MailtoUrlScheme:
   default:
      break;
   }
   
   if (FileUrlScheme != mScheme) // no user part in file urls
   {
      // Parse the username and password
      LOG_TIME("userpass   < ");
      RegEx usernameAndPassword(UsernameAndPassword);
      if (   (usernameAndPassword.SearchAt(urlString, workingOffset))
          && usernameAndPassword.MatchStart(0) == workingOffset 
          )
      {
         LOG_TIME("userpass   > ");
         usernameAndPassword.MatchString(&mUserId, 1);
         usernameAndPassword.MatchString(&mPassword, 2);
         workingOffset = usernameAndPassword.AfterMatch(0);
      }
      else
      {
         // username and password are optional, so not finding them is ok
         // leave workingOffset where it is
      }
   }

   // Parse the hostname and port
   LOG_TIME("hostport   < ");
   RegEx hostAndPort(HostAndPort);
   if (   (hostAndPort.SearchAt(urlString,workingOffset))
       && (hostAndPort.MatchStart(0) == workingOffset)
       )
   {
      LOG_TIME("hostport   > ");
      hostAndPort.MatchString(&mHostAddress,1);
      UtlString portStr;
      if (hostAndPort.MatchString(&portStr,2))
      {
         mHostPort = atoi(portStr.data());
      }

      workingOffset = hostAndPort.AfterMatch(0);

      if (UnknownUrlScheme == mScheme)
      {
         /*
          * Resolve AMBIGUITY
          *   Since we were able to parse this as a host and port, it is now safe to
          *   set the scheme to the implied 'sip:'.
          */
         mScheme = SipUrlScheme;
      }
   }
   else
   {
      if (FileUrlScheme != mScheme) // no host is ok in a file URL
      {
         /*
          * This is not a file URL, so not having a recognized host name is invalid.
          *
          * Since we may have been called from a constructor, there is no way to
          * return an error, but at this point we know this is bad, so instead
          * we just log an error and set the scheme to the unknown url type and
          * clear any components that might have been set.
          */
         OsSysLog::add(FAC_SIP, PRI_ERR,
                       "Url::parseString no valid host found at char %d in '%s', "
                       "isAddrSpec = %d",
                       workingOffset, urlString, isAddrSpec
                       );
         mScheme = UnknownUrlScheme;
         mDisplayName.remove(0);
         mUserId.remove(0);
         mPassword.remove(0);
      }
   }
   
   // Next is a path if http, https, or ftp,
   //      OR url parameters if sip or sips.
   // There can be no Url parameters for http, https, or ftp
   //    because semicolon is a valid part of the path value
   switch ( mScheme )
   {
   case FileUrlScheme:
   case FtpUrlScheme:
   case HttpUrlScheme:
   case HttpsUrlScheme:
   case RtspUrlScheme:
   {
      // this is an http, https, or ftp URL, so get the path
      LOG_TIME("path   < ");
      RegEx urlPath(UrlPath);
      if (   (urlPath.SearchAt(urlString, workingOffset))
          && (urlPath.MatchStart(0) == workingOffset)
          )
      {
         LOG_TIME("path   > ");
         urlPath.MatchString(&mPath,1);
         workingOffset = urlPath.AfterMatch(1);
      }
   }
   break;

   case SipUrlScheme:
   case SipsUrlScheme:
   {
      // it may have url parameters of the form ";" param "=" value ...
      //                if it meets the right conditions:
      if (   isAddrSpec                          // in addr-spec, any param is a url param
          || afterAngleBrackets != UTL_NOT_FOUND // inside angle brackets there may be a url param
          ) 
      {
         LOG_TIME("urlparm   < ");
         RegEx urlParams(UrlParams);
         if (   (urlParams.SearchAt(urlString, workingOffset))
             && (urlParams.MatchStart(0) == workingOffset)
             )
         {
            LOG_TIME("urlparm   > ");
            urlParams.MatchString(&mRawUrlParameters, 1);
            workingOffset = urlParams.AfterMatch(1);

            // actual parsing of the parameters is in parseUrlParameters
            // so that it only happens if someone asks for them.
         }
      }
   }
   break;
   
   case MailtoUrlScheme:
   default:
      // no path component
      break;
   }

   if (UnknownUrlScheme != mScheme)
   {
   // Parse any header or query parameters
      LOG_TIME("hdrparm   < ");
   RegEx headerOrQueryParams(HeaderOrQueryParams);
   if(   (headerOrQueryParams.SearchAt(urlString, workingOffset))
      && (headerOrQueryParams.MatchStart(0) == workingOffset)
      )
   {
         LOG_TIME("hdrparm   > ");
      headerOrQueryParams.MatchString(&mRawHeaderOrQueryParameters, 1);
      workingOffset = headerOrQueryParams.AfterMatch(0);
            
      // actual parsing of the parameters is in parseHeaderOrQueryParameters
      // so that it only happens if someone asks for them.
   }

   // Parse the field parameters
   if (!isAddrSpec) // can't have field parameters in an addrspec
   {
      if (afterAngleBrackets != UTL_NOT_FOUND)
      {
         workingOffset = afterAngleBrackets;
      }

         LOG_TIME("fldparm   < ");
         RegEx fieldParameters(FieldParams);
      if (   (fieldParameters.SearchAt(urlString, workingOffset))
          && (fieldParameters.MatchStart(0) == workingOffset)
          )
      {
            LOG_TIME("fldparm   > ");
         fieldParameters.MatchString(&mRawFieldParameters, 1);

         // actual parsing of the parameters is in parseFieldParameters
         // so that it only happens if someone asks for them.
      }
   }
}
#  ifdef TIME_PARSE
     UtlString timeDump;
   timeLog.getLogString(timeDump);
   printf("\n%s\n", timeDump.data());
#  endif
}
Example #3
0
 std::string ConnectionSettings::getFullAddress() const
 {
     return hostAndPort().toString();
 }