Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(iast): refactor iast request context by core.context #10988

Open
wants to merge 91 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 48 commits
Commits
Show all changes
91 commits
Select commit Hold shift + click to select a range
9898b74
first version
christophe-papazian Oct 2, 2024
1ca626c
Merge remote-tracking branch 'origin/main' into christophe-papazian/r…
christophe-papazian Oct 2, 2024
c2fff2c
merge forget
christophe-papazian Oct 2, 2024
619cb7c
revert unwanted changes
christophe-papazian Oct 2, 2024
f86884e
revert unwanted changes
christophe-papazian Oct 2, 2024
ccef5df
revert unwanted changes
christophe-papazian Oct 2, 2024
715dab4
Merge remote-tracking branch 'origin/main' into christophe-papazian/r…
christophe-papazian Oct 2, 2024
f16df62
move appsec load for iast
christophe-papazian Oct 2, 2024
c9f15cc
revert config raise
christophe-papazian Oct 2, 2024
26c373d
starting the change for fastapi
christophe-papazian Oct 2, 2024
f96a48d
Merge remote-tracking branch 'origin/main' into christophe-papazian/r…
christophe-papazian Oct 3, 2024
c16565c
fix
christophe-papazian Oct 3, 2024
b9f0c15
fix
christophe-papazian Oct 3, 2024
e547cd6
fix
christophe-papazian Oct 3, 2024
271c9e4
fix asgi blocking mechanism
christophe-papazian Oct 3, 2024
10411ad
improve block logic for fastapi/asgi
christophe-papazian Oct 3, 2024
7c2b9c0
use new block functions everywhere
christophe-papazian Oct 3, 2024
33adb33
fix test_processor
christophe-papazian Oct 4, 2024
20b584f
fix appsec tests
christophe-papazian Oct 4, 2024
0b2819a
Merge remote-tracking branch 'origin/main' into christophe-papazian/r…
christophe-papazian Oct 7, 2024
a927991
fix test_remoteconfiguration
christophe-papazian Oct 7, 2024
4203c4f
fix iast/test_telemetry
christophe-papazian Oct 7, 2024
7d7f3c5
make core context real context and add exception catching. fix test_a…
christophe-papazian Oct 7, 2024
3f310b8
Merge remote-tracking branch 'origin/main' into christophe-papazian/r…
christophe-papazian Oct 7, 2024
ebe7f02
context return self
christophe-papazian Oct 7, 2024
6e26fc3
more test fixes
christophe-papazian Oct 7, 2024
9f7372b
remove context slots and fix more tests
christophe-papazian Oct 7, 2024
41502da
Merge branch 'main' into christophe-papazian/refactor_asm_request_con…
christophe-papazian Oct 8, 2024
538b0bf
remove code commented
christophe-papazian Oct 8, 2024
f55a018
chore(appsec): move common context to class
avara1986 Oct 8, 2024
c84c840
chore(appsec): move common context to class
avara1986 Oct 9, 2024
f2a584f
chore(appsec): move common context to class
avara1986 Oct 9, 2024
4b29b90
chore(appsec): move common context to class
avara1986 Oct 9, 2024
45849ea
chore(appsec): move common context to class
avara1986 Oct 9, 2024
dab6a6a
chore(appsec): move common context to class
avara1986 Oct 9, 2024
a42eba6
chore(appsec): move common context to class
avara1986 Oct 9, 2024
41d6c4a
chore(appsec): move common context to class
avara1986 Oct 9, 2024
66e5996
chore(appsec): move common context to class
avara1986 Oct 10, 2024
06da8c6
chore(appsec): move common context to class
avara1986 Oct 10, 2024
cac89f8
chore(appsec): move common context to class
avara1986 Oct 10, 2024
d7af85c
chore(appsec): move common context to class
avara1986 Oct 10, 2024
2452893
chore(appsec): move common context to class
avara1986 Oct 10, 2024
d830dd2
chore(appsec): move common context to class
avara1986 Oct 10, 2024
1f3efe7
Merge branch 'main' into avara1986/refactor_iast_request_context_to_core
avara1986 Oct 10, 2024
0d8288a
chore(appsec): move common context to class
avara1986 Oct 10, 2024
fe59ea6
chore(appsec): move common context to class
avara1986 Oct 10, 2024
2b9f436
chore(appsec): move common context to class
avara1986 Oct 10, 2024
33b522b
chore(appsec): move common context to class
avara1986 Oct 10, 2024
811b5f8
Merge branch 'main' into avara1986/refactor_iast_request_context_to_core
avara1986 Oct 10, 2024
3b1237f
Merge branch 'main' into avara1986/refactor_iast_request_context_to_core
avara1986 Oct 11, 2024
2153c4e
chore(appsec): move common context to class
avara1986 Oct 11, 2024
5bbe3c8
chore(appsec): move common context to class
avara1986 Oct 11, 2024
491ef4d
chore(appsec): move common context to class
avara1986 Oct 11, 2024
7aa40a8
chore(appsec): move common context to class
avara1986 Oct 11, 2024
deffd91
chore(appsec): move common context to class
avara1986 Oct 11, 2024
4725518
chore(appsec): move common context to class
avara1986 Oct 11, 2024
75bf96a
chore(appsec): move common context to class
avara1986 Oct 11, 2024
f597cd1
chore(appsec): move common context to class
avara1986 Oct 11, 2024
1cc399f
chore(appsec): move common context to class
avara1986 Oct 11, 2024
97f5904
Merge branch 'main' into avara1986/refactor_iast_request_context_to_core
avara1986 Oct 11, 2024
b14030a
chore(appsec): move common context to class
avara1986 Oct 11, 2024
72f73f1
chore(appsec): move common context to class
avara1986 Oct 11, 2024
15d1b9e
chore(appsec): move common context to class
avara1986 Oct 11, 2024
b76a7bf
chore(appsec): move common context to class
avara1986 Oct 11, 2024
df8194b
Merge branch 'main' into avara1986/refactor_iast_request_context_to_core
avara1986 Oct 11, 2024
6369ff5
chore(appsec): move common context to class
avara1986 Oct 11, 2024
ef7200a
chore(appsec): move common context to class
avara1986 Oct 11, 2024
8815a91
chore(appsec): move common context to class
avara1986 Oct 11, 2024
62606e0
chore(appsec): move common context to class
avara1986 Oct 11, 2024
a8b6638
chore(appsec): move common context to class
avara1986 Oct 11, 2024
32faf3e
Merge branch 'main' into avara1986/refactor_iast_request_context_to_core
avara1986 Oct 11, 2024
232d98b
chore(appsec): move common context to class
avara1986 Oct 11, 2024
c0d19a3
chore(appsec): move common context to class
avara1986 Oct 11, 2024
dbb6b55
chore(appsec): move common context to class
avara1986 Oct 11, 2024
27f8e96
chore(appsec): move common context to class
avara1986 Oct 14, 2024
e4cc5f4
Merge branch 'main' into avara1986/refactor_iast_request_context_to_core
avara1986 Oct 14, 2024
d057d9d
Merge branch 'main' into avara1986/refactor_iast_request_context_to_core
avara1986 Oct 14, 2024
fb74d23
chore(appsec): move common context to class
avara1986 Oct 14, 2024
8df1c33
Merge branch 'main' into avara1986/refactor_iast_request_context_to_core
avara1986 Oct 14, 2024
20b386a
Merge branch 'main' into avara1986/refactor_iast_request_context_to_core
avara1986 Oct 15, 2024
3ac963d
Merge branch 'main' into avara1986/refactor_iast_request_context_to_core
avara1986 Oct 15, 2024
61bda6e
fix: enable fastapi header source
avara1986 Oct 15, 2024
95f30af
Merge branch 'main' into avara1986/refactor_iast_request_context_to_core
avara1986 Oct 15, 2024
fe76bef
fix(iast): re.finditer error
avara1986 Oct 15, 2024
528573e
fix re match aspects related to #11027
avara1986 Oct 15, 2024
7d1eab1
revert
avara1986 Oct 15, 2024
5582bbe
remove Match from tainteable_types. APPSEC_55239
avara1986 Oct 16, 2024
3b43efe
revert changes
avara1986 Oct 16, 2024
8df5394
Merge branch 'main' into avara1986/refactor_iast_request_context_to_core
avara1986 Oct 16, 2024
c6edcb6
disable re tests
avara1986 Oct 16, 2024
c29f5ec
remove Match from tainteable_types. APPSEC_55239
avara1986 Oct 16, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions benchmarks/appsec_iast_aspects/scenario.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@
import bm
from bm.utils import override_env

