diff --git a/Tests/T_Utils.cpp b/Tests/T_Utils.cpp index 44acdfa..9b11a55 100644 --- a/Tests/T_Utils.cpp +++ b/Tests/T_Utils.cpp @@ -466,6 +466,34 @@ int main() Result = Utils::StringToInt("", &Value); test(Result == KErrCorrupt); + /* Test #16: Utils::splitHost() tests */ + + Test.Next("Utils::splitHost() tests"); + + std::string Server; + int PathOffset; + unsigned short Port; + + test(Utils::splitHost("www.example.com", Server, Port, 80) == KErrNone); + test(Server == "www.example.com"); + test(Port == 80); + + test(Utils::splitHost("www.example.com:8080", Server, Port, 80) == KErrNone); + test(Server == "www.example.com"); + test(Port == 8080); + + test(Utils::splitHost("", Server, Port, 80) == KErrNotFound); + + PathOffset = Utils::splitHost("www.example.com/path", Server, Port, 80); + test(Server == "www.example.com"); + test(Port == 80); + test(PathOffset == 16); + + PathOffset = Utils::splitHost("www.example.com:8080/path", Server, Port, 80); + test(Server == "www.example.com"); + test(Port == 8080); + test(PathOffset == 21); + /* Clean up after ourselves */ Result = g_oFileUtils.deleteFile("TimeFile.txt"); diff --git a/Utils.cpp b/Utils.cpp index f078445..4de1785 100644 --- a/Utils.cpp +++ b/Utils.cpp @@ -3083,56 +3083,77 @@ TInt Utils::setProtection(const char *a_pccFileName, TUint a_uiAttributes) /** * Split a host into its hostname and port components. - * This function parses a string in the format hostname:port and extracts the two components into a string - * and an unsigned short variable respectively. The port is optional and if not present, a default value will - * be used. It is considered an error for the hostname to not be present. + * This function parses a string in the format hostname:port/path and extracts the first two components into a string + * and an unsigned short variable respectively. The port is optional and if not present, a default value will be used. + * It is considered an error for the hostname to not be present. + * + * If a path follows the hostname and port, it will be discarded, but its offset will be returned to indicate its + * presence. * * @date Friday 10-May-2024 6:03 am, Code HQ Tokyo Tsukuda * @param a_pccHost The host to parse * @param a_roServer The string into which to place the extracted hostname * @param a_rusPort The unsigned short into which to place the extracted port * @param a_usDefaultPort The port to be used if no port is specified - * @return KErrNone if successful + * @return KErrNone or the positive path offset if successful * @return KErrNotFound if the hostname was not present */ -int Utils::splitHost(const char *a_pccHost, std::string &a_roServer, unsigned short &a_rusPort, unsigned short a_usDefaultPort) +int Utils::splitHost(const char *a_host, std::string &a_server, unsigned short &a_port, unsigned short a_defaultPort) { - int serverLength, portLength, port, retVal; - TLex lex(a_pccHost, static_cast(strlen(a_pccHost))); + int hostLength, pathLength, serverLength, portLength, port, retVal; + TLex hostLex(a_host, static_cast(strlen(a_host))); - retVal = KErrNone; + retVal = KErrNotFound; - /* Extract the server name and port number from the host passed in and, if a port was specified, */ - /* convert it and check its validity */ - lex.SetWhitespace(":"); + /* Extract the server name and port number from the complete URL passed in */ + hostLex.SetWhitespace("/"); - const char *serverString = lex.NextToken(&serverLength); - const char *portString = lex.NextToken(&portLength); + const char *hostString = hostLex.NextToken(&hostLength); - if (serverString != nullptr) + if (hostString != nullptr) { - a_roServer = std::string(serverString, serverLength); + std::string host(hostString, hostLength); + TLex lex(host.c_str(), hostLength); + + /* Extract the server name and port number from the host passed in and, if a port was specified, */ + /* convert it and check its validity */ + lex.SetWhitespace(":"); - /* The port string is optional so only parse if it is there, and use the default value if it is missing */ - /* or invalid */ - a_rusPort = a_usDefaultPort; + const char *serverString = lex.NextToken(&serverLength); + const char *portString = lex.NextToken(&portLength); - if (portString) + if (serverString != nullptr) { - if (Utils::StringToInt(portString, &port) == KErrNone) - { - a_rusPort = static_cast(port); - } - else + retVal = KErrNone; + + a_server = std::string(serverString, serverLength); + + /* The port string is optional so only parse if it is there, and use the default value if it is missing */ + /* or invalid */ + a_port = a_defaultPort; + + if (portString) { - Utils::info("Utils::splitURL() => Specified port \"%s\" is invalid, using default port %d", portString, a_rusPort); + if (Utils::StringToInt(portString, &port) == KErrNone) + { + a_port = static_cast(port); + } + else + { + Utils::info("Utils::splitURL() => Specified port \"%s\" is invalid, using default port %d", portString, a_port); + } } } - } - else - { - retVal = KErrNotFound; + + /* If a path follows the server name and port, it will be discarded, but return to the client the fact that */ + /* it is there, by returning its offset in the URL */ + const char *pathString = hostLex.NextToken(&pathLength); + + if (pathString != nullptr) + { + retVal = static_cast(pathString - a_host); + } } return retVal; diff --git a/Utils.h b/Utils.h index f498065..8eb442e 100644 --- a/Utils.h +++ b/Utils.h @@ -109,7 +109,7 @@ class Utils static TInt setProtection(const char *a_pccFileName, TUint a_uiAttributes); - static int splitHost(const char *a_pccHost, std::string &a_roServer, unsigned short &a_rusPort, unsigned short a_usDefaultPort = 80); + static int splitHost(const char *a_host, std::string &a_server, unsigned short &a_port, unsigned short a_defaultPort = 80); static char *StripDags(char *a_pcLine, TInt *a_piLength);