cavisson-pythonagent 0.0.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (180) hide show
  1. cavisson_pythonagent-0.0.1.dist-info/METADATA +32 -0
  2. cavisson_pythonagent-0.0.1.dist-info/RECORD +180 -0
  3. cavisson_pythonagent-0.0.1.dist-info/WHEEL +5 -0
  4. cavisson_pythonagent-0.0.1.dist-info/licenses/LICENSE +19 -0
  5. cavisson_pythonagent-0.0.1.dist-info/top_level.txt +1 -0
  6. pythonagent/__init__.py +22 -0
  7. pythonagent/agent/__init__.py +219 -0
  8. pythonagent/agent/internal/__init__.py +1 -0
  9. pythonagent/agent/internal/agent.py +1651 -0
  10. pythonagent/agent/internal/framesinfo.py +152 -0
  11. pythonagent/agent/internal/heap_dump.py +39 -0
  12. pythonagent/agent/internal/intercept_module.py +70 -0
  13. pythonagent/agent/internal/logs.py +122 -0
  14. pythonagent/agent/internal/metadata/__init__.py +0 -0
  15. pythonagent/agent/internal/metadata/agent_meta_data.py +276 -0
  16. pythonagent/agent/internal/proc_compat.py +75 -0
  17. pythonagent/agent/internal/profile.py +47 -0
  18. pythonagent/agent/internal/provider.py +83 -0
  19. pythonagent/agent/internal/thread_dump.py +85 -0
  20. pythonagent/agent/internal/udp.py +245 -0
  21. pythonagent/agent/internal/udp_message.py +800 -0
  22. pythonagent/agent/probes/Instrumentation/__init__.py +340 -0
  23. pythonagent/agent/probes/Instrumentation/find.py +243 -0
  24. pythonagent/agent/probes/Instrumentation/module_version_resolver.py +155 -0
  25. pythonagent/agent/probes/Instrumentation/new_parser.py +64 -0
  26. pythonagent/agent/probes/Instrumentation/parser.py +129 -0
  27. pythonagent/agent/probes/__init__.py +219 -0
  28. pythonagent/agent/probes/base.py +303 -0
  29. pythonagent/agent/probes/cache/__init__.py +51 -0
  30. pythonagent/agent/probes/cache/redis.py +119 -0
  31. pythonagent/agent/probes/cache/redis_asyncio.py +83 -0
  32. pythonagent/agent/probes/coroutines/__init__.py +1 -0
  33. pythonagent/agent/probes/coroutines/asyncio.py +63 -0
  34. pythonagent/agent/probes/elasticdb/__init__.py +7 -0
  35. pythonagent/agent/probes/elasticdb/aelastic.py +54 -0
  36. pythonagent/agent/probes/frameworks/__init__.py +27 -0
  37. pythonagent/agent/probes/frameworks/agentprofiler.py +105 -0
  38. pythonagent/agent/probes/frameworks/aiohttp_web.py +155 -0
  39. pythonagent/agent/probes/frameworks/aisess.py +151 -0
  40. pythonagent/agent/probes/frameworks/asgi.py +340 -0
  41. pythonagent/agent/probes/frameworks/bottle.py +27 -0
  42. pythonagent/agent/probes/frameworks/cherry.py +25 -0
  43. pythonagent/agent/probes/frameworks/django.py +128 -0
  44. pythonagent/agent/probes/frameworks/falcon.py +21 -0
  45. pythonagent/agent/probes/frameworks/fastapi.py +35 -0
  46. pythonagent/agent/probes/frameworks/flask.py +30 -0
  47. pythonagent/agent/probes/frameworks/pyramid.py +56 -0
  48. pythonagent/agent/probes/frameworks/test.py +108 -0
  49. pythonagent/agent/probes/frameworks/tornado_async_web.py +117 -0
  50. pythonagent/agent/probes/frameworks/tornado_web.py +133 -0
  51. pythonagent/agent/probes/frameworks/wsgi.py +353 -0
  52. pythonagent/agent/probes/grpc/__init__.py +76 -0
  53. pythonagent/agent/probes/grpc/client_interceptor.py +132 -0
  54. pythonagent/agent/probes/grpc/server_interceptor.py +129 -0
  55. pythonagent/agent/probes/havoc/__init__.py +0 -0
  56. pythonagent/agent/probes/havoc/custom_memory_stress.py +186 -0
  57. pythonagent/agent/probes/havoc/custom_thread_stress.py +187 -0
  58. pythonagent/agent/probes/havoc/havoc_constants.py +218 -0
  59. pythonagent/agent/probes/havoc/havoc_manager.py +981 -0
  60. pythonagent/agent/probes/http/__init__.py +49 -0
  61. pythonagent/agent/probes/http/aiohttp_client.py +59 -0
  62. pythonagent/agent/probes/http/boto.py +12 -0
  63. pythonagent/agent/probes/http/httplib.py +110 -0
  64. pythonagent/agent/probes/http/httpx_client.py +116 -0
  65. pythonagent/agent/probes/http/requests.py +15 -0
  66. pythonagent/agent/probes/http/tornado_httpclient.py +85 -0
  67. pythonagent/agent/probes/http/urllib3.py +16 -0
  68. pythonagent/agent/probes/langchain/__init__.py +21 -0
  69. pythonagent/agent/probes/langchain/base_tool.py +95 -0
  70. pythonagent/agent/probes/langchain/langchain_community.py +136 -0
  71. pythonagent/agent/probes/langchain/langchain_core.py +32 -0
  72. pythonagent/agent/probes/langchain/langchain_openai.py +110 -0
  73. pythonagent/agent/probes/logging/__init__.py +106 -0
  74. pythonagent/agent/probes/message_brokers/__init__.py +4 -0
  75. pythonagent/agent/probes/message_brokers/pika.py +126 -0
  76. pythonagent/agent/probes/mongodb/__init__.py +6 -0
  77. pythonagent/agent/probes/mongodb/pymongo.py +286 -0
  78. pythonagent/agent/probes/openai/__init__.py +3 -0
  79. pythonagent/agent/probes/openai/openai.py +797 -0
  80. pythonagent/agent/probes/span.py +101 -0
  81. pythonagent/agent/probes/sql/__init__.py +13 -0
  82. pythonagent/agent/probes/sql/botocores3.py +51 -0
  83. pythonagent/agent/probes/sql/dbapi.py +285 -0
  84. pythonagent/agent/probes/sql/dynamodb.py +90 -0
  85. pythonagent/agent/probes/sql/mysql_connector.py +24 -0
  86. pythonagent/agent/probes/sql/mysql_connector_cext.py +24 -0
  87. pythonagent/agent/probes/sql/mysqldb.py +43 -0
  88. pythonagent/agent/probes/sql/psycopg2.py +174 -0
  89. pythonagent/agent/probes/sql/pymysql.py +25 -0
  90. pythonagent/bootstrap/__init__.py +0 -0
  91. pythonagent/bootstrap/cav_gunicorn.py +26 -0
  92. pythonagent/bootstrap/cavagent_lambda_wrapper.py +291 -0
  93. pythonagent/bootstrap/run.py +47 -0
  94. pythonagent/bootstrap/sitecustomize.py +287 -0
  95. pythonagent/cavisson/netdiagnostics/CavAgent/instrumentationprofile.json +26 -0
  96. pythonagent/cavisson/netdiagnostics/CavAgent/interceptor_points.txt +29 -0
  97. pythonagent/cavisson/netdiagnostics/python/CavAgent/instrumentationprofile.json +42 -0
  98. pythonagent/cavisson/netdiagnostics/python/CavAgent/interceptor_points.txt +29 -0
  99. pythonagent/cavisson/netdiagnostics/python/config/ndsettings.conf +6 -0
  100. pythonagent/config.py +279 -0
  101. pythonagent/find.py +72 -0
  102. pythonagent/find_mod_cls_name.py +54 -0
  103. pythonagent/lang.py +131 -0
  104. pythonagent/lib.py +91 -0
  105. pythonagent/main/__init__.py +0 -0
  106. pythonagent/main/pytrace/__init__.py +79 -0
  107. pythonagent/main/pytrace/commands/__init__.py +0 -0
  108. pythonagent/main/pytrace/commands/auto_discovery.py +25 -0
  109. pythonagent/main/pytrace/commands/run.py +401 -0
  110. pythonagent/main/pytrace/pytrace.py +133 -0
  111. pythonagent/main/wsgi.py +6 -0
  112. pythonagent/main.py +27 -0
  113. pythonagent/run.py +46 -0
  114. pythonagent/sqins.py +8 -0
  115. pythonagent/test.py +73 -0
  116. pythonagent/utils.py +168 -0
  117. pythonagent/vendor/__init__.py +0 -0
  118. pythonagent/vendor/pympler/__init__.py +1 -0
  119. pythonagent/vendor/pympler/asizeof.py +2810 -0
  120. pythonagent/vendor/pympler/charts.py +62 -0
  121. pythonagent/vendor/pympler/classtracker.py +590 -0
  122. pythonagent/vendor/pympler/classtracker_stats.py +780 -0
  123. pythonagent/vendor/pympler/garbagegraph.py +80 -0
  124. pythonagent/vendor/pympler/mprofile.py +97 -0
  125. pythonagent/vendor/pympler/muppy.py +275 -0
  126. pythonagent/vendor/pympler/panels.py +115 -0
  127. pythonagent/vendor/pympler/process.py +238 -0
  128. pythonagent/vendor/pympler/py.typed +0 -0
  129. pythonagent/vendor/pympler/refbrowser.py +451 -0
  130. pythonagent/vendor/pympler/refgraph.py +350 -0
  131. pythonagent/vendor/pympler/summary.py +321 -0
  132. pythonagent/vendor/pympler/tracker.py +267 -0
  133. pythonagent/vendor/pympler/util/__init__.py +0 -0
  134. pythonagent/vendor/pympler/util/bottle.py +3809 -0
  135. pythonagent/vendor/pympler/util/compat.py +23 -0
  136. pythonagent/vendor/pympler/util/stringutils.py +77 -0
  137. pythonagent/vendor/pympler/web.py +346 -0
  138. pythonagent/vendor/werkzeug/__init__.py +20 -0
  139. pythonagent/vendor/werkzeug/_compat.py +228 -0
  140. pythonagent/vendor/werkzeug/_internal.py +473 -0
  141. pythonagent/vendor/werkzeug/_reloader.py +341 -0
  142. pythonagent/vendor/werkzeug/datastructures.py +3120 -0
  143. pythonagent/vendor/werkzeug/debug/__init__.py +498 -0
  144. pythonagent/vendor/werkzeug/debug/console.py +218 -0
  145. pythonagent/vendor/werkzeug/debug/repr.py +297 -0
  146. pythonagent/vendor/werkzeug/debug/tbtools.py +628 -0
  147. pythonagent/vendor/werkzeug/exceptions.py +829 -0
  148. pythonagent/vendor/werkzeug/filesystem.py +64 -0
  149. pythonagent/vendor/werkzeug/formparser.py +584 -0
  150. pythonagent/vendor/werkzeug/http.py +1307 -0
  151. pythonagent/vendor/werkzeug/local.py +420 -0
  152. pythonagent/vendor/werkzeug/middleware/__init__.py +25 -0
  153. pythonagent/vendor/werkzeug/middleware/dispatcher.py +66 -0
  154. pythonagent/vendor/werkzeug/middleware/http_proxy.py +219 -0
  155. pythonagent/vendor/werkzeug/middleware/lint.py +408 -0
  156. pythonagent/vendor/werkzeug/middleware/profiler.py +132 -0
  157. pythonagent/vendor/werkzeug/middleware/proxy_fix.py +169 -0
  158. pythonagent/vendor/werkzeug/middleware/shared_data.py +293 -0
  159. pythonagent/vendor/werkzeug/posixemulation.py +117 -0
  160. pythonagent/vendor/werkzeug/routing.py +2210 -0
  161. pythonagent/vendor/werkzeug/security.py +249 -0
  162. pythonagent/vendor/werkzeug/serving.py +1117 -0
  163. pythonagent/vendor/werkzeug/test.py +1123 -0
  164. pythonagent/vendor/werkzeug/testapp.py +241 -0
  165. pythonagent/vendor/werkzeug/urls.py +1138 -0
  166. pythonagent/vendor/werkzeug/useragents.py +202 -0
  167. pythonagent/vendor/werkzeug/utils.py +778 -0
  168. pythonagent/vendor/werkzeug/wrappers/__init__.py +36 -0
  169. pythonagent/vendor/werkzeug/wrappers/accept.py +50 -0
  170. pythonagent/vendor/werkzeug/wrappers/auth.py +33 -0
  171. pythonagent/vendor/werkzeug/wrappers/base_request.py +673 -0
  172. pythonagent/vendor/werkzeug/wrappers/base_response.py +700 -0
  173. pythonagent/vendor/werkzeug/wrappers/common_descriptors.py +341 -0
  174. pythonagent/vendor/werkzeug/wrappers/cors.py +100 -0
  175. pythonagent/vendor/werkzeug/wrappers/etag.py +304 -0
  176. pythonagent/vendor/werkzeug/wrappers/json.py +145 -0
  177. pythonagent/vendor/werkzeug/wrappers/request.py +49 -0
  178. pythonagent/vendor/werkzeug/wrappers/response.py +84 -0
  179. pythonagent/vendor/werkzeug/wrappers/user_agent.py +14 -0
  180. pythonagent/vendor/werkzeug/wsgi.py +1000 -0