from ddtrace.appsec._iast import oce
from ddtrace.appsec._iast._ast.ast_patching import astpatch_module
from ddtrace.appsec._iast._iast_request_context import end_iast_context
from ddtrace.appsec._iast._iast_request_context import set_iast_request_enabled
from ddtrace.appsec._iast._iast_request_context import start_iast_context


# Copypasted here from tests.iast.aspects.conftest since the benchmarks can't access tests.*
Expand All @@ -19,6 +23,18 @@ def _iast_patched_module(module_name):
return module_changed


def _start_iast_context_and_oce():
oce.reconfigure()
oce.acquire_request(None)
start_iast_context()
set_iast_request_enabled(True)


def _end_iast_context_and_oce():
end_iast_context()
oce.release_request()


class IAST_Aspects(bm.Scenario):
iast_enabled: bool
mod_original_name: str
Expand All @@ -27,6 +43,9 @@ class IAST_Aspects(bm.Scenario):

def run(self):
args = ast.literal_eval(self.args)
if self.iast_enabled:
with override_env({"DD_IAST_ENABLED": "True"}):
_start_iast_context_and_oce()

def _(loops):
for _ in range(loops):
Expand All @@ -40,3 +59,6 @@ def _(loops):
getattr(module_unpatched, self.function_name)(*args)

