Repository: aws/aws-cli

Issue:
Provide better error message for invalid endpoint urls
The error message could provide more context about what exactly went wrong with the request.  For example:

```
$ aws s3api list-buckets --endpoint-url example.com

Invalid URL u'/': No schema supplied
```

A better error message would be something like:

```
$ aws s3api list-buckets --endpoint-url example.com

Bad value for --endpoint-url "example.com": scheme is missing.  Must be of the form http://<hostname>/ or https://<hostname>/
```



Discussion:

Resolving patch:
diff --git a/awscli/compat.py b/awscli/compat.py
--- a/awscli/compat.py
+++ b/awscli/compat.py
@@ -15,6 +15,7 @@
 
 if six.PY3:
     import locale
+    import urllib.parse as urlparse
 
     def get_stdout_text_writer():
         return sys.stdout
@@ -38,6 +39,7 @@ def compat_open(filename, mode='r', encoding=None):
     import codecs
     import locale
     import io
+    import urlparse
 
     def get_stdout_text_writer():
         # In python3, all the sys.stdout/sys.stderr streams are in text
diff --git a/awscli/customizations/globalargs.py b/awscli/customizations/globalargs.py
--- a/awscli/customizations/globalargs.py
+++ b/awscli/customizations/globalargs.py
@@ -15,6 +15,8 @@
 
 import jmespath
 
+from awscli.compat import urlparse
+
 
 def register_parse_global_args(cli):
     cli.register('top-level-args-parsed', resolve_types)
@@ -26,6 +28,7 @@ def resolve_types(parsed_args, **kwargs):
     # that plugins can also hook into this process.
     _resolve_arg(parsed_args, 'query')
     _resolve_arg(parsed_args, 'verify_ssl')
+    _resolve_arg(parsed_args, 'endpoint_url')
 
 
 def _resolve_arg(parsed_args, name):
@@ -51,6 +54,17 @@ def _resolve_verify_ssl(value):
     return verify
 
 
+def _resolve_endpoint_url(value):
+    parsed = urlparse.urlparse(value)
+    # Our http library requires you specify an endpoint url
+    # that contains a scheme, so we'll verify that up front.
+    if not parsed.scheme:
+        raise ValueError('Bad value for --endpoint-url "%s": scheme is '
+                         'missing.  Must be of the form '
+                         'http://<hostname>/ or https://<hostname>/' % value)
+    return value
+
+
 def no_sign_request(parsed_args, session, **kwargs):
     if not parsed_args.sign_request:
         # In order to make signing disabled for all requests


Test patch:
diff --git a/tests/unit/customizations/test_globalargs.py b/tests/unit/customizations/test_globalargs.py
--- a/tests/unit/customizations/test_globalargs.py
+++ b/tests/unit/customizations/test_globalargs.py
@@ -82,3 +82,15 @@ def test_disable_signing(self):
         service.signature_version = 'v4'
         globalargs.disable_signing(service)
         service.signature_version = None
+
+    def test_invalid_endpoint_url(self):
+        # Invalid jmespath expression.
+        parsed_args = FakeParsedArgs(endpoint_url='missing-scheme.com')
+        with self.assertRaises(ValueError):
+            globalargs.resolve_types(parsed_args)
+
+    def test_valid_endpoint_url(self):
+        parsed_args = FakeParsedArgs(endpoint_url='http://custom-endpoint.com')
+        globalargs.resolve_types(parsed_args)
+        self.assertEqual(parsed_args.endpoint_url,
+                         'http://custom-endpoint.com')