@@ -0,0 +1,673 @@
1
+ from functools import update_wrapper
2
+ from io import BytesIO
3
+
4
+ from .._compat import to_native
5
+ from .._compat import to_unicode
6
+ from .._compat import wsgi_decoding_dance
7
+ from .._compat import wsgi_get_bytes
8
+ from ..datastructures import CombinedMultiDict
9
+ from ..datastructures import EnvironHeaders
10
+ from ..datastructures import ImmutableList
11
+ from ..datastructures import ImmutableMultiDict
12
+ from ..datastructures import iter_multi_items
13
+ from ..datastructures import MultiDict
14
+ from ..formparser import default_stream_factory
15
+ from ..formparser import FormDataParser
16
+ from ..http import parse_cookie
17
+ from ..http import parse_list_header
18
+ from ..http import parse_options_header
19
+ from ..urls import url_decode
20
+ from ..utils import cached_property
21
+ from ..utils import environ_property
22
+ from ..wsgi import get_content_length
23
+ from ..wsgi import get_current_url
24
+ from ..wsgi import get_host
25
+ from ..wsgi import get_input_stream
26
+
27
+
28
+ class BaseRequest(object):
29
+ """Very basic request object. This does not implement advanced stuff like
30
+ entity tag parsing or cache controls. The request object is created with
31
+ the WSGI environment as first argument and will add itself to the WSGI
32
+ environment as ``'werkzeug.request'`` unless it's created with
33
+ `populate_request` set to False.
34
+
35
+ There are a couple of mixins available that add additional functionality
36
+ to the request object, there is also a class called `Request` which
37
+ subclasses `BaseRequest` and all the important mixins.
38
+
39
+ It's a good idea to create a custom subclass of the :class:`BaseRequest`
40
+ and add missing functionality either via mixins or direct implementation.
41
+ Here an example for such subclasses::
42
+
43
+ from pythonagent.vendor.werkzeug.wrappers import BaseRequest, ETagRequestMixin
44
+
45
+ class Request(BaseRequest, ETagRequestMixin):
46
+ pass
47
+
48
+ Request objects are **read only**. As of 0.5 modifications are not
49
+ allowed in any place. Unlike the lower level parsing functions the
50
+ request object will use immutable objects everywhere possible.
51
+
52
+ Per default the request object will assume all the text data is `utf-8`
53
+ encoded. Please refer to :doc:`the unicode chapter </unicode>` for more
54
+ details about customizing the behavior.
55
+
56
+ Per default the request object will be added to the WSGI
57
+ environment as `werkzeug.request` to support the debugging system.
58
+ If you don't want that, set `populate_request` to `False`.
59
+
60
+ If `shallow` is `True` the environment is initialized as shallow
61
+ object around the environ. Every operation that would modify the
62
+ environ in any way (such as consuming form data) raises an exception
63
+ unless the `shallow` attribute is explicitly set to `False`. This
64
+ is useful for middlewares where you don't want to consume the form
65
+ data by accident. A shallow request is not populated to the WSGI
66
+ environment.
67
+
68
+ .. versionchanged:: 0.5
69
+ read-only mode was enforced by using immutables classes for all
70
+ data.
71
+ """
72
+
73
+ #: the charset for the request, defaults to utf-8
74
+ charset = "utf-8"
75
+
76
+ #: the error handling procedure for errors, defaults to 'replace'
77
+ encoding_errors = "replace"
78
+
79
+ #: the maximum content length. This is forwarded to the form data
80
+ #: parsing function (:func:`parse_form_data`). When set and the
81
+ #: :attr:`form` or :attr:`files` attribute is accessed and the
82
+ #: parsing fails because more than the specified value is transmitted
83
+ #: a :exc:`~werkzeug.exceptions.RequestEntityTooLarge` exception is raised.
84
+ #:
85
+ #: Have a look at :ref:`dealing-with-request-data` for more details.
86
+ #:
87
+ #: .. versionadded:: 0.5
88
+ max_content_length = None
89
+
90
+ #: the maximum form field size. This is forwarded to the form data
91
+ #: parsing function (:func:`parse_form_data`). When set and the
92
+ #: :attr:`form` or :attr:`files` attribute is accessed and the
93
+ #: data in memory for post data is longer than the specified value a
94
+ #: :exc:`~werkzeug.exceptions.RequestEntityTooLarge` exception is raised.
95
+ #:
96
+ #: Have a look at :ref:`dealing-with-request-data` for more details.
97
+ #:
98
+ #: .. versionadded:: 0.5
99
+ max_form_memory_size = None
100
+
101
+ #: the class to use for `args` and `form`. The default is an
102
+ #: :class:`~werkzeug.datastructures.ImmutableMultiDict` which supports
103
+ #: multiple values per key. alternatively it makes sense to use an
104
+ #: :class:`~werkzeug.datastructures.ImmutableOrderedMultiDict` which
105
+ #: preserves order or a :class:`~werkzeug.datastructures.ImmutableDict`
106
+ #: which is the fastest but only remembers the last key. It is also
107
+ #: possible to use mutable structures, but this is not recommended.
108
+ #:
109
+ #: .. versionadded:: 0.6
110
+ parameter_storage_class = ImmutableMultiDict
111
+
112
+ #: the type to be used for list values from the incoming WSGI environment.
113
+ #: By default an :class:`~werkzeug.datastructures.ImmutableList` is used
114
+ #: (for example for :attr:`access_list`).
115
+ #:
116
+ #: .. versionadded:: 0.6
117
+ list_storage_class = ImmutableList
118
+
119
+ #: The type to be used for dict values from the incoming WSGI
120
+ #: environment. (For example for :attr:`cookies`.) By default an
121
+ #: :class:`~werkzeug.datastructures.ImmutableMultiDict` is used.
122
+ #:
123
+ #: .. versionchanged:: 1.0.0
124
+ #: Changed to ``ImmutableMultiDict`` to support multiple values.
125
+ #:
126
+ #: .. versionadded:: 0.6
127
+ dict_storage_class = ImmutableMultiDict
128
+
129
+ #: The form data parser that shoud be used. Can be replaced to customize
130
+ #: the form date parsing.
131
+ form_data_parser_class = FormDataParser
132
+
133
+ #: Optionally a list of hosts that is trusted by this request. By default
134
+ #: all hosts are trusted which means that whatever the client sends the
135
+ #: host is will be accepted.
136
+ #:
137
+ #: Because `Host` and `X-Forwarded-Host` headers can be set to any value by
138
+ #: a malicious client, it is recommended to either set this property or
139
+ #: implement similar validation in the proxy (if application is being run
140
+ #: behind one).
141
+ #:
142
+ #: .. versionadded:: 0.9
143
+ trusted_hosts = None
144
+
145
+ #: Indicates whether the data descriptor should be allowed to read and
146
+ #: buffer up the input stream. By default it's enabled.
147
+ #:
148
+ #: .. versionadded:: 0.9
149
+ disable_data_descriptor = False
150
+
151
+ def __init__(self, environ, populate_request=True, shallow=False):
152
+ self.environ = environ
153
+ if populate_request and not shallow:
154
+ self.environ["werkzeug.request"] = self
155
+ self.shallow = shallow
156
+
157
+ def __repr__(self):
158
+ # make sure the __repr__ even works if the request was created
159
+ # from an invalid WSGI environment. If we display the request
160
+ # in a debug session we don't want the repr to blow up.
161
+ args = []
162
+ try:
163
+ args.append("'%s'" % to_native(self.url, self.url_charset))
164
+ args.append("[%s]" % self.method)
165
+ except Exception:
166
+ args.append("(invalid WSGI environ)")
167
+
168
+ return "<%s %s>" % (self.__class__.__name__, " ".join(args))
169
+
170
+ @property
171
+ def url_charset(self):
172
+ """The charset that is assumed for URLs. Defaults to the value
173
+ of :attr:`charset`.
174
+
175
+ .. versionadded:: 0.6
176
+ """
177
+ return self.charset
178
+
179
+ @classmethod
180
+ def from_values(cls, *args, **kwargs):
181
+ """Create a new request object based on the values provided. If
182
+ environ is given missing values are filled from there. This method is
183
+ useful for small scripts when you need to simulate a request from an URL.
184
+ Do not use this method for unittesting, there is a full featured client
185
+ object (:class:`Client`) that allows to create multipart requests,
186
+ support for cookies etc.
187
+
188
+ This accepts the same options as the
189
+ :class:`~werkzeug.test.EnvironBuilder`.
190
+
191
+ .. versionchanged:: 0.5
192
+ This method now accepts the same arguments as
193
+ :class:`~werkzeug.test.EnvironBuilder`. Because of this the
194
+ `environ` parameter is now called `environ_overrides`.
195
+
196
+ :return: request object
197
+ """
198
+ from ..test import EnvironBuilder
199
+
200
+ charset = kwargs.pop("charset", cls.charset)
201
+ kwargs["charset"] = charset
202
+ builder = EnvironBuilder(*args, **kwargs)
203
+ try:
204
+ return builder.get_request(cls)
205
+ finally:
206
+ builder.close()
207
+
208
+ @classmethod
209
+ def application(cls, f):
210
+ """Decorate a function as responder that accepts the request as
211
+ the last argument. This works like the :func:`responder`
212
+ decorator but the function is passed the request object as the
213
+ last argument and the request object will be closed
214
+ automatically::
215
+
216
+ @Request.application
217
+ def my_wsgi_app(request):
218
+ return Response('Hello World!')
219
+
220
+ As of Werkzeug 0.14 HTTP exceptions are automatically caught and
221
+ converted to responses instead of failing.
222
+
223
+ :param f: the WSGI callable to decorate
224
+ :return: a new WSGI callable
225
+ """
226
+ #: return a callable that wraps the -2nd argument with the request
227
+ #: and calls the function with all the arguments up to that one and
228
+ #: the request. The return value is then called with the latest
229
+ #: two arguments. This makes it possible to use this decorator for
230
+ #: both standalone WSGI functions as well as bound methods and
231
+ #: partially applied functions.
232
+ from ..exceptions import HTTPException
233
+
234
+ def application(*args):
235
+ request = cls(args[-2])
236
+ with request:
237
+ try:
238
+ resp = f(*args[:-2] + (request,))
239
+ except HTTPException as e:
240
+ resp = e.get_response(args[-2])
241
+ return resp(*args[-2:])
242
+
243
+ return update_wrapper(application, f)
244
+
245
+ def _get_file_stream(
246
+ self, total_content_length, content_type, filename=None, content_length=None
247
+ ):
248
+ """Called to get a stream for the file upload.
249
+
250
+ This must provide a file-like class with `read()`, `readline()`
251
+ and `seek()` methods that is both writeable and readable.
252
+
253
+ The default implementation returns a temporary file if the total
254
+ content length is higher than 500KB. Because many browsers do not
255
+ provide a content length for the files only the total content
256
+ length matters.
257
+
258
+ :param total_content_length: the total content length of all the
259
+ data in the request combined. This value
260
+ is guaranteed to be there.
261
+ :param content_type: the mimetype of the uploaded file.
262
+ :param filename: the filename of the uploaded file. May be `None`.
263
+ :param content_length: the length of this file. This value is usually
264
+ not provided because webbrowsers do not provide
265
+ this value.
266
+ """
267
+ return default_stream_factory(
268
+ total_content_length=total_content_length,
269
+ filename=filename,
270
+ content_type=content_type,
271
+ content_length=content_length,
272
+ )
273
+
274
+ @property
275
+ def want_form_data_parsed(self):
276
+ """Returns True if the request method carries content. As of
277
+ Werkzeug 0.9 this will be the case if a content type is transmitted.
278
+
279
+ .. versionadded:: 0.8
280
+ """
281
+ return bool(self.environ.get("CONTENT_TYPE"))
282
+
283
+ def make_form_data_parser(self):
284
+ """Creates the form data parser. Instantiates the
285
+ :attr:`form_data_parser_class` with some parameters.
286
+
287
+ .. versionadded:: 0.8
288
+ """
289
+ return self.form_data_parser_class(
290
+ self._get_file_stream,
291
+ self.charset,
292
+ self.encoding_errors,
293
+ self.max_form_memory_size,
294
+ self.max_content_length,
295
+ self.parameter_storage_class,
296
+ )
297
+
298
+ def _load_form_data(self):
299
+ """Method used internally to retrieve submitted data. After calling
300
+ this sets `form` and `files` on the request object to multi dicts
301
+ filled with the incoming form data. As a matter of fact the input
302
+ stream will be empty afterwards. You can also call this method to
303
+ force the parsing of the form data.
304
+
305
+ .. versionadded:: 0.8
306
+ """
307
+ # abort early if we have already consumed the stream
308
+ if "form" in self.__dict__:
309
+ return
310
+
311
+ _assert_not_shallow(self)
312
+
313
+ if self.want_form_data_parsed:
314
+ content_type = self.environ.get("CONTENT_TYPE", "")
315
+ content_length = get_content_length(self.environ)
316
+ mimetype, options = parse_options_header(content_type)
317
+ parser = self.make_form_data_parser()
318
+ data = parser.parse(
319
+ self._get_stream_for_parsing(), mimetype, content_length, options
320
+ )
321
+ else:
322
+ data = (
323
+ self.stream,
324
+ self.parameter_storage_class(),
325
+ self.parameter_storage_class(),
326
+ )
327
+
328
+ # inject the values into the instance dict so that we bypass
329
+ # our cached_property non-data descriptor.
330
+ d = self.__dict__
331
+ d["stream"], d["form"], d["files"] = data
332
+
333
+ def _get_stream_for_parsing(self):
334
+ """This is the same as accessing :attr:`stream` with the difference
335
+ that if it finds cached data from calling :meth:`get_data` first it
336
+ will create a new stream out of the cached data.
337
+
338
+ .. versionadded:: 0.9.3
339
+ """
340
+ cached_data = getattr(self, "_cached_data", None)
341
+ if cached_data is not None:
342
+ return BytesIO(cached_data)
343
+ return self.stream
344
+
345
+ def close(self):
346
+ """Closes associated resources of this request object. This
347
+ closes all file handles explicitly. You can also use the request
348
+ object in a with statement which will automatically close it.
349
+
350
+ .. versionadded:: 0.9
351
+ """
352
+ files = self.__dict__.get("files")
353
+ for _key, value in iter_multi_items(files or ()):
354
+ value.close()
355
+
356
+ def __enter__(self):
357
+ return self
358
+
359
+ def __exit__(self, exc_type, exc_value, tb):
360
+ self.close()
361
+
362
+ @cached_property
363
+ def stream(self):
364
+ """
365
+ If the incoming form data was not encoded with a known mimetype
366
+ the data is stored unmodified in this stream for consumption. Most
367
+ of the time it is a better idea to use :attr:`data` which will give
368
+ you that data as a string. The stream only returns the data once.
369
+
370
+ Unlike :attr:`input_stream` this stream is properly guarded that you
371
+ can't accidentally read past the length of the input. Werkzeug will
372
+ internally always refer to this stream to read data which makes it
373
+ possible to wrap this object with a stream that does filtering.
374
+
375
+ .. versionchanged:: 0.9
376
+ This stream is now always available but might be consumed by the
377
+ form parser later on. Previously the stream was only set if no
378
+ parsing happened.
379
+ """
380
+ _assert_not_shallow(self)
381
+ return get_input_stream(self.environ)
382
+
383
+ input_stream = environ_property(
384
+ "wsgi.input",
385
+ """The WSGI input stream.
386
+
387
+ In general it's a bad idea to use this one because you can
388
+ easily read past the boundary. Use the :attr:`stream`
389
+ instead.""",
390
+ )
391
+
392
+ @cached_property
393
+ def args(self):
394
+ """The parsed URL parameters (the part in the URL after the question
395
+ mark).
396
+
397
+ By default an
398
+ :class:`~werkzeug.datastructures.ImmutableMultiDict`
399
+ is returned from this function. This can be changed by setting
400
+ :attr:`parameter_storage_class` to a different type. This might
401
+ be necessary if the order of the form data is important.
402
+ """
403
+ return url_decode(
404
+ wsgi_get_bytes(self.environ.get("QUERY_STRING", "")),
405
+ self.url_charset,
406
+ errors=self.encoding_errors,
407
+ cls=self.parameter_storage_class,
408
+ )
409
+
410
+ @cached_property
411
+ def data(self):
412
+ """
413
+ Contains the incoming request data as string in case it came with
414
+ a mimetype Werkzeug does not handle.
415
+ """
416
+
417
+ if self.disable_data_descriptor:
418
+ raise AttributeError("data descriptor is disabled")
419
+ # XXX: this should eventually be deprecated.
420
+
421
+ # We trigger form data parsing first which means that the descriptor
422
+ # will not cache the data that would otherwise be .form or .files
423
+ # data. This restores the behavior that was there in Werkzeug
424
+ # before 0.9. New code should use :meth:`get_data` explicitly as
425
+ # this will make behavior explicit.
426
+ return self.get_data(parse_form_data=True)
427
+
428
+ def get_data(self, cache=True, as_text=False, parse_form_data=False):
429
+ """This reads the buffered incoming data from the client into one
430
+ bytestring. By default this is cached but that behavior can be
431
+ changed by setting `cache` to `False`.
432
+
433
+ Usually it's a bad idea to call this method without checking the
434
+ content length first as a client could send dozens of megabytes or more
435
+ to cause memory problems on the server.
436
+
437
+ Note that if the form data was already parsed this method will not
438
+ return anything as form data parsing does not cache the data like
439
+ this method does. To implicitly invoke form data parsing function
440
+ set `parse_form_data` to `True`. When this is done the return value
441
+ of this method will be an empty string if the form parser handles
442
+ the data. This generally is not necessary as if the whole data is
443
+ cached (which is the default) the form parser will used the cached
444
+ data to parse the form data. Please be generally aware of checking
445
+ the content length first in any case before calling this method
446
+ to avoid exhausting server memory.
447
+
448
+ If `as_text` is set to `True` the return value will be a decoded
449
+ unicode string.
450
+
451
+ .. versionadded:: 0.9
452
+ """
453
+ rv = getattr(self, "_cached_data", None)
454
+ if rv is None:
455
+ if parse_form_data:
456
+ self._load_form_data()
457
+ rv = self.stream.read()
458
+ if cache:
459
+ self._cached_data = rv
460
+ if as_text:
461
+ rv = rv.decode(self.charset, self.encoding_errors)
462
+ return rv
463
+
464
+ @cached_property
465
+ def form(self):
466
+ """The form parameters. By default an
467
+ :class:`~werkzeug.datastructures.ImmutableMultiDict`
468
+ is returned from this function. This can be changed by setting
469
+ :attr:`parameter_storage_class` to a different type. This might
470
+ be necessary if the order of the form data is important.
471
+
472
+ Please keep in mind that file uploads will not end up here, but instead
473
+ in the :attr:`files` attribute.
474
+
475
+ .. versionchanged:: 0.9
476
+
477
+ Previous to Werkzeug 0.9 this would only contain form data for POST
478
+ and PUT requests.
479
+ """
480
+ self._load_form_data()
481
+ return self.form
482
+
483
+ @cached_property
484
+ def values(self):
485
+ """A :class:`werkzeug.datastructures.CombinedMultiDict` that combines
486
+ :attr:`args` and :attr:`form`."""
487
+ args = []
488
+ for d in self.args, self.form:
489
+ if not isinstance(d, MultiDict):
490
+ d = MultiDict(d)
491
+ args.append(d)
492
+ return CombinedMultiDict(args)
493
+
494
+ @cached_property
495
+ def files(self):
496
+ """:class:`~werkzeug.datastructures.MultiDict` object containing
497
+ all uploaded files. Each key in :attr:`files` is the name from the
498
+ ``<input type="file" name="">``. Each value in :attr:`files` is a
499
+ Werkzeug :class:`~werkzeug.datastructures.FileStorage` object.
500
+
501
+ It basically behaves like a standard file object you know from Python,
502
+ with the difference that it also has a
503
+ :meth:`~werkzeug.datastructures.FileStorage.save` function that can
504
+ store the file on the filesystem.
505
+
506
+ Note that :attr:`files` will only contain data if the request method was
507
+ POST, PUT or PATCH and the ``<form>`` that posted to the request had
508
+ ``enctype="multipart/form-data"``. It will be empty otherwise.
509
+
510
+ See the :class:`~werkzeug.datastructures.MultiDict` /
511
+ :class:`~werkzeug.datastructures.FileStorage` documentation for
512
+ more details about the used data structure.
513
+ """
514
+ self._load_form_data()
515
+ return self.files
516
+
517
+ @cached_property
518
+ def cookies(self):
519
+ """A :class:`dict` with the contents of all cookies transmitted with
520
+ the request."""
521
+ return parse_cookie(
522
+ self.environ,
523
+ self.charset,
524
+ self.encoding_errors,
525
+ cls=self.dict_storage_class,
526
+ )
527
+
528
+ @cached_property
529
+ def headers(self):
530
+ """The headers from the WSGI environ as immutable
531
+ :class:`~werkzeug.datastructures.EnvironHeaders`.
532
+ """
533
+ return EnvironHeaders(self.environ)
534
+
535
+ @cached_property
536
+ def path(self):
537
+ """Requested path as unicode. This works a bit like the regular path
538
+ info in the WSGI environment but will always include a leading slash,
539
+ even if the URL root is accessed.
540
+ """
541
+ raw_path = wsgi_decoding_dance(
542
+ self.environ.get("PATH_INFO") or "", self.charset, self.encoding_errors
543
+ )
544
+ return "/" + raw_path.lstrip("/")
545
+
546
+ @cached_property
547
+ def full_path(self):
548
+ """Requested path as unicode, including the query string."""
549
+ return self.path + u"?" + to_unicode(self.query_string, self.url_charset)
550
+
551
+ @cached_property
552
+ def script_root(self):
553
+ """The root path of the script without the trailing slash."""
554
+ raw_path = wsgi_decoding_dance(
555
+ self.environ.get("SCRIPT_NAME") or "", self.charset, self.encoding_errors
556
+ )
557
+ return raw_path.rstrip("/")
558
+
559
+ @cached_property
560
+ def url(self):
561
+ """The reconstructed current URL as IRI.
562
+ See also: :attr:`trusted_hosts`.
563
+ """
564
+ return get_current_url(self.environ, trusted_hosts=self.trusted_hosts)
565
+
566
+ @cached_property
567
+ def base_url(self):
568
+ """Like :attr:`url` but without the querystring
569
+ See also: :attr:`trusted_hosts`.
570
+ """
571
+ return get_current_url(
572
+ self.environ, strip_querystring=True, trusted_hosts=self.trusted_hosts
573
+ )
574
+
575
+ @cached_property
576
+ def url_root(self):
577
+ """The full URL root (with hostname), this is the application
578
+ root as IRI.
579
+ See also: :attr:`trusted_hosts`.
580
+ """
581
+ return get_current_url(self.environ, True, trusted_hosts=self.trusted_hosts)
582
+
583
+ @cached_property
584
+ def host_url(self):
585
+ """Just the host with scheme as IRI.
586
+ See also: :attr:`trusted_hosts`.
587
+ """
588
+ return get_current_url(
589
+ self.environ, host_only=True, trusted_hosts=self.trusted_hosts
590
+ )
591
+
592
+ @cached_property
593
+ def host(self):
594
+ """Just the host including the port if available.
595
+ See also: :attr:`trusted_hosts`.
596
+ """
597
+ return get_host(self.environ, trusted_hosts=self.trusted_hosts)
598
+
599
+ query_string = environ_property(
600
+ "QUERY_STRING",
601
+ "",
602
+ read_only=True,
603
+ load_func=wsgi_get_bytes,
604
+ doc="The URL parameters as raw bytestring.",
605
+ )
606
+ method = environ_property(
607
+ "REQUEST_METHOD",
608
+ "GET",
609
+ read_only=True,
610
+ load_func=lambda x: x.upper(),
611
+ doc="The request method. (For example ``'GET'`` or ``'POST'``).",
612
+ )
613
+
614
+ @cached_property
615
+ def access_route(self):
616
+ """If a forwarded header exists this is a list of all ip addresses
617
+ from the client ip to the last proxy server.
618
+ """
619
+ if "HTTP_X_FORWARDED_FOR" in self.environ:
620
+ return self.list_storage_class(
621
+ parse_list_header(self.environ["HTTP_X_FORWARDED_FOR"])
622
+ )
623
+ elif "REMOTE_ADDR" in self.environ:
624
+ return self.list_storage_class([self.environ["REMOTE_ADDR"]])
625
+ return self.list_storage_class()
626
+
627
+ @property
628
+ def remote_addr(self):
629
+ """The remote address of the client."""
630
+ return self.environ.get("REMOTE_ADDR")
631
+
632
+ remote_user = environ_property(
633
+ "REMOTE_USER",
634
+ doc="""If the server supports user authentication, and the
635
+ script is protected, this attribute contains the username the
636
+ user has authenticated as.""",
637
+ )
638
+ scheme = environ_property(
639
+ "wsgi.url_scheme",
640
+ doc="""
641
+ URL scheme (http or https).
642
+
643
+ .. versionadded:: 0.7""",
644
+ )
645
+ is_secure = property(
646
+ lambda self: self.environ["wsgi.url_scheme"] == "https",
647
+ doc="`True` if the request is secure.",
648
+ )
649
+ is_multithread = environ_property(
650
+ "wsgi.multithread",
651
+ doc="""boolean that is `True` if the application is served by a
652
+ multithreaded WSGI server.""",
653
+ )
654
+ is_multiprocess = environ_property(
655
+ "wsgi.multiprocess",
656
+ doc="""boolean that is `True` if the application is served by a
657
+ WSGI server that spawns multiple processes.""",
658
+ )
659
+ is_run_once = environ_property(
660
+ "wsgi.run_once",
661
+ doc="""boolean that is `True` if the application will be
662
+ executed only once in a process lifetime. This is the case for
663
+ CGI for example, but it's not guaranteed that the execution only
664
+ happens one time.""",
665
+ )
666
+
667
+
668
+ def _assert_not_shallow(request):
669
+ if request.shallow:
670
+ raise RuntimeError(
671
+ "A shallow request tried to consume form data. If you really"
672
+ " want to do that, set `shallow` to False."
673
+ )