Repository: ericsson/codechecker
Issue: exception is thrown if product name is not specified

(venv)ednikru@md-mtas2:~/work/codechecker$ CodeChecker cmd runs --url http://md-mtas2.tsp.eth.ericsson.se:9996
[WARNING] [11:47] - '/home/ednikru/.codechecker.passwords.json' is readable by users other than you! This poses a risk of leaking sensitive information, such as passwords, session tokens, etc.!
Please 'chmod 0600 /home/ednikru/.codechecker.passwords.json' so only you can access the file.
Connection failed to localhost:80
Traceback (most recent call last):
  File "/home/ednikru/work/codechecker/codechecker_git/codechecker/build/CodeChecker/lib/python2.7/libcodechecker/libclient/authentication_helper.py", line 50, in wrapper
    res = func(*args, **kwargs)
  File "/home/ednikru/work/codechecker/codechecker_git/codechecker/build/CodeChecker/lib/python2.7/gencodechecker/Authentication_v6/codeCheckerAuthentication.py", line 106, in checkAPIVersion
    self.recv_checkAPIVersion()
  File "/home/ednikru/work/codechecker/codechecker_git/codechecker/build/CodeChecker/lib/python2.7/gencodechecker/Authentication_v6/codeCheckerAuthentication.py", line 116, in recv_checkAPIVersion
    (fname, mtype, rseqid) = self._iprot.readMessageBegin()
  File "/home/ednikru/work/codechecker/codechecker_git/codechecker/venv/local/lib/python2.7/site-packages/thrift/protocol/TJSONProtocol.py", line 317, in readMessageBegin
    self.readJSONArrayStart()
  File "/home/ednikru/work/codechecker/codechecker_git/codechecker/venv/local/lib/python2.7/site-packages/thrift/protocol/TJSONProtocol.py", line 305, in readJSONArrayStart
    self.readJSONSyntaxChar(LBRACKET)
  File "/home/ednikru/work/codechecker/codechecker_git/codechecker/venv/local/lib/python2.7/site-packages/thrift/protocol/TJSONProtocol.py", line 213, in readJSONSyntaxChar
    "Unexpected character: %s" % current)
TProtocolException: Unexpected character: <

Changed files:
libcodechecker/util.py, tests/unit/test_url_understanding.py, libcodechecker/libclient/client.py

diff --git a/libcodechecker/libclient/client.py b/libcodechecker/libclient/client.py
index 6fc29358..fd9a48b4 100644
--- a/libcodechecker/libclient/client.py
+++ b/libcodechecker/libclient/client.py
@@ -73,7 +73,8 @@ def setup_auth_client_from_url(product_url, session_token=None):
         protocol, host, port, _ = split_product_url(product_url)
         return setup_auth_client(protocol, host, port, session_token)
     except:
-        LOG.error("Malformed product URL was provided.")
+        LOG.error("Malformed product URL was provided. A valid product URL "
+                  "looks like this: 'http://my.server.com:80/ProductName'.")
         sys.exit(2)  # 2 for argument error.
 
 
@@ -235,7 +236,8 @@ def setup_client(product_url):
     try:
         protocol, host, port, product_name = split_product_url(product_url)
     except:
-        LOG.error("Malformed product URL was provided.")
+        LOG.error("Malformed product URL was provided. A valid product URL "
+                  "looks like this: 'http://my.server.com:80/ProductName'.")
         sys.exit(2)  # 2 for argument error.
 
     _, session_token = setup_auth_client(protocol, host, port)
diff --git a/libcodechecker/util.py b/libcodechecker/util.py
index 5e3f6bfd..bcbbf99a 100644
--- a/libcodechecker/util.py
+++ b/libcodechecker/util.py
@@ -249,8 +249,7 @@ def split_server_url(url):
             raise ValueError("The server's address is not in a valid "
                              "'host:port' format!")
     except:
-        LOG.error("The specified server URL is invalid.")
-        raise
+        raise ValueError("The specified server URL is invalid.")
 
     LOG.debug("Result: With '{0}' on server '{1}:{2}'"
               .format(protocol, host, port))
@@ -290,11 +289,16 @@ def split_product_url(url):
 
         if len(parts) == 1:
             # If only one word is given in the URL, consider it as product
-            # name, but then it cannot begin with a number.
+            # name, but then it must appear to be a valid product name.
+
+            # "Only one word" URLs can be just simple host names too:
+            # http://codechecker.example.com:1234 should NOT be understood as
+            # the "codechecker.example.com:1234" product on "localhost:8001".
             product_name = parts[0]
-            if product_name[0].isdigit():
-                raise ValueError("Product name was given in URL, but it "
-                                 "cannot begin with a number!")
+            if product_name[0].isdigit() or '.' in product_name \\
+                    or ':' in product_name:
+                raise ValueError("The given product URL is invalid. Please "
+                                 "specify a full product URL.")
         elif len(parts) == 2:
             # URL is at least something/product-name.
             product_name = parts[1]
@@ -312,8 +316,7 @@ def split_product_url(url):
         else:
             raise ValueError("Product URL can not contain extra '/' chars.")
     except:
-        LOG.error("The specified product URL is invalid.")
-        raise
+        raise ValueError("The specified product URL is invalid.")
 
     LOG.debug("Result: With '{0}' on server '{1}:{2}', product '{3}'"
               .format(protocol, host, port, product_name))
diff --git a/tests/unit/test_url_understanding.py b/tests/unit/test_url_understanding.py
index 24500c7e..7b330fd2 100644
--- a/tests/unit/test_url_understanding.py
+++ b/tests/unit/test_url_understanding.py
@@ -107,6 +107,11 @@ class product_urlTest(unittest.TestCase):
         with self.assertRaises(ValueError):
             split_product_url("codechecker://codecheker.com/Baz")
 
+        with self.assertRaises(ValueError):
+            # Make sure we don't understand "https://foobar.baz:1234" as
+            # HTTPS, localhost, 443, and "foobar.baz:1234" product name.
+            split_product_url("https://foobar.bar:1234")
+
     def testFullServerURL(self):
         """
         Whole server URL understanding.