yield _
if self.iast_enabled:
with override_env({"DD_IAST_ENABLED": "True"}):
_end_iast_context_and_oce()
38 changes: 25 additions & 13 deletions benchmarks/appsec_iast_propagation/scenario.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,36 @@
from typing import Any

import bm
from bm.utils import override_env


with override_env({"DD_IAST_ENABLED": "True"}):
from ddtrace.appsec._iast._taint_tracking import OriginType
from ddtrace.appsec._iast._taint_tracking import Source
from ddtrace.appsec._iast._taint_tracking import TaintRange
from ddtrace.appsec._iast._taint_tracking import create_context
from ddtrace.appsec._iast._taint_tracking import reset_context
from ddtrace.appsec._iast._taint_tracking import set_ranges
from ddtrace.appsec._iast._taint_tracking.aspects import add_aspect
from ddtrace.appsec._iast._taint_tracking.aspects import join_aspect
from ddtrace.appsec._iast import oce
from ddtrace.appsec._iast._iast_request_context import end_iast_context
from ddtrace.appsec._iast._iast_request_context import set_iast_request_enabled
from ddtrace.appsec._iast._iast_request_context import start_iast_context
from ddtrace.appsec._iast._taint_tracking import OriginType
from ddtrace.appsec._iast._taint_tracking import Source
from ddtrace.appsec._iast._taint_tracking import TaintRange
from ddtrace.appsec._iast._taint_tracking import set_ranges
from ddtrace.appsec._iast._taint_tracking.aspects import add_aspect
from ddtrace.appsec._iast._taint_tracking.aspects import join_aspect


TAINT_ORIGIN = Source(name="sample_name", value="sample_value", origin=OriginType.PARAMETER)

CHECK_RANGES = [TaintRange(0, 3, TAINT_ORIGIN), TaintRange(21, 3, TAINT_ORIGIN), TaintRange(41, 3, TAINT_ORIGIN)]


def _start_iast_context_and_oce():
oce.reconfigure()
oce.acquire_request(None)
start_iast_context()
set_iast_request_enabled(True)


def _end_iast_context_and_oce():
end_iast_context()
oce.release_request()


def taint_pyobject_with_ranges(pyobject: Any, ranges: tuple) -> None:
set_ranges(pyobject, tuple(ranges))

Expand Down Expand Up @@ -53,8 +64,6 @@ def aspect_function(internal_loop, tainted):

def new_request(enable_propagation):
tainted = b"my_string".decode("ascii")
reset_context()
create_context()

