sentry-sdk 0.7.5__py2.py3-none-any.whl → 2.46.0__py2.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.
- sentry_sdk/__init__.py +48 -30
- sentry_sdk/_compat.py +74 -61
- sentry_sdk/_init_implementation.py +84 -0
- sentry_sdk/_log_batcher.py +172 -0
- sentry_sdk/_lru_cache.py +47 -0
- sentry_sdk/_metrics_batcher.py +167 -0
- sentry_sdk/_queue.py +289 -0
- sentry_sdk/_types.py +338 -0
- sentry_sdk/_werkzeug.py +98 -0
- sentry_sdk/ai/__init__.py +7 -0
- sentry_sdk/ai/monitoring.py +137 -0
- sentry_sdk/ai/utils.py +144 -0
- sentry_sdk/api.py +496 -80
- sentry_sdk/attachments.py +75 -0
- sentry_sdk/client.py +1023 -103
- sentry_sdk/consts.py +1438 -66
- sentry_sdk/crons/__init__.py +10 -0
- sentry_sdk/crons/api.py +62 -0
- sentry_sdk/crons/consts.py +4 -0
- sentry_sdk/crons/decorator.py +135 -0
- sentry_sdk/debug.py +15 -14
- sentry_sdk/envelope.py +369 -0
- sentry_sdk/feature_flags.py +71 -0
- sentry_sdk/hub.py +611 -280
- sentry_sdk/integrations/__init__.py +276 -49
- sentry_sdk/integrations/_asgi_common.py +108 -0
- sentry_sdk/integrations/_wsgi_common.py +180 -44
- sentry_sdk/integrations/aiohttp.py +291 -42
- sentry_sdk/integrations/anthropic.py +439 -0
- sentry_sdk/integrations/argv.py +9 -8
- sentry_sdk/integrations/ariadne.py +161 -0
- sentry_sdk/integrations/arq.py +247 -0
- sentry_sdk/integrations/asgi.py +341 -0
- sentry_sdk/integrations/asyncio.py +144 -0
- sentry_sdk/integrations/asyncpg.py +208 -0
- sentry_sdk/integrations/atexit.py +17 -10
- sentry_sdk/integrations/aws_lambda.py +377 -62
- sentry_sdk/integrations/beam.py +176 -0
- sentry_sdk/integrations/boto3.py +137 -0
- sentry_sdk/integrations/bottle.py +221 -0
- sentry_sdk/integrations/celery/__init__.py +529 -0
- sentry_sdk/integrations/celery/beat.py +293 -0
- sentry_sdk/integrations/celery/utils.py +43 -0
- sentry_sdk/integrations/chalice.py +134 -0
- sentry_sdk/integrations/clickhouse_driver.py +177 -0
- sentry_sdk/integrations/cloud_resource_context.py +280 -0
- sentry_sdk/integrations/cohere.py +274 -0
- sentry_sdk/integrations/dedupe.py +48 -14
- sentry_sdk/integrations/django/__init__.py +584 -191
- sentry_sdk/integrations/django/asgi.py +245 -0
- sentry_sdk/integrations/django/caching.py +204 -0
- sentry_sdk/integrations/django/middleware.py +187 -0
- sentry_sdk/integrations/django/signals_handlers.py +91 -0
- sentry_sdk/integrations/django/templates.py +79 -5
- sentry_sdk/integrations/django/transactions.py +49 -22
- sentry_sdk/integrations/django/views.py +96 -0
- sentry_sdk/integrations/dramatiq.py +226 -0
- sentry_sdk/integrations/excepthook.py +50 -13
- sentry_sdk/integrations/executing.py +67 -0
- sentry_sdk/integrations/falcon.py +272 -0
- sentry_sdk/integrations/fastapi.py +141 -0
- sentry_sdk/integrations/flask.py +142 -88
- sentry_sdk/integrations/gcp.py +239 -0
- sentry_sdk/integrations/gnu_backtrace.py +99 -0
- sentry_sdk/integrations/google_genai/__init__.py +301 -0
- sentry_sdk/integrations/google_genai/consts.py +16 -0
- sentry_sdk/integrations/google_genai/streaming.py +155 -0
- sentry_sdk/integrations/google_genai/utils.py +576 -0
- sentry_sdk/integrations/gql.py +162 -0
- sentry_sdk/integrations/graphene.py +151 -0
- sentry_sdk/integrations/grpc/__init__.py +168 -0
- sentry_sdk/integrations/grpc/aio/__init__.py +7 -0
- sentry_sdk/integrations/grpc/aio/client.py +95 -0
- sentry_sdk/integrations/grpc/aio/server.py +100 -0
- sentry_sdk/integrations/grpc/client.py +91 -0
- sentry_sdk/integrations/grpc/consts.py +1 -0
- sentry_sdk/integrations/grpc/server.py +66 -0
- sentry_sdk/integrations/httpx.py +178 -0
- sentry_sdk/integrations/huey.py +174 -0
- sentry_sdk/integrations/huggingface_hub.py +378 -0
- sentry_sdk/integrations/langchain.py +1132 -0
- sentry_sdk/integrations/langgraph.py +337 -0
- sentry_sdk/integrations/launchdarkly.py +61 -0
- sentry_sdk/integrations/litellm.py +287 -0
- sentry_sdk/integrations/litestar.py +315 -0
- sentry_sdk/integrations/logging.py +307 -96
- sentry_sdk/integrations/loguru.py +213 -0
- sentry_sdk/integrations/mcp.py +566 -0
- sentry_sdk/integrations/modules.py +14 -31
- sentry_sdk/integrations/openai.py +725 -0
- sentry_sdk/integrations/openai_agents/__init__.py +61 -0
- sentry_sdk/integrations/openai_agents/consts.py +1 -0
- sentry_sdk/integrations/openai_agents/patches/__init__.py +5 -0
- sentry_sdk/integrations/openai_agents/patches/agent_run.py +140 -0
- sentry_sdk/integrations/openai_agents/patches/error_tracing.py +77 -0
- sentry_sdk/integrations/openai_agents/patches/models.py +50 -0
- sentry_sdk/integrations/openai_agents/patches/runner.py +45 -0
- sentry_sdk/integrations/openai_agents/patches/tools.py +77 -0
- sentry_sdk/integrations/openai_agents/spans/__init__.py +5 -0
- sentry_sdk/integrations/openai_agents/spans/agent_workflow.py +21 -0
- sentry_sdk/integrations/openai_agents/spans/ai_client.py +42 -0
- sentry_sdk/integrations/openai_agents/spans/execute_tool.py +48 -0
- sentry_sdk/integrations/openai_agents/spans/handoff.py +19 -0
- sentry_sdk/integrations/openai_agents/spans/invoke_agent.py +86 -0
- sentry_sdk/integrations/openai_agents/utils.py +199 -0
- sentry_sdk/integrations/openfeature.py +35 -0
- sentry_sdk/integrations/opentelemetry/__init__.py +7 -0
- sentry_sdk/integrations/opentelemetry/consts.py +5 -0
- sentry_sdk/integrations/opentelemetry/integration.py +58 -0
- sentry_sdk/integrations/opentelemetry/propagator.py +117 -0
- sentry_sdk/integrations/opentelemetry/span_processor.py +391 -0
- sentry_sdk/integrations/otlp.py +82 -0
- sentry_sdk/integrations/pure_eval.py +141 -0
- sentry_sdk/integrations/pydantic_ai/__init__.py +47 -0
- sentry_sdk/integrations/pydantic_ai/consts.py +1 -0
- sentry_sdk/integrations/pydantic_ai/patches/__init__.py +4 -0
- sentry_sdk/integrations/pydantic_ai/patches/agent_run.py +215 -0
- sentry_sdk/integrations/pydantic_ai/patches/graph_nodes.py +110 -0
- sentry_sdk/integrations/pydantic_ai/patches/model_request.py +40 -0
- sentry_sdk/integrations/pydantic_ai/patches/tools.py +98 -0
- sentry_sdk/integrations/pydantic_ai/spans/__init__.py +3 -0
- sentry_sdk/integrations/pydantic_ai/spans/ai_client.py +246 -0
- sentry_sdk/integrations/pydantic_ai/spans/execute_tool.py +49 -0
- sentry_sdk/integrations/pydantic_ai/spans/invoke_agent.py +112 -0
- sentry_sdk/integrations/pydantic_ai/utils.py +223 -0
- sentry_sdk/integrations/pymongo.py +214 -0
- sentry_sdk/integrations/pyramid.py +112 -68
- sentry_sdk/integrations/quart.py +237 -0
- sentry_sdk/integrations/ray.py +165 -0
- sentry_sdk/integrations/redis/__init__.py +48 -0
- sentry_sdk/integrations/redis/_async_common.py +116 -0
- sentry_sdk/integrations/redis/_sync_common.py +119 -0
- sentry_sdk/integrations/redis/consts.py +19 -0
- sentry_sdk/integrations/redis/modules/__init__.py +0 -0
- sentry_sdk/integrations/redis/modules/caches.py +118 -0
- sentry_sdk/integrations/redis/modules/queries.py +65 -0
- sentry_sdk/integrations/redis/rb.py +32 -0
- sentry_sdk/integrations/redis/redis.py +69 -0
- sentry_sdk/integrations/redis/redis_cluster.py +107 -0
- sentry_sdk/integrations/redis/redis_py_cluster_legacy.py +50 -0
- sentry_sdk/integrations/redis/utils.py +148 -0
- sentry_sdk/integrations/rq.py +95 -37
- sentry_sdk/integrations/rust_tracing.py +284 -0
- sentry_sdk/integrations/sanic.py +294 -123
- sentry_sdk/integrations/serverless.py +48 -19
- sentry_sdk/integrations/socket.py +96 -0
- sentry_sdk/integrations/spark/__init__.py +4 -0
- sentry_sdk/integrations/spark/spark_driver.py +316 -0
- sentry_sdk/integrations/spark/spark_worker.py +116 -0
- sentry_sdk/integrations/sqlalchemy.py +142 -0
- sentry_sdk/integrations/starlette.py +737 -0
- sentry_sdk/integrations/starlite.py +292 -0
- sentry_sdk/integrations/statsig.py +37 -0
- sentry_sdk/integrations/stdlib.py +235 -29
- sentry_sdk/integrations/strawberry.py +394 -0
- sentry_sdk/integrations/sys_exit.py +70 -0
- sentry_sdk/integrations/threading.py +158 -28
- sentry_sdk/integrations/tornado.py +84 -52
- sentry_sdk/integrations/trytond.py +50 -0
- sentry_sdk/integrations/typer.py +60 -0
- sentry_sdk/integrations/unleash.py +33 -0
- sentry_sdk/integrations/unraisablehook.py +53 -0
- sentry_sdk/integrations/wsgi.py +201 -119
- sentry_sdk/logger.py +96 -0
- sentry_sdk/metrics.py +81 -0
- sentry_sdk/monitor.py +120 -0
- sentry_sdk/profiler/__init__.py +49 -0
- sentry_sdk/profiler/continuous_profiler.py +730 -0
- sentry_sdk/profiler/transaction_profiler.py +839 -0
- sentry_sdk/profiler/utils.py +195 -0
- sentry_sdk/py.typed +0 -0
- sentry_sdk/scope.py +1713 -85
- sentry_sdk/scrubber.py +177 -0
- sentry_sdk/serializer.py +405 -0
- sentry_sdk/session.py +177 -0
- sentry_sdk/sessions.py +275 -0
- sentry_sdk/spotlight.py +242 -0
- sentry_sdk/tracing.py +1486 -0
- sentry_sdk/tracing_utils.py +1236 -0
- sentry_sdk/transport.py +806 -134
- sentry_sdk/types.py +52 -0
- sentry_sdk/utils.py +1625 -465
- sentry_sdk/worker.py +54 -25
- sentry_sdk-2.46.0.dist-info/METADATA +268 -0
- sentry_sdk-2.46.0.dist-info/RECORD +189 -0
- {sentry_sdk-0.7.5.dist-info → sentry_sdk-2.46.0.dist-info}/WHEEL +1 -1
- sentry_sdk-2.46.0.dist-info/entry_points.txt +2 -0
- sentry_sdk-2.46.0.dist-info/licenses/LICENSE +21 -0
- sentry_sdk/integrations/celery.py +0 -119
- sentry_sdk-0.7.5.dist-info/LICENSE +0 -9
- sentry_sdk-0.7.5.dist-info/METADATA +0 -36
- sentry_sdk-0.7.5.dist-info/RECORD +0 -39
- {sentry_sdk-0.7.5.dist-info → sentry_sdk-2.46.0.dist-info}/top_level.txt +0 -0
|
@@ -1,58 +1,132 @@
|
|
|
1
|
+
from contextlib import contextmanager
|
|
1
2
|
import json
|
|
3
|
+
from copy import deepcopy
|
|
2
4
|
|
|
3
|
-
|
|
4
|
-
from sentry_sdk.
|
|
5
|
-
from sentry_sdk.
|
|
5
|
+
import sentry_sdk
|
|
6
|
+
from sentry_sdk.scope import should_send_default_pii
|
|
7
|
+
from sentry_sdk.utils import AnnotatedValue, logger
|
|
6
8
|
|
|
7
|
-
|
|
9
|
+
try:
|
|
10
|
+
from django.http.request import RawPostDataException
|
|
11
|
+
except ImportError:
|
|
12
|
+
RawPostDataException = None
|
|
13
|
+
|
|
14
|
+
from typing import TYPE_CHECKING
|
|
15
|
+
|
|
16
|
+
if TYPE_CHECKING:
|
|
8
17
|
from typing import Any
|
|
9
18
|
from typing import Dict
|
|
19
|
+
from typing import Iterator
|
|
20
|
+
from typing import Mapping
|
|
21
|
+
from typing import MutableMapping
|
|
10
22
|
from typing import Optional
|
|
11
23
|
from typing import Union
|
|
24
|
+
from sentry_sdk._types import Event, HttpStatusCodeRange
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
SENSITIVE_ENV_KEYS = (
|
|
28
|
+
"REMOTE_ADDR",
|
|
29
|
+
"HTTP_X_FORWARDED_FOR",
|
|
30
|
+
"HTTP_SET_COOKIE",
|
|
31
|
+
"HTTP_COOKIE",
|
|
32
|
+
"HTTP_AUTHORIZATION",
|
|
33
|
+
"HTTP_X_API_KEY",
|
|
34
|
+
"HTTP_X_FORWARDED_FOR",
|
|
35
|
+
"HTTP_X_REAL_IP",
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
SENSITIVE_HEADERS = tuple(
|
|
39
|
+
x[len("HTTP_") :] for x in SENSITIVE_ENV_KEYS if x.startswith("HTTP_")
|
|
40
|
+
)
|
|
12
41
|
|
|
42
|
+
DEFAULT_HTTP_METHODS_TO_CAPTURE = (
|
|
43
|
+
"CONNECT",
|
|
44
|
+
"DELETE",
|
|
45
|
+
"GET",
|
|
46
|
+
# "HEAD", # do not capture HEAD requests by default
|
|
47
|
+
# "OPTIONS", # do not capture OPTIONS requests by default
|
|
48
|
+
"PATCH",
|
|
49
|
+
"POST",
|
|
50
|
+
"PUT",
|
|
51
|
+
"TRACE",
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
# This noop context manager can be replaced with "from contextlib import nullcontext" when we drop Python 3.6 support
|
|
56
|
+
@contextmanager
|
|
57
|
+
def nullcontext():
|
|
58
|
+
# type: () -> Iterator[None]
|
|
59
|
+
yield
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def request_body_within_bounds(client, content_length):
|
|
63
|
+
# type: (Optional[sentry_sdk.client.BaseClient], int) -> bool
|
|
64
|
+
if client is None:
|
|
65
|
+
return False
|
|
66
|
+
|
|
67
|
+
bodies = client.options["max_request_body_size"]
|
|
68
|
+
return not (
|
|
69
|
+
bodies == "never"
|
|
70
|
+
or (bodies == "small" and content_length > 10**3)
|
|
71
|
+
or (bodies == "medium" and content_length > 10**4)
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
class RequestExtractor:
|
|
76
|
+
"""
|
|
77
|
+
Base class for request extraction.
|
|
78
|
+
"""
|
|
79
|
+
|
|
80
|
+
# It does not make sense to make this class an ABC because it is not used
|
|
81
|
+
# for typing, only so that child classes can inherit common methods from
|
|
82
|
+
# it. Only some child classes implement all methods that raise
|
|
83
|
+
# NotImplementedError in this class.
|
|
13
84
|
|
|
14
|
-
class RequestExtractor(object):
|
|
15
85
|
def __init__(self, request):
|
|
16
86
|
# type: (Any) -> None
|
|
17
87
|
self.request = request
|
|
18
88
|
|
|
19
89
|
def extract_into_event(self, event):
|
|
20
|
-
# type: (
|
|
21
|
-
client =
|
|
22
|
-
if client
|
|
90
|
+
# type: (Event) -> None
|
|
91
|
+
client = sentry_sdk.get_client()
|
|
92
|
+
if not client.is_active():
|
|
23
93
|
return
|
|
24
94
|
|
|
25
95
|
data = None # type: Optional[Union[AnnotatedValue, Dict[str, Any]]]
|
|
26
96
|
|
|
27
97
|
content_length = self.content_length()
|
|
28
|
-
request_info = event.
|
|
98
|
+
request_info = event.get("request", {})
|
|
29
99
|
|
|
30
|
-
if
|
|
100
|
+
if should_send_default_pii():
|
|
31
101
|
request_info["cookies"] = dict(self.cookies())
|
|
32
102
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
bodies == "never"
|
|
36
|
-
or (bodies == "small" and content_length > 10 ** 3)
|
|
37
|
-
or (bodies == "medium" and content_length > 10 ** 4)
|
|
38
|
-
):
|
|
39
|
-
data = AnnotatedValue(
|
|
40
|
-
"",
|
|
41
|
-
{"rem": [["!config", "x", 0, content_length]], "len": content_length},
|
|
42
|
-
)
|
|
103
|
+
if not request_body_within_bounds(client, content_length):
|
|
104
|
+
data = AnnotatedValue.removed_because_over_size_limit()
|
|
43
105
|
else:
|
|
106
|
+
# First read the raw body data
|
|
107
|
+
# It is important to read this first because if it is Django
|
|
108
|
+
# it will cache the body and then we can read the cached version
|
|
109
|
+
# again in parsed_body() (or json() or wherever).
|
|
110
|
+
raw_data = None
|
|
111
|
+
try:
|
|
112
|
+
raw_data = self.raw_data()
|
|
113
|
+
except (RawPostDataException, ValueError):
|
|
114
|
+
# If DjangoRestFramework is used it already read the body for us
|
|
115
|
+
# so reading it here will fail. We can ignore this.
|
|
116
|
+
pass
|
|
117
|
+
|
|
44
118
|
parsed_body = self.parsed_body()
|
|
45
|
-
if parsed_body:
|
|
119
|
+
if parsed_body is not None:
|
|
46
120
|
data = parsed_body
|
|
47
|
-
elif
|
|
48
|
-
data = AnnotatedValue(
|
|
49
|
-
"",
|
|
50
|
-
{"rem": [["!raw", "x", 0, content_length]], "len": content_length},
|
|
51
|
-
)
|
|
121
|
+
elif raw_data:
|
|
122
|
+
data = AnnotatedValue.removed_because_raw_data()
|
|
52
123
|
else:
|
|
53
|
-
|
|
124
|
+
data = None
|
|
54
125
|
|
|
55
|
-
|
|
126
|
+
if data is not None:
|
|
127
|
+
request_info["data"] = data
|
|
128
|
+
|
|
129
|
+
event["request"] = deepcopy(request_info)
|
|
56
130
|
|
|
57
131
|
def content_length(self):
|
|
58
132
|
# type: () -> int
|
|
@@ -62,25 +136,35 @@ class RequestExtractor(object):
|
|
|
62
136
|
return 0
|
|
63
137
|
|
|
64
138
|
def cookies(self):
|
|
139
|
+
# type: () -> MutableMapping[str, Any]
|
|
65
140
|
raise NotImplementedError()
|
|
66
141
|
|
|
67
142
|
def raw_data(self):
|
|
143
|
+
# type: () -> Optional[Union[str, bytes]]
|
|
68
144
|
raise NotImplementedError()
|
|
69
145
|
|
|
70
146
|
def form(self):
|
|
147
|
+
# type: () -> Optional[Dict[str, Any]]
|
|
71
148
|
raise NotImplementedError()
|
|
72
149
|
|
|
73
150
|
def parsed_body(self):
|
|
74
151
|
# type: () -> Optional[Dict[str, Any]]
|
|
75
|
-
|
|
76
|
-
|
|
152
|
+
try:
|
|
153
|
+
form = self.form()
|
|
154
|
+
except Exception:
|
|
155
|
+
form = None
|
|
156
|
+
try:
|
|
157
|
+
files = self.files()
|
|
158
|
+
except Exception:
|
|
159
|
+
files = None
|
|
160
|
+
|
|
77
161
|
if form or files:
|
|
78
|
-
data =
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
162
|
+
data = {}
|
|
163
|
+
if form:
|
|
164
|
+
data = dict(form.items())
|
|
165
|
+
if files:
|
|
166
|
+
for key in files.keys():
|
|
167
|
+
data[key] = AnnotatedValue.removed_because_raw_data()
|
|
84
168
|
|
|
85
169
|
return data
|
|
86
170
|
|
|
@@ -93,28 +177,43 @@ class RequestExtractor(object):
|
|
|
93
177
|
def json(self):
|
|
94
178
|
# type: () -> Optional[Any]
|
|
95
179
|
try:
|
|
96
|
-
if self.is_json():
|
|
180
|
+
if not self.is_json():
|
|
181
|
+
return None
|
|
182
|
+
|
|
183
|
+
try:
|
|
97
184
|
raw_data = self.raw_data()
|
|
98
|
-
|
|
99
|
-
|
|
185
|
+
except (RawPostDataException, ValueError):
|
|
186
|
+
# The body might have already been read, in which case this will
|
|
187
|
+
# fail
|
|
188
|
+
raw_data = None
|
|
189
|
+
|
|
190
|
+
if raw_data is None:
|
|
191
|
+
return None
|
|
192
|
+
|
|
193
|
+
if isinstance(raw_data, str):
|
|
100
194
|
return json.loads(raw_data)
|
|
195
|
+
else:
|
|
196
|
+
return json.loads(raw_data.decode("utf-8"))
|
|
101
197
|
except ValueError:
|
|
102
198
|
pass
|
|
103
199
|
|
|
104
200
|
return None
|
|
105
201
|
|
|
106
202
|
def files(self):
|
|
203
|
+
# type: () -> Optional[Dict[str, Any]]
|
|
107
204
|
raise NotImplementedError()
|
|
108
205
|
|
|
109
206
|
def size_of_file(self, file):
|
|
207
|
+
# type: (Any) -> int
|
|
110
208
|
raise NotImplementedError()
|
|
111
209
|
|
|
112
210
|
def env(self):
|
|
211
|
+
# type: () -> Dict[str, Any]
|
|
113
212
|
raise NotImplementedError()
|
|
114
213
|
|
|
115
214
|
|
|
116
215
|
def _is_json_content_type(ct):
|
|
117
|
-
# type: (str) -> bool
|
|
216
|
+
# type: (Optional[str]) -> bool
|
|
118
217
|
mt = (ct or "").split(";", 1)[0]
|
|
119
218
|
return (
|
|
120
219
|
mt == "application/json"
|
|
@@ -124,12 +223,49 @@ def _is_json_content_type(ct):
|
|
|
124
223
|
|
|
125
224
|
|
|
126
225
|
def _filter_headers(headers):
|
|
127
|
-
# type: (
|
|
128
|
-
if
|
|
226
|
+
# type: (Mapping[str, str]) -> Mapping[str, Union[AnnotatedValue, str]]
|
|
227
|
+
if should_send_default_pii():
|
|
129
228
|
return headers
|
|
130
229
|
|
|
131
230
|
return {
|
|
132
|
-
k:
|
|
231
|
+
k: (
|
|
232
|
+
v
|
|
233
|
+
if k.upper().replace("-", "_") not in SENSITIVE_HEADERS
|
|
234
|
+
else AnnotatedValue.removed_because_over_size_limit()
|
|
235
|
+
)
|
|
133
236
|
for k, v in headers.items()
|
|
134
|
-
if k.lower().replace("_", "-") not in ("set-cookie", "cookie", "authorization")
|
|
135
237
|
}
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
def _in_http_status_code_range(code, code_ranges):
|
|
241
|
+
# type: (object, list[HttpStatusCodeRange]) -> bool
|
|
242
|
+
for target in code_ranges:
|
|
243
|
+
if isinstance(target, int):
|
|
244
|
+
if code == target:
|
|
245
|
+
return True
|
|
246
|
+
continue
|
|
247
|
+
|
|
248
|
+
try:
|
|
249
|
+
if code in target:
|
|
250
|
+
return True
|
|
251
|
+
except TypeError:
|
|
252
|
+
logger.warning(
|
|
253
|
+
"failed_request_status_codes has to be a list of integers or containers"
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
return False
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
class HttpCodeRangeContainer:
|
|
260
|
+
"""
|
|
261
|
+
Wrapper to make it possible to use list[HttpStatusCodeRange] as a Container[int].
|
|
262
|
+
Used for backwards compatibility with the old `failed_request_status_codes` option.
|
|
263
|
+
"""
|
|
264
|
+
|
|
265
|
+
def __init__(self, code_ranges):
|
|
266
|
+
# type: (list[HttpStatusCodeRange]) -> None
|
|
267
|
+
self._code_ranges = code_ranges
|
|
268
|
+
|
|
269
|
+
def __contains__(self, item):
|
|
270
|
+
# type: (object) -> bool
|
|
271
|
+
return _in_http_status_code_range(item, self._code_ranges)
|