comparison env/lib/python3.7/site-packages/requests_toolbelt/adapters/appengine.py @ 2:6af9afd405e9 draft

"planemo upload commit 0a63dd5f4d38a1f6944587f52a8cd79874177fc1"
author shellac
date Thu, 14 May 2020 14:56:58 -0400
parents 26e78fe6e8c4
children
comparison
equal deleted inserted replaced
1:75ca89e9b81c 2:6af9afd405e9
1 # -*- coding: utf-8 -*-
2 """The App Engine Transport Adapter for requests.
3
4 .. versionadded:: 0.6.0
5
6 This requires a version of requests >= 2.10.0 and Python 2.
7
8 There are two ways to use this library:
9
10 #. If you're using requests directly, you can use code like:
11
12 .. code-block:: python
13
14 >>> import requests
15 >>> import ssl
16 >>> import requests.packages.urllib3.contrib.appengine as ul_appengine
17 >>> from requests_toolbelt.adapters import appengine
18 >>> s = requests.Session()
19 >>> if ul_appengine.is_appengine_sandbox():
20 ... s.mount('http://', appengine.AppEngineAdapter())
21 ... s.mount('https://', appengine.AppEngineAdapter())
22
23 #. If you depend on external libraries which use requests, you can use code
24 like:
25
26 .. code-block:: python
27
28 >>> from requests_toolbelt.adapters import appengine
29 >>> appengine.monkeypatch()
30
31 which will ensure all requests.Session objects use AppEngineAdapter properly.
32
33 You are also able to :ref:`disable certificate validation <insecure_appengine>`
34 when monkey-patching.
35 """
36 import requests
37 import warnings
38 from requests import adapters
39 from requests import sessions
40
41 from .. import exceptions as exc
42 from .._compat import gaecontrib
43 from .._compat import timeout
44
45
46 class AppEngineMROHack(adapters.HTTPAdapter):
47 """Resolves infinite recursion when monkeypatching.
48
49 This works by injecting itself as the base class of both the
50 :class:`AppEngineAdapter` and Requests' default HTTPAdapter, which needs to
51 be done because default HTTPAdapter's MRO is recompiled when we
52 monkeypatch, at which point this class becomes HTTPAdapter's base class.
53 In addition, we use an instantiation flag to avoid infinite recursion.
54 """
55 _initialized = False
56
57 def __init__(self, *args, **kwargs):
58 if not self._initialized:
59 self._initialized = True
60 super(AppEngineMROHack, self).__init__(*args, **kwargs)
61
62
63 class AppEngineAdapter(AppEngineMROHack, adapters.HTTPAdapter):
64 """The transport adapter for Requests to use urllib3's GAE support.
65
66 Implements Requests's HTTPAdapter API.
67
68 When deploying to Google's App Engine service, some of Requests'
69 functionality is broken. There is underlying support for GAE in urllib3.
70 This functionality, however, is opt-in and needs to be enabled explicitly
71 for Requests to be able to use it.
72 """
73
74 __attrs__ = adapters.HTTPAdapter.__attrs__ + ['_validate_certificate']
75
76 def __init__(self, validate_certificate=True, *args, **kwargs):
77 _check_version()
78 self._validate_certificate = validate_certificate
79 super(AppEngineAdapter, self).__init__(*args, **kwargs)
80
81 def init_poolmanager(self, connections, maxsize, block=False):
82 self.poolmanager = _AppEnginePoolManager(self._validate_certificate)
83
84
85 class InsecureAppEngineAdapter(AppEngineAdapter):
86 """An always-insecure GAE adapter for Requests.
87
88 This is a variant of the the transport adapter for Requests to use
89 urllib3's GAE support that does not validate certificates. Use with
90 caution!
91
92 .. note::
93 The ``validate_certificate`` keyword argument will not be honored here
94 and is not part of the signature because we always force it to
95 ``False``.
96
97 See :class:`AppEngineAdapter` for further details.
98 """
99
100 def __init__(self, *args, **kwargs):
101 if kwargs.pop("validate_certificate", False):
102 warnings.warn("Certificate validation cannot be specified on the "
103 "InsecureAppEngineAdapter, but was present. This "
104 "will be ignored and certificate validation will "
105 "remain off.", exc.IgnoringGAECertificateValidation)
106
107 super(InsecureAppEngineAdapter, self).__init__(
108 validate_certificate=False, *args, **kwargs)
109
110
111 class _AppEnginePoolManager(object):
112 """Implements urllib3's PoolManager API expected by requests.
113
114 While a real PoolManager map hostnames to reusable Connections,
115 AppEngine has no concept of a reusable connection to a host.
116 So instead, this class constructs a small Connection per request,
117 that is returned to the Adapter and used to access the URL.
118 """
119
120 def __init__(self, validate_certificate=True):
121 self.appengine_manager = gaecontrib.AppEngineManager(
122 validate_certificate=validate_certificate)
123
124 def connection_from_url(self, url):
125 return _AppEngineConnection(self.appengine_manager, url)
126
127 def clear(self):
128 pass
129
130
131 class _AppEngineConnection(object):
132 """Implements urllib3's HTTPConnectionPool API's urlopen().
133
134 This Connection's urlopen() is called with a host-relative path,
135 so in order to properly support opening the URL, we need to store
136 the full URL when this Connection is constructed from the PoolManager.
137
138 This code wraps AppEngineManager.urlopen(), which exposes a different
139 API than in the original urllib3 urlopen(), and thus needs this adapter.
140 """
141
142 def __init__(self, appengine_manager, url):
143 self.appengine_manager = appengine_manager
144 self.url = url
145
146 def urlopen(self, method, url, body=None, headers=None, retries=None,
147 redirect=True, assert_same_host=True,
148 timeout=timeout.Timeout.DEFAULT_TIMEOUT,
149 pool_timeout=None, release_conn=None, **response_kw):
150 # This function's url argument is a host-relative URL,
151 # but the AppEngineManager expects an absolute URL.
152 # So we saved out the self.url when the AppEngineConnection
153 # was constructed, which we then can use down below instead.
154
155 # We once tried to verify our assumptions here, but sometimes the
156 # passed-in URL differs on url fragments, or "http://a.com" vs "/".
157
158 # urllib3's App Engine adapter only uses Timeout.total, not read or
159 # connect.
160 if not timeout.total:
161 timeout.total = timeout._read or timeout._connect
162
163 # Jump through the hoops necessary to call AppEngineManager's API.
164 return self.appengine_manager.urlopen(
165 method,
166 self.url,
167 body=body,
168 headers=headers,
169 retries=retries,
170 redirect=redirect,
171 timeout=timeout,
172 **response_kw)
173
174
175 def monkeypatch(validate_certificate=True):
176 """Sets up all Sessions to use AppEngineAdapter by default.
177
178 If you don't want to deal with configuring your own Sessions,
179 or if you use libraries that use requests directly (ie requests.post),
180 then you may prefer to monkeypatch and auto-configure all Sessions.
181
182 .. warning: :
183
184 If ``validate_certificate`` is ``False``, certification validation will
185 effectively be disabled for all requests.
186 """
187 _check_version()
188 # HACK: We should consider modifying urllib3 to support this cleanly,
189 # so that we can set a module-level variable in the sessions module,
190 # instead of overriding an imported HTTPAdapter as is done here.
191 adapter = AppEngineAdapter
192 if not validate_certificate:
193 adapter = InsecureAppEngineAdapter
194
195 sessions.HTTPAdapter = adapter
196 adapters.HTTPAdapter = adapter
197
198
199 def _check_version():
200 if gaecontrib is None:
201 raise exc.VersionMismatchError(
202 "The toolbelt requires at least Requests 2.10.0 to be "
203 "installed. Version {0} was found instead.".format(
204 requests.__version__
205 )
206 )