if enable_propagation:
taint_pyobject_with_ranges(tainted, (CHECK_RANGES[0],))
Expand All @@ -74,6 +83,7 @@ class IastPropagation(bm.Scenario):
def run(self):
caller_loop = 10
if self.iast_enabled:
_start_iast_context_and_oce()
func = aspect_function
else:
func = normal_function
Expand All @@ -83,3 +93,5 @@ def _(loops):
launch_function(self.iast_enabled, func, self.internal_loop, caller_loop)

yield _
if self.iast_enabled:
_end_iast_context_and_oce()
5 changes: 2 additions & 3 deletions benchmarks/bm/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,9 @@ def drop_traces(tracer):
def drop_telemetry_events():
# Avoids sending instrumentation telemetry payloads to the agent
try:
if telemetry.telemetry_writer.is_periodic:
telemetry.telemetry_writer.stop()
telemetry.telemetry_writer.stop()
telemetry.telemetry_writer.reset_queues()
telemetry.telemetry_writer.enable(start_worker_thread=False)
telemetry.telemetry_writer.enable()
except AttributeError:
# telemetry.telemetry_writer is not defined in this version of dd-trace-py
# Telemetry events will not be mocked!
Expand Down
165 changes: 9 additions & 156 deletions ddtrace/_trace/trace_handlers.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import functools
import re
import sys
from typing import TYPE_CHECKING
from typing import Any
from typing import Callable
from typing import Dict
Expand All @@ -10,7 +10,6 @@
import wrapt

