We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
contrib/_appengine_environ.py KeyError SERVER_SOFTWARE
https://github.com/urllib3/urllib3/blob/master/src/urllib3/contrib/_appengine_environ.py

In the development environment, the variable SERVER_SOFTWARE is sometimes not set, so the query should read as follows:

`os.environ.get('SERVER_SOFTWARE', '').startswith('Development')`

```
def is_local_appengine():
    return ('APPENGINE_RUNTIME' in os.environ and
            os.environ.get('SERVER_SOFTWARE', '').startswith('Development'))


def is_prod_appengine():
    return ('APPENGINE_RUNTIME' in os.environ and
            not os.environ.get('SERVER_SOFTWARE', '').startswith('Development') and
            not is_prod_appengine_mvms())
```

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `src/urllib3/contrib/appengine.py`
Content:
```
1 """
2 This module provides a pool manager that uses Google App Engine's
3 `URLFetch Service <https://cloud.google.com/appengine/docs/python/urlfetch>`_.
4 
5 Example usage::
6 
7     from urllib3 import PoolManager
8     from urllib3.contrib.appengine import AppEngineManager, is_appengine_sandbox
9 
10     if is_appengine_sandbox():
11         # AppEngineManager uses AppEngine's URLFetch API behind the scenes
12         http = AppEngineManager()
13     else:
14         # PoolManager uses a socket-level API behind the scenes
15         http = PoolManager()
16 
17     r = http.request('GET', 'https://google.com/')
18 
19 There are `limitations <https://cloud.google.com/appengine/docs/python/\
20 urlfetch/#Python_Quotas_and_limits>`_ to the URLFetch service and it may not be
21 the best choice for your application. There are three options for using
22 urllib3 on Google App Engine:
23 
24 1. You can use :class:`AppEngineManager` with URLFetch. URLFetch is
25    cost-effective in many circumstances as long as your usage is within the
26    limitations.
27 2. You can use a normal :class:`~urllib3.PoolManager` by enabling sockets.
28    Sockets also have `limitations and restrictions
29    <https://cloud.google.com/appengine/docs/python/sockets/\
30    #limitations-and-restrictions>`_ and have a lower free quota than URLFetch.
31    To use sockets, be sure to specify the following in your ``app.yaml``::
32 
33         env_variables:
34             GAE_USE_SOCKETS_HTTPLIB : 'true'
35 
36 3. If you are using `App Engine Flexible
37 <https://cloud.google.com/appengine/docs/flexible/>`_, you can use the standard
38 :class:`PoolManager` without any configuration or special environment variables.
39 """
40 
41 from __future__ import absolute_import
42 import io
43 import logging
44 import warnings
45 from ..packages.six.moves.urllib.parse import urljoin
46 
47 from ..exceptions import (
48     HTTPError,
49     HTTPWarning,
50     MaxRetryError,
51     ProtocolError,
52     TimeoutError,
53     SSLError,
54 )
55 
56 from ..request import RequestMethods
57 from ..response import HTTPResponse
58 from ..util.timeout import Timeout
59 from ..util.retry import Retry
60 from . import _appengine_environ
61 
62 try:
63     from google.appengine.api import urlfetch
64 except ImportError:
65     urlfetch = None
66 
67 
68 log = logging.getLogger(__name__)
69 
70 
71 class AppEnginePlatformWarning(HTTPWarning):
72     pass
73 
74 
75 class AppEnginePlatformError(HTTPError):
76     pass
77 
78 
79 class AppEngineManager(RequestMethods):
80     """
81     Connection manager for Google App Engine sandbox applications.
82 
83     This manager uses the URLFetch service directly instead of using the
84     emulated httplib, and is subject to URLFetch limitations as described in
85     the App Engine documentation `here
86     <https://cloud.google.com/appengine/docs/python/urlfetch>`_.
87 
88     Notably it will raise an :class:`AppEnginePlatformError` if:
89         * URLFetch is not available.
90         * If you attempt to use this on App Engine Flexible, as full socket
91           support is available.
92         * If a request size is more than 10 megabytes.
93         * If a response size is more than 32 megabtyes.
94         * If you use an unsupported request method such as OPTIONS.
95 
96     Beyond those cases, it will raise normal urllib3 errors.
97     """
98 
99     def __init__(
100         self,
101         headers=None,
102         retries=None,
103         validate_certificate=True,
104         urlfetch_retries=True,
105     ):
106         if not urlfetch:
107             raise AppEnginePlatformError(
108                 "URLFetch is not available in this environment."
109             )
110 
111         if is_prod_appengine_mvms():
112             raise AppEnginePlatformError(
113                 "Use normal urllib3.PoolManager instead of AppEngineManager"
114                 "on Managed VMs, as using URLFetch is not necessary in "
115                 "this environment."
116             )
117 
118         warnings.warn(
119             "urllib3 is using URLFetch on Google App Engine sandbox instead "
120             "of sockets. To use sockets directly instead of URLFetch see "
121             "https://urllib3.readthedocs.io/en/latest/reference/urllib3.contrib.html.",
122             AppEnginePlatformWarning,
123         )
124 
125         RequestMethods.__init__(self, headers)
126         self.validate_certificate = validate_certificate
127         self.urlfetch_retries = urlfetch_retries
128 
129         self.retries = retries or Retry.DEFAULT
130 
131     def __enter__(self):
132         return self
133 
134     def __exit__(self, exc_type, exc_val, exc_tb):
135         # Return False to re-raise any potential exceptions
136         return False
137 
138     def urlopen(
139         self,
140         method,
141         url,
142         body=None,
143         headers=None,
144         retries=None,
145         redirect=True,
146         timeout=Timeout.DEFAULT_TIMEOUT,
147         **response_kw
148     ):
149 
150         retries = self._get_retries(retries, redirect)
151 
152         try:
153             follow_redirects = redirect and retries.redirect != 0 and retries.total
154             response = urlfetch.fetch(
155                 url,
156                 payload=body,
157                 method=method,
158                 headers=headers or {},
159                 allow_truncated=False,
160                 follow_redirects=self.urlfetch_retries and follow_redirects,
161                 deadline=self._get_absolute_timeout(timeout),
162                 validate_certificate=self.validate_certificate,
163             )
164         except urlfetch.DeadlineExceededError as e:
165             raise TimeoutError(self, e)
166 
167         except urlfetch.InvalidURLError as e:
168             if "too large" in str(e):
169                 raise AppEnginePlatformError(
170                     "URLFetch request too large, URLFetch only "
171                     "supports requests up to 10mb in size.",
172                     e,
173                 )
174             raise ProtocolError(e)
175 
176         except urlfetch.DownloadError as e:
177             if "Too many redirects" in str(e):
178                 raise MaxRetryError(self, url, reason=e)
179             raise ProtocolError(e)
180 
181         except urlfetch.ResponseTooLargeError as e:
182             raise AppEnginePlatformError(
183                 "URLFetch response too large, URLFetch only supports"
184                 "responses up to 32mb in size.",
185                 e,
186             )
187 
188         except urlfetch.SSLCertificateError as e:
189             raise SSLError(e)
190 
191         except urlfetch.InvalidMethodError as e:
192             raise AppEnginePlatformError(
193                 "URLFetch does not support method: %s" % method, e
194             )
195 
196         http_response = self._urlfetch_response_to_http_response(
197             response, retries=retries, **response_kw
198         )
199 
200         # Handle redirect?
201         redirect_location = redirect and http_response.get_redirect_location()
202         if redirect_location:
203             # Check for redirect response
204             if self.urlfetch_retries and retries.raise_on_redirect:
205                 raise MaxRetryError(self, url, "too many redirects")
206             else:
207                 if http_response.status == 303:
208                     method = "GET"
209 
210                 try:
211                     retries = retries.increment(
212                         method, url, response=http_response, _pool=self
213                     )
214                 except MaxRetryError:
215                     if retries.raise_on_redirect:
216                         raise MaxRetryError(self, url, "too many redirects")
217                     return http_response
218 
219                 retries.sleep_for_retry(http_response)
220                 log.debug("Redirecting %s -> %s", url, redirect_location)
221                 redirect_url = urljoin(url, redirect_location)
222                 return self.urlopen(
223                     method,
224                     redirect_url,
225                     body,
226                     headers,
227                     retries=retries,
228                     redirect=redirect,
229                     timeout=timeout,
230                     **response_kw
231                 )
232 
233         # Check if we should retry the HTTP response.
234         has_retry_after = bool(http_response.getheader("Retry-After"))
235         if retries.is_retry(method, http_response.status, has_retry_after):
236             retries = retries.increment(method, url, response=http_response, _pool=self)
237             log.debug("Retry: %s", url)
238             retries.sleep(http_response)
239             return self.urlopen(
240                 method,
241                 url,
242                 body=body,
243                 headers=headers,
244                 retries=retries,
245                 redirect=redirect,
246                 timeout=timeout,
247                 **response_kw
248             )
249 
250         return http_response
251 
252     def _urlfetch_response_to_http_response(self, urlfetch_resp, **response_kw):
253 
254         if is_prod_appengine():
255             # Production GAE handles deflate encoding automatically, but does
256             # not remove the encoding header.
257             content_encoding = urlfetch_resp.headers.get("content-encoding")
258 
259             if content_encoding == "deflate":
260                 del urlfetch_resp.headers["content-encoding"]
261 
262         transfer_encoding = urlfetch_resp.headers.get("transfer-encoding")
263         # We have a full response's content,
264         # so let's make sure we don't report ourselves as chunked data.
265         if transfer_encoding == "chunked":
266             encodings = transfer_encoding.split(",")
267             encodings.remove("chunked")
268             urlfetch_resp.headers["transfer-encoding"] = ",".join(encodings)
269 
270         original_response = HTTPResponse(
271             # In order for decoding to work, we must present the content as
272             # a file-like object.
273             body=io.BytesIO(urlfetch_resp.content),
274             msg=urlfetch_resp.header_msg,
275             headers=urlfetch_resp.headers,
276             status=urlfetch_resp.status_code,
277             **response_kw
278         )
279 
280         return HTTPResponse(
281             body=io.BytesIO(urlfetch_resp.content),
282             headers=urlfetch_resp.headers,
283             status=urlfetch_resp.status_code,
284             original_response=original_response,
285             **response_kw
286         )
287 
288     def _get_absolute_timeout(self, timeout):
289         if timeout is Timeout.DEFAULT_TIMEOUT:
290             return None  # Defer to URLFetch's default.
291         if isinstance(timeout, Timeout):
292             if timeout._read is not None or timeout._connect is not None:
293                 warnings.warn(
294                     "URLFetch does not support granular timeout settings, "
295                     "reverting to total or default URLFetch timeout.",
296                     AppEnginePlatformWarning,
297                 )
298             return timeout.total
299         return timeout
300 
301     def _get_retries(self, retries, redirect):
302         if not isinstance(retries, Retry):
303             retries = Retry.from_int(retries, redirect=redirect, default=self.retries)
304 
305         if retries.connect or retries.read or retries.redirect:
306             warnings.warn(
307                 "URLFetch only supports total retries and does not "
308                 "recognize connect, read, or redirect retry parameters.",
309                 AppEnginePlatformWarning,
310             )
311 
312         return retries
313 
314 
315 # Alias methods from _appengine_environ to maintain public API interface.
316 
317 is_appengine = _appengine_environ.is_appengine
318 is_appengine_sandbox = _appengine_environ.is_appengine_sandbox
319 is_local_appengine = _appengine_environ.is_local_appengine
320 is_prod_appengine = _appengine_environ.is_prod_appengine
321 is_prod_appengine_mvms = _appengine_environ.is_prod_appengine_mvms
322
```

Path: `src/urllib3/contrib/_appengine_environ.py`
Content:
```
1 """
2 This module provides means to detect the App Engine environment.
3 """
4 
5 import os
6 
7 
8 def is_appengine():
9     return is_local_appengine() or is_prod_appengine() or is_prod_appengine_mvms()
10 
11 
12 def is_appengine_sandbox():
13     return is_appengine() and not is_prod_appengine_mvms()
14 
15 
16 def is_local_appengine():
17     return (
18         "APPENGINE_RUNTIME" in os.environ
19         and "Development/" in os.environ["SERVER_SOFTWARE"]
20     )
21 
22 
23 def is_prod_appengine():
24     return (
25         "APPENGINE_RUNTIME" in os.environ
26         and "Google App Engine/" in os.environ["SERVER_SOFTWARE"]
27         and not is_prod_appengine_mvms()
28     )
29 
30 
31 def is_prod_appengine_mvms():
32     return os.environ.get("GAE_VM", False) == "true"
33
```
--- 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/src/urllib3/contrib/_appengine_environ.py b/src/urllib3/contrib/_appengine_environ.py
--- a/src/urllib3/contrib/_appengine_environ.py
+++ b/src/urllib3/contrib/_appengine_environ.py
@@ -6,27 +6,31 @@
 
 
 def is_appengine():
-    return is_local_appengine() or is_prod_appengine() or is_prod_appengine_mvms()
+    return "APPENGINE_RUNTIME" in os.environ
 
 
 def is_appengine_sandbox():
-    return is_appengine() and not is_prod_appengine_mvms()
+    """Reports if the app is running in the first generation sandbox.
+
+    The second generation runtimes are technically still in a sandbox, but it
+    is much less restrictive, so generally you shouldn't need to check for it.
+    see https://cloud.google.com/appengine/docs/standard/runtimes
+    """
+    return is_appengine() and os.environ["APPENGINE_RUNTIME"] == "python27"
 
 
 def is_local_appengine():
-    return (
-        "APPENGINE_RUNTIME" in os.environ
-        and "Development/" in os.environ["SERVER_SOFTWARE"]
+    return is_appengine() and os.environ.get("SERVER_SOFTWARE", "").startswith(
+        "Development/"
     )
 
 
 def is_prod_appengine():
-    return (
-        "APPENGINE_RUNTIME" in os.environ
-        and "Google App Engine/" in os.environ["SERVER_SOFTWARE"]
-        and not is_prod_appengine_mvms()
+    return is_appengine() and os.environ.get("SERVER_SOFTWARE", "").startswith(
+        "Google App Engine/"
     )
 
 
 def is_prod_appengine_mvms():
-    return os.environ.get("GAE_VM", False) == "true"
+    """Deprecated."""
+    return False
diff --git a/src/urllib3/contrib/appengine.py b/src/urllib3/contrib/appengine.py
--- a/src/urllib3/contrib/appengine.py
+++ b/src/urllib3/contrib/appengine.py
@@ -108,13 +108,6 @@
                 "URLFetch is not available in this environment."
             )
 
-        if is_prod_appengine_mvms():
-            raise AppEnginePlatformError(
-                "Use normal urllib3.PoolManager instead of AppEngineManager"
-                "on Managed VMs, as using URLFetch is not necessary in "
-                "this environment."
-            )
-
         warnings.warn(
             "urllib3 is using URLFetch on Google App Engine sandbox instead "
             "of sockets. To use sockets directly instead of URLFetch see "

{"golden_diff": "diff --git a/src/urllib3/contrib/_appengine_environ.py b/src/urllib3/contrib/_appengine_environ.py\n--- a/src/urllib3/contrib/_appengine_environ.py\n+++ b/src/urllib3/contrib/_appengine_environ.py\n@@ -6,27 +6,31 @@\n \n \n def is_appengine():\n-    return is_local_appengine() or is_prod_appengine() or is_prod_appengine_mvms()\n+    return \"APPENGINE_RUNTIME\" in os.environ\n \n \n def is_appengine_sandbox():\n-    return is_appengine() and not is_prod_appengine_mvms()\n+    \"\"\"Reports if the app is running in the first generation sandbox.\n+\n+    The second generation runtimes are technically still in a sandbox, but it\n+    is much less restrictive, so generally you shouldn't need to check for it.\n+    see https://cloud.google.com/appengine/docs/standard/runtimes\n+    \"\"\"\n+    return is_appengine() and os.environ[\"APPENGINE_RUNTIME\"] == \"python27\"\n \n \n def is_local_appengine():\n-    return (\n-        \"APPENGINE_RUNTIME\" in os.environ\n-        and \"Development/\" in os.environ[\"SERVER_SOFTWARE\"]\n+    return is_appengine() and os.environ.get(\"SERVER_SOFTWARE\", \"\").startswith(\n+        \"Development/\"\n     )\n \n \n def is_prod_appengine():\n-    return (\n-        \"APPENGINE_RUNTIME\" in os.environ\n-        and \"Google App Engine/\" in os.environ[\"SERVER_SOFTWARE\"]\n-        and not is_prod_appengine_mvms()\n+    return is_appengine() and os.environ.get(\"SERVER_SOFTWARE\", \"\").startswith(\n+        \"Google App Engine/\"\n     )\n \n \n def is_prod_appengine_mvms():\n-    return os.environ.get(\"GAE_VM\", False) == \"true\"\n+    \"\"\"Deprecated.\"\"\"\n+    return False\ndiff --git a/src/urllib3/contrib/appengine.py b/src/urllib3/contrib/appengine.py\n--- a/src/urllib3/contrib/appengine.py\n+++ b/src/urllib3/contrib/appengine.py\n@@ -108,13 +108,6 @@\n                 \"URLFetch is not available in this environment.\"\n             )\n \n-        if is_prod_appengine_mvms():\n-            raise AppEnginePlatformError(\n-                \"Use normal urllib3.PoolManager instead of AppEngineManager\"\n-                \"on Managed VMs, as using URLFetch is not necessary in \"\n-                \"this environment.\"\n-            )\n-\n         warnings.warn(\n             \"urllib3 is using URLFetch on Google App Engine sandbox instead \"\n             \"of sockets. To use sockets directly instead of URLFetch see \"\n", "issue": "contrib/_appengine_environ.py KeyError SERVER_SOFTWARE\nhttps://github.com/urllib3/urllib3/blob/master/src/urllib3/contrib/_appengine_environ.py\r\n\r\nIn the development environment, the variable SERVER_SOFTWARE is sometimes not set, so the query should read as follows:\r\n\r\n`os.environ.get('SERVER_SOFTWARE', '').startswith('Development')`\r\n\r\n```\r\ndef is_local_appengine():\r\n    return ('APPENGINE_RUNTIME' in os.environ and\r\n            os.environ.get('SERVER_SOFTWARE', '').startswith('Development'))\r\n\r\n\r\ndef is_prod_appengine():\r\n    return ('APPENGINE_RUNTIME' in os.environ and\r\n            not os.environ.get('SERVER_SOFTWARE', '').startswith('Development') and\r\n            not is_prod_appengine_mvms())\r\n```\n", "before_files": [{"content": "\"\"\"\nThis module provides a pool manager that uses Google App Engine's\n`URLFetch Service <https://cloud.google.com/appengine/docs/python/urlfetch>`_.\n\nExample usage::\n\n    from urllib3 import PoolManager\n    from urllib3.contrib.appengine import AppEngineManager, is_appengine_sandbox\n\n    if is_appengine_sandbox():\n        # AppEngineManager uses AppEngine's URLFetch API behind the scenes\n        http = AppEngineManager()\n    else:\n        # PoolManager uses a socket-level API behind the scenes\n        http = PoolManager()\n\n    r = http.request('GET', 'https://google.com/')\n\nThere are `limitations <https://cloud.google.com/appengine/docs/python/\\\nurlfetch/#Python_Quotas_and_limits>`_ to the URLFetch service and it may not be\nthe best choice for your application. There are three options for using\nurllib3 on Google App Engine:\n\n1. You can use :class:`AppEngineManager` with URLFetch. URLFetch is\n   cost-effective in many circumstances as long as your usage is within the\n   limitations.\n2. You can use a normal :class:`~urllib3.PoolManager` by enabling sockets.\n   Sockets also have `limitations and restrictions\n   <https://cloud.google.com/appengine/docs/python/sockets/\\\n   #limitations-and-restrictions>`_ and have a lower free quota than URLFetch.\n   To use sockets, be sure to specify the following in your ``app.yaml``::\n\n        env_variables:\n            GAE_USE_SOCKETS_HTTPLIB : 'true'\n\n3. If you are using `App Engine Flexible\n<https://cloud.google.com/appengine/docs/flexible/>`_, you can use the standard\n:class:`PoolManager` without any configuration or special environment variables.\n\"\"\"\n\nfrom __future__ import absolute_import\nimport io\nimport logging\nimport warnings\nfrom ..packages.six.moves.urllib.parse import urljoin\n\nfrom ..exceptions import (\n    HTTPError,\n    HTTPWarning,\n    MaxRetryError,\n    ProtocolError,\n    TimeoutError,\n    SSLError,\n)\n\nfrom ..request import RequestMethods\nfrom ..response import HTTPResponse\nfrom ..util.timeout import Timeout\nfrom ..util.retry import Retry\nfrom . import _appengine_environ\n\ntry:\n    from google.appengine.api import urlfetch\nexcept ImportError:\n    urlfetch = None\n\n\nlog = logging.getLogger(__name__)\n\n\nclass AppEnginePlatformWarning(HTTPWarning):\n    pass\n\n\nclass AppEnginePlatformError(HTTPError):\n    pass\n\n\nclass AppEngineManager(RequestMethods):\n    \"\"\"\n    Connection manager for Google App Engine sandbox applications.\n\n    This manager uses the URLFetch service directly instead of using the\n    emulated httplib, and is subject to URLFetch limitations as described in\n    the App Engine documentation `here\n    <https://cloud.google.com/appengine/docs/python/urlfetch>`_.\n\n    Notably it will raise an :class:`AppEnginePlatformError` if:\n        * URLFetch is not available.\n        * If you attempt to use this on App Engine Flexible, as full socket\n          support is available.\n        * If a request size is more than 10 megabytes.\n        * If a response size is more than 32 megabtyes.\n        * If you use an unsupported request method such as OPTIONS.\n\n    Beyond those cases, it will raise normal urllib3 errors.\n    \"\"\"\n\n    def __init__(\n        self,\n        headers=None,\n        retries=None,\n        validate_certificate=True,\n        urlfetch_retries=True,\n    ):\n        if not urlfetch:\n            raise AppEnginePlatformError(\n                \"URLFetch is not available in this environment.\"\n            )\n\n        if is_prod_appengine_mvms():\n            raise AppEnginePlatformError(\n                \"Use normal urllib3.PoolManager instead of AppEngineManager\"\n                \"on Managed VMs, as using URLFetch is not necessary in \"\n                \"this environment.\"\n            )\n\n        warnings.warn(\n            \"urllib3 is using URLFetch on Google App Engine sandbox instead \"\n            \"of sockets. To use sockets directly instead of URLFetch see \"\n            \"https://urllib3.readthedocs.io/en/latest/reference/urllib3.contrib.html.\",\n            AppEnginePlatformWarning,\n        )\n\n        RequestMethods.__init__(self, headers)\n        self.validate_certificate = validate_certificate\n        self.urlfetch_retries = urlfetch_retries\n\n        self.retries = retries or Retry.DEFAULT\n\n    def __enter__(self):\n        return self\n\n    def __exit__(self, exc_type, exc_val, exc_tb):\n        # Return False to re-raise any potential exceptions\n        return False\n\n    def urlopen(\n        self,\n        method,\n        url,\n        body=None,\n        headers=None,\n        retries=None,\n        redirect=True,\n        timeout=Timeout.DEFAULT_TIMEOUT,\n        **response_kw\n    ):\n\n        retries = self._get_retries(retries, redirect)\n\n        try:\n            follow_redirects = redirect and retries.redirect != 0 and retries.total\n            response = urlfetch.fetch(\n                url,\n                payload=body,\n                method=method,\n                headers=headers or {},\n                allow_truncated=False,\n                follow_redirects=self.urlfetch_retries and follow_redirects,\n                deadline=self._get_absolute_timeout(timeout),\n                validate_certificate=self.validate_certificate,\n            )\n        except urlfetch.DeadlineExceededError as e:\n            raise TimeoutError(self, e)\n\n        except urlfetch.InvalidURLError as e:\n            if \"too large\" in str(e):\n                raise AppEnginePlatformError(\n                    \"URLFetch request too large, URLFetch only \"\n                    \"supports requests up to 10mb in size.\",\n                    e,\n                )\n            raise ProtocolError(e)\n\n        except urlfetch.DownloadError as e:\n            if \"Too many redirects\" in str(e):\n                raise MaxRetryError(self, url, reason=e)\n            raise ProtocolError(e)\n\n        except urlfetch.ResponseTooLargeError as e:\n            raise AppEnginePlatformError(\n                \"URLFetch response too large, URLFetch only supports\"\n                \"responses up to 32mb in size.\",\n                e,\n            )\n\n        except urlfetch.SSLCertificateError as e:\n            raise SSLError(e)\n\n        except urlfetch.InvalidMethodError as e:\n            raise AppEnginePlatformError(\n                \"URLFetch does not support method: %s\" % method, e\n            )\n\n        http_response = self._urlfetch_response_to_http_response(\n            response, retries=retries, **response_kw\n        )\n\n        # Handle redirect?\n        redirect_location = redirect and http_response.get_redirect_location()\n        if redirect_location:\n            # Check for redirect response\n            if self.urlfetch_retries and retries.raise_on_redirect:\n                raise MaxRetryError(self, url, \"too many redirects\")\n            else:\n                if http_response.status == 303:\n                    method = \"GET\"\n\n                try:\n                    retries = retries.increment(\n                        method, url, response=http_response, _pool=self\n                    )\n                except MaxRetryError:\n                    if retries.raise_on_redirect:\n                        raise MaxRetryError(self, url, \"too many redirects\")\n                    return http_response\n\n                retries.sleep_for_retry(http_response)\n                log.debug(\"Redirecting %s -> %s\", url, redirect_location)\n                redirect_url = urljoin(url, redirect_location)\n                return self.urlopen(\n                    method,\n                    redirect_url,\n                    body,\n                    headers,\n                    retries=retries,\n                    redirect=redirect,\n                    timeout=timeout,\n                    **response_kw\n                )\n\n        # Check if we should retry the HTTP response.\n        has_retry_after = bool(http_response.getheader(\"Retry-After\"))\n        if retries.is_retry(method, http_response.status, has_retry_after):\n            retries = retries.increment(method, url, response=http_response, _pool=self)\n            log.debug(\"Retry: %s\", url)\n            retries.sleep(http_response)\n            return self.urlopen(\n                method,\n                url,\n                body=body,\n                headers=headers,\n                retries=retries,\n                redirect=redirect,\n                timeout=timeout,\n                **response_kw\n            )\n\n        return http_response\n\n    def _urlfetch_response_to_http_response(self, urlfetch_resp, **response_kw):\n\n        if is_prod_appengine():\n            # Production GAE handles deflate encoding automatically, but does\n            # not remove the encoding header.\n            content_encoding = urlfetch_resp.headers.get(\"content-encoding\")\n\n            if content_encoding == \"deflate\":\n                del urlfetch_resp.headers[\"content-encoding\"]\n\n        transfer_encoding = urlfetch_resp.headers.get(\"transfer-encoding\")\n        # We have a full response's content,\n        # so let's make sure we don't report ourselves as chunked data.\n        if transfer_encoding == \"chunked\":\n            encodings = transfer_encoding.split(\",\")\n            encodings.remove(\"chunked\")\n            urlfetch_resp.headers[\"transfer-encoding\"] = \",\".join(encodings)\n\n        original_response = HTTPResponse(\n            # In order for decoding to work, we must present the content as\n            # a file-like object.\n            body=io.BytesIO(urlfetch_resp.content),\n            msg=urlfetch_resp.header_msg,\n            headers=urlfetch_resp.headers,\n            status=urlfetch_resp.status_code,\n            **response_kw\n        )\n\n        return HTTPResponse(\n            body=io.BytesIO(urlfetch_resp.content),\n            headers=urlfetch_resp.headers,\n            status=urlfetch_resp.status_code,\n            original_response=original_response,\n            **response_kw\n        )\n\n    def _get_absolute_timeout(self, timeout):\n        if timeout is Timeout.DEFAULT_TIMEOUT:\n            return None  # Defer to URLFetch's default.\n        if isinstance(timeout, Timeout):\n            if timeout._read is not None or timeout._connect is not None:\n                warnings.warn(\n                    \"URLFetch does not support granular timeout settings, \"\n                    \"reverting to total or default URLFetch timeout.\",\n                    AppEnginePlatformWarning,\n                )\n            return timeout.total\n        return timeout\n\n    def _get_retries(self, retries, redirect):\n        if not isinstance(retries, Retry):\n            retries = Retry.from_int(retries, redirect=redirect, default=self.retries)\n\n        if retries.connect or retries.read or retries.redirect:\n            warnings.warn(\n                \"URLFetch only supports total retries and does not \"\n                \"recognize connect, read, or redirect retry parameters.\",\n                AppEnginePlatformWarning,\n            )\n\n        return retries\n\n\n# Alias methods from _appengine_environ to maintain public API interface.\n\nis_appengine = _appengine_environ.is_appengine\nis_appengine_sandbox = _appengine_environ.is_appengine_sandbox\nis_local_appengine = _appengine_environ.is_local_appengine\nis_prod_appengine = _appengine_environ.is_prod_appengine\nis_prod_appengine_mvms = _appengine_environ.is_prod_appengine_mvms\n", "path": "src/urllib3/contrib/appengine.py"}, {"content": "\"\"\"\nThis module provides means to detect the App Engine environment.\n\"\"\"\n\nimport os\n\n\ndef is_appengine():\n    return is_local_appengine() or is_prod_appengine() or is_prod_appengine_mvms()\n\n\ndef is_appengine_sandbox():\n    return is_appengine() and not is_prod_appengine_mvms()\n\n\ndef is_local_appengine():\n    return (\n        \"APPENGINE_RUNTIME\" in os.environ\n        and \"Development/\" in os.environ[\"SERVER_SOFTWARE\"]\n    )\n\n\ndef is_prod_appengine():\n    return (\n        \"APPENGINE_RUNTIME\" in os.environ\n        and \"Google App Engine/\" in os.environ[\"SERVER_SOFTWARE\"]\n        and not is_prod_appengine_mvms()\n    )\n\n\ndef is_prod_appengine_mvms():\n    return os.environ.get(\"GAE_VM\", False) == \"true\"\n", "path": "src/urllib3/contrib/_appengine_environ.py"}], "after_files": [{"content": "\"\"\"\nThis module provides a pool manager that uses Google App Engine's\n`URLFetch Service <https://cloud.google.com/appengine/docs/python/urlfetch>`_.\n\nExample usage::\n\n    from urllib3 import PoolManager\n    from urllib3.contrib.appengine import AppEngineManager, is_appengine_sandbox\n\n    if is_appengine_sandbox():\n        # AppEngineManager uses AppEngine's URLFetch API behind the scenes\n        http = AppEngineManager()\n    else:\n        # PoolManager uses a socket-level API behind the scenes\n        http = PoolManager()\n\n    r = http.request('GET', 'https://google.com/')\n\nThere are `limitations <https://cloud.google.com/appengine/docs/python/\\\nurlfetch/#Python_Quotas_and_limits>`_ to the URLFetch service and it may not be\nthe best choice for your application. There are three options for using\nurllib3 on Google App Engine:\n\n1. You can use :class:`AppEngineManager` with URLFetch. URLFetch is\n   cost-effective in many circumstances as long as your usage is within the\n   limitations.\n2. You can use a normal :class:`~urllib3.PoolManager` by enabling sockets.\n   Sockets also have `limitations and restrictions\n   <https://cloud.google.com/appengine/docs/python/sockets/\\\n   #limitations-and-restrictions>`_ and have a lower free quota than URLFetch.\n   To use sockets, be sure to specify the following in your ``app.yaml``::\n\n        env_variables:\n            GAE_USE_SOCKETS_HTTPLIB : 'true'\n\n3. If you are using `App Engine Flexible\n<https://cloud.google.com/appengine/docs/flexible/>`_, you can use the standard\n:class:`PoolManager` without any configuration or special environment variables.\n\"\"\"\n\nfrom __future__ import absolute_import\nimport io\nimport logging\nimport warnings\nfrom ..packages.six.moves.urllib.parse import urljoin\n\nfrom ..exceptions import (\n    HTTPError,\n    HTTPWarning,\n    MaxRetryError,\n    ProtocolError,\n    TimeoutError,\n    SSLError,\n)\n\nfrom ..request import RequestMethods\nfrom ..response import HTTPResponse\nfrom ..util.timeout import Timeout\nfrom ..util.retry import Retry\nfrom . import _appengine_environ\n\ntry:\n    from google.appengine.api import urlfetch\nexcept ImportError:\n    urlfetch = None\n\n\nlog = logging.getLogger(__name__)\n\n\nclass AppEnginePlatformWarning(HTTPWarning):\n    pass\n\n\nclass AppEnginePlatformError(HTTPError):\n    pass\n\n\nclass AppEngineManager(RequestMethods):\n    \"\"\"\n    Connection manager for Google App Engine sandbox applications.\n\n    This manager uses the URLFetch service directly instead of using the\n    emulated httplib, and is subject to URLFetch limitations as described in\n    the App Engine documentation `here\n    <https://cloud.google.com/appengine/docs/python/urlfetch>`_.\n\n    Notably it will raise an :class:`AppEnginePlatformError` if:\n        * URLFetch is not available.\n        * If you attempt to use this on App Engine Flexible, as full socket\n          support is available.\n        * If a request size is more than 10 megabytes.\n        * If a response size is more than 32 megabtyes.\n        * If you use an unsupported request method such as OPTIONS.\n\n    Beyond those cases, it will raise normal urllib3 errors.\n    \"\"\"\n\n    def __init__(\n        self,\n        headers=None,\n        retries=None,\n        validate_certificate=True,\n        urlfetch_retries=True,\n    ):\n        if not urlfetch:\n            raise AppEnginePlatformError(\n                \"URLFetch is not available in this environment.\"\n            )\n\n        warnings.warn(\n            \"urllib3 is using URLFetch on Google App Engine sandbox instead \"\n            \"of sockets. To use sockets directly instead of URLFetch see \"\n            \"https://urllib3.readthedocs.io/en/latest/reference/urllib3.contrib.html.\",\n            AppEnginePlatformWarning,\n        )\n\n        RequestMethods.__init__(self, headers)\n        self.validate_certificate = validate_certificate\n        self.urlfetch_retries = urlfetch_retries\n\n        self.retries = retries or Retry.DEFAULT\n\n    def __enter__(self):\n        return self\n\n    def __exit__(self, exc_type, exc_val, exc_tb):\n        # Return False to re-raise any potential exceptions\n        return False\n\n    def urlopen(\n        self,\n        method,\n        url,\n        body=None,\n        headers=None,\n        retries=None,\n        redirect=True,\n        timeout=Timeout.DEFAULT_TIMEOUT,\n        **response_kw\n    ):\n\n        retries = self._get_retries(retries, redirect)\n\n        try:\n            follow_redirects = redirect and retries.redirect != 0 and retries.total\n            response = urlfetch.fetch(\n                url,\n                payload=body,\n                method=method,\n                headers=headers or {},\n                allow_truncated=False,\n                follow_redirects=self.urlfetch_retries and follow_redirects,\n                deadline=self._get_absolute_timeout(timeout),\n                validate_certificate=self.validate_certificate,\n            )\n        except urlfetch.DeadlineExceededError as e:\n            raise TimeoutError(self, e)\n\n        except urlfetch.InvalidURLError as e:\n            if \"too large\" in str(e):\n                raise AppEnginePlatformError(\n                    \"URLFetch request too large, URLFetch only \"\n                    \"supports requests up to 10mb in size.\",\n                    e,\n                )\n            raise ProtocolError(e)\n\n        except urlfetch.DownloadError as e:\n            if \"Too many redirects\" in str(e):\n                raise MaxRetryError(self, url, reason=e)\n            raise ProtocolError(e)\n\n        except urlfetch.ResponseTooLargeError as e:\n            raise AppEnginePlatformError(\n                \"URLFetch response too large, URLFetch only supports\"\n                \"responses up to 32mb in size.\",\n                e,\n            )\n\n        except urlfetch.SSLCertificateError as e:\n            raise SSLError(e)\n\n        except urlfetch.InvalidMethodError as e:\n            raise AppEnginePlatformError(\n                \"URLFetch does not support method: %s\" % method, e\n            )\n\n        http_response = self._urlfetch_response_to_http_response(\n            response, retries=retries, **response_kw\n        )\n\n        # Handle redirect?\n        redirect_location = redirect and http_response.get_redirect_location()\n        if redirect_location:\n            # Check for redirect response\n            if self.urlfetch_retries and retries.raise_on_redirect:\n                raise MaxRetryError(self, url, \"too many redirects\")\n            else:\n                if http_response.status == 303:\n                    method = \"GET\"\n\n                try:\n                    retries = retries.increment(\n                        method, url, response=http_response, _pool=self\n                    )\n                except MaxRetryError:\n                    if retries.raise_on_redirect:\n                        raise MaxRetryError(self, url, \"too many redirects\")\n                    return http_response\n\n                retries.sleep_for_retry(http_response)\n                log.debug(\"Redirecting %s -> %s\", url, redirect_location)\n                redirect_url = urljoin(url, redirect_location)\n                return self.urlopen(\n                    method,\n                    redirect_url,\n                    body,\n                    headers,\n                    retries=retries,\n                    redirect=redirect,\n                    timeout=timeout,\n                    **response_kw\n                )\n\n        # Check if we should retry the HTTP response.\n        has_retry_after = bool(http_response.getheader(\"Retry-After\"))\n        if retries.is_retry(method, http_response.status, has_retry_after):\n            retries = retries.increment(method, url, response=http_response, _pool=self)\n            log.debug(\"Retry: %s\", url)\n            retries.sleep(http_response)\n            return self.urlopen(\n                method,\n                url,\n                body=body,\n                headers=headers,\n                retries=retries,\n                redirect=redirect,\n                timeout=timeout,\n                **response_kw\n            )\n\n        return http_response\n\n    def _urlfetch_response_to_http_response(self, urlfetch_resp, **response_kw):\n\n        if is_prod_appengine():\n            # Production GAE handles deflate encoding automatically, but does\n            # not remove the encoding header.\n            content_encoding = urlfetch_resp.headers.get(\"content-encoding\")\n\n            if content_encoding == \"deflate\":\n                del urlfetch_resp.headers[\"content-encoding\"]\n\n        transfer_encoding = urlfetch_resp.headers.get(\"transfer-encoding\")\n        # We have a full response's content,\n        # so let's make sure we don't report ourselves as chunked data.\n        if transfer_encoding == \"chunked\":\n            encodings = transfer_encoding.split(\",\")\n            encodings.remove(\"chunked\")\n            urlfetch_resp.headers[\"transfer-encoding\"] = \",\".join(encodings)\n\n        original_response = HTTPResponse(\n            # In order for decoding to work, we must present the content as\n            # a file-like object.\n            body=io.BytesIO(urlfetch_resp.content),\n            msg=urlfetch_resp.header_msg,\n            headers=urlfetch_resp.headers,\n            status=urlfetch_resp.status_code,\n            **response_kw\n        )\n\n        return HTTPResponse(\n            body=io.BytesIO(urlfetch_resp.content),\n            headers=urlfetch_resp.headers,\n            status=urlfetch_resp.status_code,\n            original_response=original_response,\n            **response_kw\n        )\n\n    def _get_absolute_timeout(self, timeout):\n        if timeout is Timeout.DEFAULT_TIMEOUT:\n            return None  # Defer to URLFetch's default.\n        if isinstance(timeout, Timeout):\n            if timeout._read is not None or timeout._connect is not None:\n                warnings.warn(\n                    \"URLFetch does not support granular timeout settings, \"\n                    \"reverting to total or default URLFetch timeout.\",\n                    AppEnginePlatformWarning,\n                )\n            return timeout.total\n        return timeout\n\n    def _get_retries(self, retries, redirect):\n        if not isinstance(retries, Retry):\n            retries = Retry.from_int(retries, redirect=redirect, default=self.retries)\n\n        if retries.connect or retries.read or retries.redirect:\n            warnings.warn(\n                \"URLFetch only supports total retries and does not \"\n                \"recognize connect, read, or redirect retry parameters.\",\n                AppEnginePlatformWarning,\n            )\n\n        return retries\n\n\n# Alias methods from _appengine_environ to maintain public API interface.\n\nis_appengine = _appengine_environ.is_appengine\nis_appengine_sandbox = _appengine_environ.is_appengine_sandbox\nis_local_appengine = _appengine_environ.is_local_appengine\nis_prod_appengine = _appengine_environ.is_prod_appengine\nis_prod_appengine_mvms = _appengine_environ.is_prod_appengine_mvms\n", "path": "src/urllib3/contrib/appengine.py"}, {"content": "\"\"\"\nThis module provides means to detect the App Engine environment.\n\"\"\"\n\nimport os\n\n\ndef is_appengine():\n    return \"APPENGINE_RUNTIME\" in os.environ\n\n\ndef is_appengine_sandbox():\n    \"\"\"Reports if the app is running in the first generation sandbox.\n\n    The second generation runtimes are technically still in a sandbox, but it\n    is much less restrictive, so generally you shouldn't need to check for it.\n    see https://cloud.google.com/appengine/docs/standard/runtimes\n    \"\"\"\n    return is_appengine() and os.environ[\"APPENGINE_RUNTIME\"] == \"python27\"\n\n\ndef is_local_appengine():\n    return is_appengine() and os.environ.get(\"SERVER_SOFTWARE\", \"\").startswith(\n        \"Development/\"\n    )\n\n\ndef is_prod_appengine():\n    return is_appengine() and os.environ.get(\"SERVER_SOFTWARE\", \"\").startswith(\n        \"Google App Engine/\"\n    )\n\n\ndef is_prod_appengine_mvms():\n    \"\"\"Deprecated.\"\"\"\n    return False\n", "path": "src/urllib3/contrib/_appengine_environ.py"}]}