We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Add trusted hosts / networks to Server mode
Currently (Java) AWS API can only work with Moto from the local network (if it starts with "192.168.X.X") or if the request is coming from the same host as the server, that's very limiting because i want to run Moto on a container in an external network.

Any chance to add trusted networks or hosts via config file or CLI args?

I'd appreciate any info if this had been addressed or i'm using it wrong

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `moto/server.py`
Content:
```
1 from __future__ import unicode_literals
2 
3 import argparse
4 import json
5 import re
6 import sys
7 from threading import Lock
8 
9 import six
10 from flask import Flask
11 from flask.testing import FlaskClient
12 
13 from six.moves.urllib.parse import urlencode
14 from werkzeug.routing import BaseConverter
15 from werkzeug.serving import run_simple
16 
17 from moto.backends import BACKENDS
18 from moto.core.utils import convert_flask_to_httpretty_response
19 
20 
21 HTTP_METHODS = ["GET", "POST", "PUT", "DELETE", "HEAD", "PATCH"]
22 
23 
24 DEFAULT_SERVICE_REGION = ('s3', 'us-east-1')
25 
26 # Map of unsigned calls to service-region as per AWS API docs
27 # https://docs.aws.amazon.com/cognito/latest/developerguide/resource-permissions.html#amazon-cognito-signed-versus-unsigned-apis
28 UNSIGNED_REQUESTS = {
29     'AWSCognitoIdentityService': ('cognito-identity', 'us-east-1'),
30     'AWSCognitoIdentityProviderService': ('cognito-idp', 'us-east-1'),
31 }
32 
33 
34 class DomainDispatcherApplication(object):
35     """
36     Dispatch requests to different applications based on the "Host:" header
37     value. We'll match the host header value with the url_bases of each backend.
38     """
39 
40     def __init__(self, create_app, service=None):
41         self.create_app = create_app
42         self.lock = Lock()
43         self.app_instances = {}
44         self.service = service
45 
46     def get_backend_for_host(self, host):
47         if host == 'moto_api':
48             return host
49 
50         if self.service:
51             return self.service
52 
53         if host in BACKENDS:
54             return host
55 
56         for backend_name, backend in BACKENDS.items():
57             for url_base in list(backend.values())[0].url_bases:
58                 if re.match(url_base, 'http://%s' % host):
59                     return backend_name
60 
61         raise RuntimeError('Invalid host: "%s"' % host)
62 
63     def infer_service_region(self, environ):
64         auth = environ.get('HTTP_AUTHORIZATION')
65         if auth:
66             # Signed request
67             # Parse auth header to find service assuming a SigV4 request
68             # https://docs.aws.amazon.com/general/latest/gr/sigv4-signed-request-examples.html
69             # ['Credential=sdffdsa', '20170220', 'us-east-1', 'sns', 'aws4_request']
70             try:
71                 credential_scope = auth.split(",")[0].split()[1]
72                 _, _, region, service, _ = credential_scope.split("/")
73                 return service, region
74             except ValueError:
75                 # Signature format does not match, this is exceptional and we can't
76                 # infer a service-region. A reduced set of services still use
77                 # the deprecated SigV2, ergo prefer S3 as most likely default.
78                 # https://docs.aws.amazon.com/general/latest/gr/signature-version-2.html
79                 return DEFAULT_SERVICE_REGION
80         else:
81             # Unsigned request
82             target = environ.get('HTTP_X_AMZ_TARGET')
83             if target:
84                 service, _ = target.split('.', 1)
85                 return UNSIGNED_REQUESTS.get(service, DEFAULT_SERVICE_REGION)
86             # S3 is the last resort when the target is also unknown
87             return DEFAULT_SERVICE_REGION
88 
89     def get_application(self, environ):
90         path_info = environ.get('PATH_INFO', '')
91 
92         # The URL path might contain non-ASCII text, for instance unicode S3 bucket names
93         if six.PY2 and isinstance(path_info, str):
94             path_info = six.u(path_info)
95         if six.PY3 and isinstance(path_info, six.binary_type):
96             path_info = path_info.decode('utf-8')
97 
98         if path_info.startswith("/moto-api") or path_info == "/favicon.ico":
99             host = "moto_api"
100         elif path_info.startswith("/latest/meta-data/"):
101             host = "instance_metadata"
102         else:
103             host = environ['HTTP_HOST'].split(':')[0]
104         if host in {'localhost', 'motoserver'} or host.startswith("192.168."):
105             service, region = self.infer_service_region(environ)
106             if service == 'dynamodb':
107                 if environ['HTTP_X_AMZ_TARGET'].startswith('DynamoDBStreams'):
108                     host = 'dynamodbstreams'
109                 else:
110                     dynamo_api_version = environ['HTTP_X_AMZ_TARGET'].split("_")[1].split(".")[0]
111                     # If Newer API version, use dynamodb2
112                     if dynamo_api_version > "20111205":
113                         host = "dynamodb2"
114             else:
115                 host = "{service}.{region}.amazonaws.com".format(
116                     service=service, region=region)
117 
118         with self.lock:
119             backend = self.get_backend_for_host(host)
120             app = self.app_instances.get(backend, None)
121             if app is None:
122                 app = self.create_app(backend)
123                 self.app_instances[backend] = app
124             return app
125 
126     def __call__(self, environ, start_response):
127         backend_app = self.get_application(environ)
128         return backend_app(environ, start_response)
129 
130 
131 class RegexConverter(BaseConverter):
132     # http://werkzeug.pocoo.org/docs/routing/#custom-converters
133 
134     def __init__(self, url_map, *items):
135         super(RegexConverter, self).__init__(url_map)
136         self.regex = items[0]
137 
138 
139 class AWSTestHelper(FlaskClient):
140 
141     def action_data(self, action_name, **kwargs):
142         """
143         Method calls resource with action_name and returns data of response.
144         """
145         opts = {"Action": action_name}
146         opts.update(kwargs)
147         res = self.get("/?{0}".format(urlencode(opts)),
148                        headers={"Host": "{0}.us-east-1.amazonaws.com".format(self.application.service)})
149         return res.data.decode("utf-8")
150 
151     def action_json(self, action_name, **kwargs):
152         """
153         Method calls resource with action_name and returns object obtained via
154         deserialization of output.
155         """
156         return json.loads(self.action_data(action_name, **kwargs))
157 
158 
159 def create_backend_app(service):
160     from werkzeug.routing import Map
161 
162     # Create the backend_app
163     backend_app = Flask(__name__)
164     backend_app.debug = True
165     backend_app.service = service
166 
167     # Reset view functions to reset the app
168     backend_app.view_functions = {}
169     backend_app.url_map = Map()
170     backend_app.url_map.converters['regex'] = RegexConverter
171     backend = list(BACKENDS[service].values())[0]
172     for url_path, handler in backend.flask_paths.items():
173         if handler.__name__ == 'dispatch':
174             endpoint = '{0}.dispatch'.format(handler.__self__.__name__)
175         else:
176             endpoint = None
177 
178         original_endpoint = endpoint
179         index = 2
180         while endpoint in backend_app.view_functions:
181             # HACK: Sometimes we map the same view to multiple url_paths. Flask
182             # requries us to have different names.
183             endpoint = original_endpoint + str(index)
184             index += 1
185 
186         backend_app.add_url_rule(
187             url_path,
188             endpoint=endpoint,
189             methods=HTTP_METHODS,
190             view_func=convert_flask_to_httpretty_response(handler),
191             strict_slashes=False,
192         )
193 
194     backend_app.test_client_class = AWSTestHelper
195     return backend_app
196 
197 
198 def main(argv=sys.argv[1:]):
199     parser = argparse.ArgumentParser()
200 
201     # Keep this for backwards compat
202     parser.add_argument(
203         "service",
204         type=str,
205         nargs='?',  # http://stackoverflow.com/a/4480202/731592
206         default=None)
207     parser.add_argument(
208         '-H', '--host', type=str,
209         help='Which host to bind',
210         default='127.0.0.1')
211     parser.add_argument(
212         '-p', '--port', type=int,
213         help='Port number to use for connection',
214         default=5000)
215     parser.add_argument(
216         '-r', '--reload',
217         action='store_true',
218         help='Reload server on a file change',
219         default=False
220     )
221     parser.add_argument(
222         '-s', '--ssl',
223         action='store_true',
224         help='Enable SSL encrypted connection with auto-generated certificate (use https://... URL)',
225         default=False
226     )
227     parser.add_argument(
228         '-c', '--ssl-cert', type=str,
229         help='Path to SSL certificate',
230         default=None)
231     parser.add_argument(
232         '-k', '--ssl-key', type=str,
233         help='Path to SSL private key',
234         default=None)
235 
236     args = parser.parse_args(argv)
237 
238     # Wrap the main application
239     main_app = DomainDispatcherApplication(
240         create_backend_app, service=args.service)
241     main_app.debug = True
242 
243     ssl_context = None
244     if args.ssl_key and args.ssl_cert:
245         ssl_context = (args.ssl_cert, args.ssl_key)
246     elif args.ssl:
247         ssl_context = 'adhoc'
248 
249     run_simple(args.host, args.port, main_app,
250                threaded=True, use_reloader=args.reload,
251                ssl_context=ssl_context)
252 
253 
254 if __name__ == '__main__':
255     main()
256
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/moto/server.py b/moto/server.py
--- a/moto/server.py
+++ b/moto/server.py
@@ -58,9 +58,7 @@
                 if re.match(url_base, 'http://%s' % host):
                     return backend_name
 
-        raise RuntimeError('Invalid host: "%s"' % host)
-
-    def infer_service_region(self, environ):
+    def infer_service_region_host(self, environ):
         auth = environ.get('HTTP_AUTHORIZATION')
         if auth:
             # Signed request
@@ -70,21 +68,35 @@
             try:
                 credential_scope = auth.split(",")[0].split()[1]
                 _, _, region, service, _ = credential_scope.split("/")
-                return service, region
             except ValueError:
                 # Signature format does not match, this is exceptional and we can't
                 # infer a service-region. A reduced set of services still use
                 # the deprecated SigV2, ergo prefer S3 as most likely default.
                 # https://docs.aws.amazon.com/general/latest/gr/signature-version-2.html
-                return DEFAULT_SERVICE_REGION
+                service, region = DEFAULT_SERVICE_REGION
         else:
             # Unsigned request
             target = environ.get('HTTP_X_AMZ_TARGET')
             if target:
                 service, _ = target.split('.', 1)
-                return UNSIGNED_REQUESTS.get(service, DEFAULT_SERVICE_REGION)
-            # S3 is the last resort when the target is also unknown
-            return DEFAULT_SERVICE_REGION
+                service, region = UNSIGNED_REQUESTS.get(service, DEFAULT_SERVICE_REGION)
+            else:
+                # S3 is the last resort when the target is also unknown
+                service, region = DEFAULT_SERVICE_REGION
+
+        if service == 'dynamodb':
+            if environ['HTTP_X_AMZ_TARGET'].startswith('DynamoDBStreams'):
+                host = 'dynamodbstreams'
+            else:
+                dynamo_api_version = environ['HTTP_X_AMZ_TARGET'].split("_")[1].split(".")[0]
+                # If Newer API version, use dynamodb2
+                if dynamo_api_version > "20111205":
+                    host = "dynamodb2"
+        else:
+            host = "{service}.{region}.amazonaws.com".format(
+                service=service, region=region)
+
+        return host
 
     def get_application(self, environ):
         path_info = environ.get('PATH_INFO', '')
@@ -101,22 +113,14 @@
             host = "instance_metadata"
         else:
             host = environ['HTTP_HOST'].split(':')[0]
-        if host in {'localhost', 'motoserver'} or host.startswith("192.168."):
-            service, region = self.infer_service_region(environ)
-            if service == 'dynamodb':
-                if environ['HTTP_X_AMZ_TARGET'].startswith('DynamoDBStreams'):
-                    host = 'dynamodbstreams'
-                else:
-                    dynamo_api_version = environ['HTTP_X_AMZ_TARGET'].split("_")[1].split(".")[0]
-                    # If Newer API version, use dynamodb2
-                    if dynamo_api_version > "20111205":
-                        host = "dynamodb2"
-            else:
-                host = "{service}.{region}.amazonaws.com".format(
-                    service=service, region=region)
 
         with self.lock:
             backend = self.get_backend_for_host(host)
+            if not backend:
+                # No regular backend found; try parsing other headers
+                host = self.infer_service_region_host(environ)
+                backend = self.get_backend_for_host(host)
+
             app = self.app_instances.get(backend, None)
             if app is None:
                 app = self.create_app(backend)

{"golden_diff": "diff --git a/moto/server.py b/moto/server.py\n--- a/moto/server.py\n+++ b/moto/server.py\n@@ -58,9 +58,7 @@\n                 if re.match(url_base, 'http://%s' % host):\n                     return backend_name\n \n-        raise RuntimeError('Invalid host: \"%s\"' % host)\n-\n-    def infer_service_region(self, environ):\n+    def infer_service_region_host(self, environ):\n         auth = environ.get('HTTP_AUTHORIZATION')\n         if auth:\n             # Signed request\n@@ -70,21 +68,35 @@\n             try:\n                 credential_scope = auth.split(\",\")[0].split()[1]\n                 _, _, region, service, _ = credential_scope.split(\"/\")\n-                return service, region\n             except ValueError:\n                 # Signature format does not match, this is exceptional and we can't\n                 # infer a service-region. A reduced set of services still use\n                 # the deprecated SigV2, ergo prefer S3 as most likely default.\n                 # https://docs.aws.amazon.com/general/latest/gr/signature-version-2.html\n-                return DEFAULT_SERVICE_REGION\n+                service, region = DEFAULT_SERVICE_REGION\n         else:\n             # Unsigned request\n             target = environ.get('HTTP_X_AMZ_TARGET')\n             if target:\n                 service, _ = target.split('.', 1)\n-                return UNSIGNED_REQUESTS.get(service, DEFAULT_SERVICE_REGION)\n-            # S3 is the last resort when the target is also unknown\n-            return DEFAULT_SERVICE_REGION\n+                service, region = UNSIGNED_REQUESTS.get(service, DEFAULT_SERVICE_REGION)\n+            else:\n+                # S3 is the last resort when the target is also unknown\n+                service, region = DEFAULT_SERVICE_REGION\n+\n+        if service == 'dynamodb':\n+            if environ['HTTP_X_AMZ_TARGET'].startswith('DynamoDBStreams'):\n+                host = 'dynamodbstreams'\n+            else:\n+                dynamo_api_version = environ['HTTP_X_AMZ_TARGET'].split(\"_\")[1].split(\".\")[0]\n+                # If Newer API version, use dynamodb2\n+                if dynamo_api_version > \"20111205\":\n+                    host = \"dynamodb2\"\n+        else:\n+            host = \"{service}.{region}.amazonaws.com\".format(\n+                service=service, region=region)\n+\n+        return host\n \n     def get_application(self, environ):\n         path_info = environ.get('PATH_INFO', '')\n@@ -101,22 +113,14 @@\n             host = \"instance_metadata\"\n         else:\n             host = environ['HTTP_HOST'].split(':')[0]\n-        if host in {'localhost', 'motoserver'} or host.startswith(\"192.168.\"):\n-            service, region = self.infer_service_region(environ)\n-            if service == 'dynamodb':\n-                if environ['HTTP_X_AMZ_TARGET'].startswith('DynamoDBStreams'):\n-                    host = 'dynamodbstreams'\n-                else:\n-                    dynamo_api_version = environ['HTTP_X_AMZ_TARGET'].split(\"_\")[1].split(\".\")[0]\n-                    # If Newer API version, use dynamodb2\n-                    if dynamo_api_version > \"20111205\":\n-                        host = \"dynamodb2\"\n-            else:\n-                host = \"{service}.{region}.amazonaws.com\".format(\n-                    service=service, region=region)\n \n         with self.lock:\n             backend = self.get_backend_for_host(host)\n+            if not backend:\n+                # No regular backend found; try parsing other headers\n+                host = self.infer_service_region_host(environ)\n+                backend = self.get_backend_for_host(host)\n+\n             app = self.app_instances.get(backend, None)\n             if app is None:\n                 app = self.create_app(backend)\n", "issue": "Add trusted hosts / networks to Server mode\nCurrently (Java) AWS API can only work with Moto from the local network (if it starts with \"192.168.X.X\") or if the request is coming from the same host as the server, that's very limiting because i want to run Moto on a container in an external network.\r\n\r\nAny chance to add trusted networks or hosts via config file or CLI args?\r\n\r\nI'd appreciate any info if this had been addressed or i'm using it wrong\n", "before_files": [{"content": "from __future__ import unicode_literals\n\nimport argparse\nimport json\nimport re\nimport sys\nfrom threading import Lock\n\nimport six\nfrom flask import Flask\nfrom flask.testing import FlaskClient\n\nfrom six.moves.urllib.parse import urlencode\nfrom werkzeug.routing import BaseConverter\nfrom werkzeug.serving import run_simple\n\nfrom moto.backends import BACKENDS\nfrom moto.core.utils import convert_flask_to_httpretty_response\n\n\nHTTP_METHODS = [\"GET\", \"POST\", \"PUT\", \"DELETE\", \"HEAD\", \"PATCH\"]\n\n\nDEFAULT_SERVICE_REGION = ('s3', 'us-east-1')\n\n# Map of unsigned calls to service-region as per AWS API docs\n# https://docs.aws.amazon.com/cognito/latest/developerguide/resource-permissions.html#amazon-cognito-signed-versus-unsigned-apis\nUNSIGNED_REQUESTS = {\n    'AWSCognitoIdentityService': ('cognito-identity', 'us-east-1'),\n    'AWSCognitoIdentityProviderService': ('cognito-idp', 'us-east-1'),\n}\n\n\nclass DomainDispatcherApplication(object):\n    \"\"\"\n    Dispatch requests to different applications based on the \"Host:\" header\n    value. We'll match the host header value with the url_bases of each backend.\n    \"\"\"\n\n    def __init__(self, create_app, service=None):\n        self.create_app = create_app\n        self.lock = Lock()\n        self.app_instances = {}\n        self.service = service\n\n    def get_backend_for_host(self, host):\n        if host == 'moto_api':\n            return host\n\n        if self.service:\n            return self.service\n\n        if host in BACKENDS:\n            return host\n\n        for backend_name, backend in BACKENDS.items():\n            for url_base in list(backend.values())[0].url_bases:\n                if re.match(url_base, 'http://%s' % host):\n                    return backend_name\n\n        raise RuntimeError('Invalid host: \"%s\"' % host)\n\n    def infer_service_region(self, environ):\n        auth = environ.get('HTTP_AUTHORIZATION')\n        if auth:\n            # Signed request\n            # Parse auth header to find service assuming a SigV4 request\n            # https://docs.aws.amazon.com/general/latest/gr/sigv4-signed-request-examples.html\n            # ['Credential=sdffdsa', '20170220', 'us-east-1', 'sns', 'aws4_request']\n            try:\n                credential_scope = auth.split(\",\")[0].split()[1]\n                _, _, region, service, _ = credential_scope.split(\"/\")\n                return service, region\n            except ValueError:\n                # Signature format does not match, this is exceptional and we can't\n                # infer a service-region. A reduced set of services still use\n                # the deprecated SigV2, ergo prefer S3 as most likely default.\n                # https://docs.aws.amazon.com/general/latest/gr/signature-version-2.html\n                return DEFAULT_SERVICE_REGION\n        else:\n            # Unsigned request\n            target = environ.get('HTTP_X_AMZ_TARGET')\n            if target:\n                service, _ = target.split('.', 1)\n                return UNSIGNED_REQUESTS.get(service, DEFAULT_SERVICE_REGION)\n            # S3 is the last resort when the target is also unknown\n            return DEFAULT_SERVICE_REGION\n\n    def get_application(self, environ):\n        path_info = environ.get('PATH_INFO', '')\n\n        # The URL path might contain non-ASCII text, for instance unicode S3 bucket names\n        if six.PY2 and isinstance(path_info, str):\n            path_info = six.u(path_info)\n        if six.PY3 and isinstance(path_info, six.binary_type):\n            path_info = path_info.decode('utf-8')\n\n        if path_info.startswith(\"/moto-api\") or path_info == \"/favicon.ico\":\n            host = \"moto_api\"\n        elif path_info.startswith(\"/latest/meta-data/\"):\n            host = \"instance_metadata\"\n        else:\n            host = environ['HTTP_HOST'].split(':')[0]\n        if host in {'localhost', 'motoserver'} or host.startswith(\"192.168.\"):\n            service, region = self.infer_service_region(environ)\n            if service == 'dynamodb':\n                if environ['HTTP_X_AMZ_TARGET'].startswith('DynamoDBStreams'):\n                    host = 'dynamodbstreams'\n                else:\n                    dynamo_api_version = environ['HTTP_X_AMZ_TARGET'].split(\"_\")[1].split(\".\")[0]\n                    # If Newer API version, use dynamodb2\n                    if dynamo_api_version > \"20111205\":\n                        host = \"dynamodb2\"\n            else:\n                host = \"{service}.{region}.amazonaws.com\".format(\n                    service=service, region=region)\n\n        with self.lock:\n            backend = self.get_backend_for_host(host)\n            app = self.app_instances.get(backend, None)\n            if app is None:\n                app = self.create_app(backend)\n                self.app_instances[backend] = app\n            return app\n\n    def __call__(self, environ, start_response):\n        backend_app = self.get_application(environ)\n        return backend_app(environ, start_response)\n\n\nclass RegexConverter(BaseConverter):\n    # http://werkzeug.pocoo.org/docs/routing/#custom-converters\n\n    def __init__(self, url_map, *items):\n        super(RegexConverter, self).__init__(url_map)\n        self.regex = items[0]\n\n\nclass AWSTestHelper(FlaskClient):\n\n    def action_data(self, action_name, **kwargs):\n        \"\"\"\n        Method calls resource with action_name and returns data of response.\n        \"\"\"\n        opts = {\"Action\": action_name}\n        opts.update(kwargs)\n        res = self.get(\"/?{0}\".format(urlencode(opts)),\n                       headers={\"Host\": \"{0}.us-east-1.amazonaws.com\".format(self.application.service)})\n        return res.data.decode(\"utf-8\")\n\n    def action_json(self, action_name, **kwargs):\n        \"\"\"\n        Method calls resource with action_name and returns object obtained via\n        deserialization of output.\n        \"\"\"\n        return json.loads(self.action_data(action_name, **kwargs))\n\n\ndef create_backend_app(service):\n    from werkzeug.routing import Map\n\n    # Create the backend_app\n    backend_app = Flask(__name__)\n    backend_app.debug = True\n    backend_app.service = service\n\n    # Reset view functions to reset the app\n    backend_app.view_functions = {}\n    backend_app.url_map = Map()\n    backend_app.url_map.converters['regex'] = RegexConverter\n    backend = list(BACKENDS[service].values())[0]\n    for url_path, handler in backend.flask_paths.items():\n        if handler.__name__ == 'dispatch':\n            endpoint = '{0}.dispatch'.format(handler.__self__.__name__)\n        else:\n            endpoint = None\n\n        original_endpoint = endpoint\n        index = 2\n        while endpoint in backend_app.view_functions:\n            # HACK: Sometimes we map the same view to multiple url_paths. Flask\n            # requries us to have different names.\n            endpoint = original_endpoint + str(index)\n            index += 1\n\n        backend_app.add_url_rule(\n            url_path,\n            endpoint=endpoint,\n            methods=HTTP_METHODS,\n            view_func=convert_flask_to_httpretty_response(handler),\n            strict_slashes=False,\n        )\n\n    backend_app.test_client_class = AWSTestHelper\n    return backend_app\n\n\ndef main(argv=sys.argv[1:]):\n    parser = argparse.ArgumentParser()\n\n    # Keep this for backwards compat\n    parser.add_argument(\n        \"service\",\n        type=str,\n        nargs='?',  # http://stackoverflow.com/a/4480202/731592\n        default=None)\n    parser.add_argument(\n        '-H', '--host', type=str,\n        help='Which host to bind',\n        default='127.0.0.1')\n    parser.add_argument(\n        '-p', '--port', type=int,\n        help='Port number to use for connection',\n        default=5000)\n    parser.add_argument(\n        '-r', '--reload',\n        action='store_true',\n        help='Reload server on a file change',\n        default=False\n    )\n    parser.add_argument(\n        '-s', '--ssl',\n        action='store_true',\n        help='Enable SSL encrypted connection with auto-generated certificate (use https://... URL)',\n        default=False\n    )\n    parser.add_argument(\n        '-c', '--ssl-cert', type=str,\n        help='Path to SSL certificate',\n        default=None)\n    parser.add_argument(\n        '-k', '--ssl-key', type=str,\n        help='Path to SSL private key',\n        default=None)\n\n    args = parser.parse_args(argv)\n\n    # Wrap the main application\n    main_app = DomainDispatcherApplication(\n        create_backend_app, service=args.service)\n    main_app.debug = True\n\n    ssl_context = None\n    if args.ssl_key and args.ssl_cert:\n        ssl_context = (args.ssl_cert, args.ssl_key)\n    elif args.ssl:\n        ssl_context = 'adhoc'\n\n    run_simple(args.host, args.port, main_app,\n               threaded=True, use_reloader=args.reload,\n               ssl_context=ssl_context)\n\n\nif __name__ == '__main__':\n    main()\n", "path": "moto/server.py"}], "after_files": [{"content": "from __future__ import unicode_literals\n\nimport argparse\nimport json\nimport re\nimport sys\nfrom threading import Lock\n\nimport six\nfrom flask import Flask\nfrom flask.testing import FlaskClient\n\nfrom six.moves.urllib.parse import urlencode\nfrom werkzeug.routing import BaseConverter\nfrom werkzeug.serving import run_simple\n\nfrom moto.backends import BACKENDS\nfrom moto.core.utils import convert_flask_to_httpretty_response\n\n\nHTTP_METHODS = [\"GET\", \"POST\", \"PUT\", \"DELETE\", \"HEAD\", \"PATCH\"]\n\n\nDEFAULT_SERVICE_REGION = ('s3', 'us-east-1')\n\n# Map of unsigned calls to service-region as per AWS API docs\n# https://docs.aws.amazon.com/cognito/latest/developerguide/resource-permissions.html#amazon-cognito-signed-versus-unsigned-apis\nUNSIGNED_REQUESTS = {\n    'AWSCognitoIdentityService': ('cognito-identity', 'us-east-1'),\n    'AWSCognitoIdentityProviderService': ('cognito-idp', 'us-east-1'),\n}\n\n\nclass DomainDispatcherApplication(object):\n    \"\"\"\n    Dispatch requests to different applications based on the \"Host:\" header\n    value. We'll match the host header value with the url_bases of each backend.\n    \"\"\"\n\n    def __init__(self, create_app, service=None):\n        self.create_app = create_app\n        self.lock = Lock()\n        self.app_instances = {}\n        self.service = service\n\n    def get_backend_for_host(self, host):\n        if host == 'moto_api':\n            return host\n\n        if self.service:\n            return self.service\n\n        if host in BACKENDS:\n            return host\n\n        for backend_name, backend in BACKENDS.items():\n            for url_base in list(backend.values())[0].url_bases:\n                if re.match(url_base, 'http://%s' % host):\n                    return backend_name\n\n    def infer_service_region_host(self, environ):\n        auth = environ.get('HTTP_AUTHORIZATION')\n        if auth:\n            # Signed request\n            # Parse auth header to find service assuming a SigV4 request\n            # https://docs.aws.amazon.com/general/latest/gr/sigv4-signed-request-examples.html\n            # ['Credential=sdffdsa', '20170220', 'us-east-1', 'sns', 'aws4_request']\n            try:\n                credential_scope = auth.split(\",\")[0].split()[1]\n                _, _, region, service, _ = credential_scope.split(\"/\")\n            except ValueError:\n                # Signature format does not match, this is exceptional and we can't\n                # infer a service-region. A reduced set of services still use\n                # the deprecated SigV2, ergo prefer S3 as most likely default.\n                # https://docs.aws.amazon.com/general/latest/gr/signature-version-2.html\n                service, region = DEFAULT_SERVICE_REGION\n        else:\n            # Unsigned request\n            target = environ.get('HTTP_X_AMZ_TARGET')\n            if target:\n                service, _ = target.split('.', 1)\n                service, region = UNSIGNED_REQUESTS.get(service, DEFAULT_SERVICE_REGION)\n            else:\n                # S3 is the last resort when the target is also unknown\n                service, region = DEFAULT_SERVICE_REGION\n\n        if service == 'dynamodb':\n            if environ['HTTP_X_AMZ_TARGET'].startswith('DynamoDBStreams'):\n                host = 'dynamodbstreams'\n            else:\n                dynamo_api_version = environ['HTTP_X_AMZ_TARGET'].split(\"_\")[1].split(\".\")[0]\n                # If Newer API version, use dynamodb2\n                if dynamo_api_version > \"20111205\":\n                    host = \"dynamodb2\"\n        else:\n            host = \"{service}.{region}.amazonaws.com\".format(\n                service=service, region=region)\n\n        return host\n\n    def get_application(self, environ):\n        path_info = environ.get('PATH_INFO', '')\n\n        # The URL path might contain non-ASCII text, for instance unicode S3 bucket names\n        if six.PY2 and isinstance(path_info, str):\n            path_info = six.u(path_info)\n        if six.PY3 and isinstance(path_info, six.binary_type):\n            path_info = path_info.decode('utf-8')\n\n        if path_info.startswith(\"/moto-api\") or path_info == \"/favicon.ico\":\n            host = \"moto_api\"\n        elif path_info.startswith(\"/latest/meta-data/\"):\n            host = \"instance_metadata\"\n        else:\n            host = environ['HTTP_HOST'].split(':')[0]\n\n        with self.lock:\n            backend = self.get_backend_for_host(host)\n            if not backend:\n                # No regular backend found; try parsing other headers\n                host = self.infer_service_region_host(environ)\n                backend = self.get_backend_for_host(host)\n\n            app = self.app_instances.get(backend, None)\n            if app is None:\n                app = self.create_app(backend)\n                self.app_instances[backend] = app\n            return app\n\n    def __call__(self, environ, start_response):\n        backend_app = self.get_application(environ)\n        return backend_app(environ, start_response)\n\n\nclass RegexConverter(BaseConverter):\n    # http://werkzeug.pocoo.org/docs/routing/#custom-converters\n\n    def __init__(self, url_map, *items):\n        super(RegexConverter, self).__init__(url_map)\n        self.regex = items[0]\n\n\nclass AWSTestHelper(FlaskClient):\n\n    def action_data(self, action_name, **kwargs):\n        \"\"\"\n        Method calls resource with action_name and returns data of response.\n        \"\"\"\n        opts = {\"Action\": action_name}\n        opts.update(kwargs)\n        res = self.get(\"/?{0}\".format(urlencode(opts)),\n                       headers={\"Host\": \"{0}.us-east-1.amazonaws.com\".format(self.application.service)})\n        return res.data.decode(\"utf-8\")\n\n    def action_json(self, action_name, **kwargs):\n        \"\"\"\n        Method calls resource with action_name and returns object obtained via\n        deserialization of output.\n        \"\"\"\n        return json.loads(self.action_data(action_name, **kwargs))\n\n\ndef create_backend_app(service):\n    from werkzeug.routing import Map\n\n    # Create the backend_app\n    backend_app = Flask(__name__)\n    backend_app.debug = True\n    backend_app.service = service\n\n    # Reset view functions to reset the app\n    backend_app.view_functions = {}\n    backend_app.url_map = Map()\n    backend_app.url_map.converters['regex'] = RegexConverter\n    backend = list(BACKENDS[service].values())[0]\n    for url_path, handler in backend.flask_paths.items():\n        if handler.__name__ == 'dispatch':\n            endpoint = '{0}.dispatch'.format(handler.__self__.__name__)\n        else:\n            endpoint = None\n\n        original_endpoint = endpoint\n        index = 2\n        while endpoint in backend_app.view_functions:\n            # HACK: Sometimes we map the same view to multiple url_paths. Flask\n            # requries us to have different names.\n            endpoint = original_endpoint + str(index)\n            index += 1\n\n        backend_app.add_url_rule(\n            url_path,\n            endpoint=endpoint,\n            methods=HTTP_METHODS,\n            view_func=convert_flask_to_httpretty_response(handler),\n            strict_slashes=False,\n        )\n\n    backend_app.test_client_class = AWSTestHelper\n    return backend_app\n\n\ndef main(argv=sys.argv[1:]):\n    parser = argparse.ArgumentParser()\n\n    # Keep this for backwards compat\n    parser.add_argument(\n        \"service\",\n        type=str,\n        nargs='?',  # http://stackoverflow.com/a/4480202/731592\n        default=None)\n    parser.add_argument(\n        '-H', '--host', type=str,\n        help='Which host to bind',\n        default='127.0.0.1')\n    parser.add_argument(\n        '-p', '--port', type=int,\n        help='Port number to use for connection',\n        default=5000)\n    parser.add_argument(\n        '-r', '--reload',\n        action='store_true',\n        help='Reload server on a file change',\n        default=False\n    )\n    parser.add_argument(\n        '-s', '--ssl',\n        action='store_true',\n        help='Enable SSL encrypted connection with auto-generated certificate (use https://... URL)',\n        default=False\n    )\n    parser.add_argument(\n        '-c', '--ssl-cert', type=str,\n        help='Path to SSL certificate',\n        default=None)\n    parser.add_argument(\n        '-k', '--ssl-key', type=str,\n        help='Path to SSL private key',\n        default=None)\n\n    args = parser.parse_args(argv)\n\n    # Wrap the main application\n    main_app = DomainDispatcherApplication(\n        create_backend_app, service=args.service)\n    main_app.debug = True\n\n    ssl_context = None\n    if args.ssl_key and args.ssl_cert:\n        ssl_context = (args.ssl_cert, args.ssl_key)\n    elif args.ssl:\n        ssl_context = 'adhoc'\n\n    run_simple(args.host, args.port, main_app,\n               threaded=True, use_reloader=args.reload,\n               ssl_context=ssl_context)\n\n\nif __name__ == '__main__':\n    main()\n", "path": "moto/server.py"}]}