from ddtrace._trace._span_pointer import _SpanPointerDescription
from ddtrace._trace.span import Span
from ddtrace._trace.utils import extract_DD_context_from_messages
from ddtrace._trace.utils_botocore.span_pointers import extract_span_pointers_from_successful_botocore_response
from ddtrace._trace.utils_botocore.span_tags import (
Expand All @@ -22,7 +21,6 @@
from ddtrace.constants import SPAN_MEASURED_KEY
from ddtrace.contrib import trace_utils
from ddtrace.contrib.internal.botocore.constants import BOTOCORE_STEPFUNCTIONS_INPUT_KEY
from ddtrace.contrib.trace_utils import _get_request_header_user_agent
from ddtrace.contrib.trace_utils import _set_url_tag
from ddtrace.ext import SpanKind
from ddtrace.ext import db
Expand All @@ -34,14 +32,15 @@
from ddtrace.internal.constants import FLASK_ENDPOINT
from ddtrace.internal.constants import FLASK_URL_RULE
from ddtrace.internal.constants import FLASK_VIEW_ARGS
from ddtrace.internal.constants import HTTP_REQUEST_BLOCKED
from ddtrace.internal.constants import RESPONSE_HEADERS
from ddtrace.internal.logger import get_logger
from ddtrace.internal.schema.span_attribute_schema import SpanDirection
from ddtrace.internal.utils import http as http_utils
from ddtrace.propagation.http import HTTPPropagator


if TYPE_CHECKING:
from ddtrace import Span


log = get_logger(__name__)


Expand Down Expand Up @@ -106,7 +105,7 @@ def _get_parameters_for_new_span_directly_from_context(ctx: core.ExecutionContex
return span_kwargs


def _start_span(ctx: core.ExecutionContext, call_trace: bool = True, **kwargs) -> Span:
def _start_span(ctx: core.ExecutionContext, call_trace: bool = True, **kwargs) -> "Span":
span_kwargs = _get_parameters_for_new_span_directly_from_context(ctx)
call_trace = ctx.get_item("call_trace", call_trace)
tracer = (ctx.get_item("middleware") or ctx["pin"]).tracer
Expand Down Expand Up @@ -160,126 +159,6 @@ def _maybe_start_http_response_span(ctx: core.ExecutionContext) -> None:
)


def _use_html(headers) -> bool:
"""decide if the response should be html or json.

Add support for quality values in the Accept header.
"""
ctype = headers.get("Accept", headers.get("accept", ""))
if not ctype:
return False
html_score = 0.0
json_score = 0.0
ctypes = ctype.split(",")
for ct in ctypes:
if len(ct) > 128:
# ignore long (and probably malicious) headers to avoid performances issues
continue
m = re.match(r"([^/;]+/[^/;]+)(?:;q=([01](?:\.\d*)?))?", ct.strip())
if m:
if m.group(1) == "text/html":
html_score = max(html_score, min(1.0, float(1.0 if m.group(2) is None else m.group(2))))
elif m.group(1) == "text/*":
html_score = max(html_score, min(1.0, float(0.2 if m.group(2) is None else m.group(2))))
elif m.group(1) == "application/json":
json_score = max(json_score, min(1.0, float(1.0 if m.group(2) is None else m.group(2))))
elif m.group(1) == "application/*":
json_score = max(json_score, min(1.0, float(0.2 if m.group(2) is None else m.group(2))))
return html_score > json_score


def _ctype_from_headers(block_config, headers) -> str:
"""compute MIME type of the blocked response."""
desired_type = block_config.get("type", "auto")
if desired_type == "auto":
return "text/html" if _use_html(headers) else "application/json"
else:
return "text/html" if block_config["type"] == "html" else "application/json"


def _wsgi_make_block_content(ctx, construct_url):
middleware = ctx.get_item("middleware")
req_span = ctx.get_item("req_span")
headers = ctx.get_item("headers")
environ = ctx.get_item("environ")
if req_span is None:
raise ValueError("request span not found")
block_config = core.get_item(HTTP_REQUEST_BLOCKED, span=req_span)
desired_type = block_config.get("type", "auto")
ctype = None
if desired_type == "none":
content = ""
resp_headers = [("content-type", "text/plain; charset=utf-8"), ("location", block_config.get("location", ""))]
else:
ctype = _ctype_from_headers(block_config, headers)
content = http_utils._get_blocked_template(ctype).encode("UTF-8")
resp_headers = [("content-type", ctype)]
status = block_config.get("status_code", 403)
try:
req_span.set_tag_str(RESPONSE_HEADERS + ".content-length", str(len(content)))
if ctype is not None:
req_span.set_tag_str(RESPONSE_HEADERS + ".content-type", ctype)
req_span.set_tag_str(http.STATUS_CODE, str(status))
url = construct_url(environ)
query_string = environ.get("QUERY_STRING")
_set_url_tag(middleware._config, req_span, url, query_string)
if query_string and middleware._config.trace_query_string:
req_span.set_tag_str(http.QUERY_STRING, query_string)
method = environ.get("REQUEST_METHOD")
if method:
req_span.set_tag_str(http.METHOD, method)
user_agent = _get_request_header_user_agent(headers, headers_are_case_sensitive=True)
if user_agent:
req_span.set_tag_str(http.USER_AGENT, user_agent)
except Exception as e:
log.warning("Could not set some span tags on blocked request: %s", str(e)) # noqa: G200
resp_headers.append(("Content-Length", str(len(content))))
return status, resp_headers, content


def _asgi_make_block_content(ctx, url):
middleware = ctx.get_item("middleware")
req_span = ctx.get_item("req_span")
headers = ctx.get_item("headers")
environ = ctx.get_item("environ")
if req_span is None:
raise ValueError("request span not found")
block_config = core.get_item(HTTP_REQUEST_BLOCKED, span=req_span)
desired_type = block_config.get("type", "auto")
ctype = None
if desired_type == "none":
content = ""
resp_headers = [
(b"content-type", b"text/plain; charset=utf-8"),
(b"location", block_config.get("location", "").encode()),
]
else:
ctype = _ctype_from_headers(block_config, headers)
content = http_utils._get_blocked_template(ctype).encode("UTF-8")
# ctype = f"{ctype}; charset=utf-8" can be considered at some point
resp_headers = [(b"content-type", ctype.encode())]
status = block_config.get("status_code", 403)
try:
req_span.set_tag_str(RESPONSE_HEADERS + ".content-length", str(len(content)))
if ctype is not None:
req_span.set_tag_str(RESPONSE_HEADERS + ".content-type", ctype)
req_span.set_tag_str(http.STATUS_CODE, str(status))
query_string = environ.get("QUERY_STRING")
_set_url_tag(middleware.integration_config, req_span, url, query_string)
if query_string and middleware._config.trace_query_string:
req_span.set_tag_str(http.QUERY_STRING, query_string)
method = environ.get("REQUEST_METHOD")
if method:
req_span.set_tag_str(http.METHOD, method)
user_agent = _get_request_header_user_agent(headers, headers_are_case_sensitive=True)
if user_agent:
req_span.set_tag_str(http.USER_AGENT, user_agent)
except Exception as e:
log.warning("Could not set some span tags on blocked request: %s", str(e)) # noqa: G200
resp_headers.append((b"Content-Length", str(len(content)).encode()))
return status, resp_headers, content


def _on_request_prepare(ctx, start_response):
middleware = ctx.get_item("middleware")
req_span = ctx.get_item("req_span")
Expand Down Expand Up @@ -438,25 +317,6 @@ def _cookies_from_response_headers(response_headers):
return cookies


def _on_flask_blocked_request(span):
span.set_tag_str(http.STATUS_CODE, "403")
request = core.get_item("flask_request")
try:
base_url = getattr(request, "base_url", None)
query_string = getattr(request, "query_string", None)
if base_url and query_string:
_set_url_tag(core.get_item("flask_config"), span, base_url, query_string)
if query_string and core.get_item("flask_config").trace_query_string:
span.set_tag_str(http.QUERY_STRING, query_string)
if request.method is not None:
span.set_tag_str(http.METHOD, request.method)
user_agent = _get_request_header_user_agent(request.headers)
if user_agent:
span.set_tag_str(http.USER_AGENT, user_agent)
except Exception as e:
log.warning("Could not set some span tags on blocked request: %s", str(e)) # noqa: G200


def _on_flask_render(template, flask_config):
span = core.get_item("current_span")
if not span:
Expand Down Expand Up @@ -508,10 +368,6 @@ def _on_request_span_modifier_post(ctx, flask_config, request, req_body):
)


def _on_start_response_blocked(ctx, flask_config, response_headers, status):
trace_utils.set_http_meta(ctx["req_span"], flask_config, status_code=status, response_headers=response_headers)


def _on_traced_get_response_pre(_, ctx: core.ExecutionContext, request, before_request_tags):
before_request_tags(ctx["pin"], ctx["call"], request)
ctx["call"]._metrics[SPAN_MEASURED_KEY] = 1
Expand Down Expand Up @@ -568,7 +424,7 @@ def _on_django_block_request(ctx: core.ExecutionContext, metadata: Dict[str, str
def _on_django_after_request_headers_post(
request_headers,
response_headers,
span: Span,
span: "Span",
django_config,
request,
url,
Expand Down Expand Up @@ -818,7 +674,7 @@ def _on_test_visibility_is_enabled() -> bool:
return CIVisibility.enabled


def _set_span_pointer(span: Span, span_pointer_description: _SpanPointerDescription) -> None:
def _set_span_pointer(span: "Span", span_pointer_description: _SpanPointerDescription) -> None:
span._add_span_pointer(
pointer_kind=span_pointer_description.pointer_kind,
pointer_direction=span_pointer_description.pointer_direction,
Expand All @@ -828,20 +684,16 @@ def _set_span_pointer(span: Span, span_pointer_description: _SpanPointerDescript


def listen():
core.on("wsgi.block.started", _wsgi_make_block_content, "status_headers_content")
core.on("asgi.block.started", _asgi_make_block_content, "status_headers_content")
core.on("wsgi.request.prepare", _on_request_prepare)
core.on("wsgi.request.prepared", _on_request_prepared)
core.on("wsgi.app.success", _on_app_success)
core.on("wsgi.app.exception", _on_app_exception)
core.on("wsgi.request.complete", _on_request_complete, "traced_iterable")
core.on("wsgi.response.prepared", _on_response_prepared)
core.on("flask.start_response.pre", _on_start_response_pre)
core.on("flask.blocked_request_callable", _on_flask_blocked_request)
core.on("flask.request_call_modifier", _on_request_span_modifier)
core.on("flask.request_call_modifier.post", _on_request_span_modifier_post)
core.on("flask.render", _on_flask_render)
core.on("flask.start_response.blocked", _on_start_response_blocked)
core.on("context.started.wsgi.response", _maybe_start_http_response_span)
core.on("context.started.flask._patched_request", _on_traced_request_context_started_flask)
core.on("django.traced_get_response.pre", _on_traced_get_response_pre)
Expand Down Expand Up @@ -891,6 +743,7 @@ def listen():
"flask.call",
"flask.jsonify",
"flask.render_template",
"asgi.__call__",
"wsgi.__call__",
"django.traced_get_response",
"django.cache",
Expand Down
Loading