diff --git a/elasticapm/conf/constants.py b/elasticapm/conf/constants.py index 46a94a6bc..3cd045799 100644 --- a/elasticapm/conf/constants.py +++ b/elasticapm/conf/constants.py @@ -7,3 +7,5 @@ TIMESTAMP_FORMAT = '%Y-%m-%dT%H:%M:%S.%fZ' KEYWORD_MAX_LENGTH = 1024 + +HTTP_WITH_BODY = {'POST', 'PUT', 'PATCH', 'DELETE'} diff --git a/elasticapm/contrib/django/client.py b/elasticapm/contrib/django/client.py index 0252ee1f4..05593d2c4 100644 --- a/elasticapm/contrib/django/client.py +++ b/elasticapm/contrib/django/client.py @@ -20,6 +20,7 @@ from django.http import HttpRequest from elasticapm.base import Client +from elasticapm.conf import constants from elasticapm.contrib.django.utils import iterate_with_template_sources from elasticapm.utils import compat, encoding, get_url_dict from elasticapm.utils.module_import import import_string @@ -106,11 +107,11 @@ def get_data_from_request(self, request, capture_body=False): 'cookies': dict(request.COOKIES), } - if request.method not in ('GET', 'HEAD'): + if request.method in constants.HTTP_WITH_BODY: content_type = request.META.get('CONTENT_TYPE') if content_type == 'application/x-www-form-urlencoded': data = compat.multidict_to_dict(request.POST) - elif content_type.startswith('multipart/form-data'): + elif content_type and content_type.startswith('multipart/form-data'): data = compat.multidict_to_dict(request.POST) if request.FILES: data['_files'] = {field: file.name for field, file in compat.iteritems(request.FILES)} diff --git a/elasticapm/contrib/django/management/commands/elasticapm.py b/elasticapm/contrib/django/management/commands/elasticapm.py index a22b52620..97b915200 100644 --- a/elasticapm/contrib/django/management/commands/elasticapm.py +++ b/elasticapm/contrib/django/management/commands/elasticapm.py @@ -56,7 +56,6 @@ def info(self, *args, **kwargs): self.log('info', *args, **kwargs) - CONFIG_EXAMPLE = """ You can set it in your settings file: diff --git a/elasticapm/contrib/flask/utils.py b/elasticapm/contrib/flask/utils.py index 00ede9e7c..ebc44d240 100644 --- a/elasticapm/contrib/flask/utils.py +++ b/elasticapm/contrib/flask/utils.py @@ -1,5 +1,6 @@ from werkzeug.exceptions import ClientDisconnected +from elasticapm.conf import constants from elasticapm.utils import compat, get_url_dict from elasticapm.utils.wsgi import get_environ, get_headers @@ -17,11 +18,11 @@ def get_data_from_request(request, capture_body=False): }, 'cookies': request.cookies, } - if request.method not in ('GET', 'HEAD'): + if request.method in constants.HTTP_WITH_BODY: body = None if request.content_type == 'application/x-www-form-urlencoded': body = compat.multidict_to_dict(request.form) - elif request.content_type.startswith('multipart/form-data'): + elif request.content_type and request.content_type.startswith('multipart/form-data'): body = compat.multidict_to_dict(request.form) if request.files: body['_files'] = { diff --git a/tests/contrib/django/django_tests.py b/tests/contrib/django/django_tests.py index f2cf3a611..efa891fb1 100644 --- a/tests/contrib/django/django_tests.py +++ b/tests/contrib/django/django_tests.py @@ -1271,3 +1271,15 @@ def test_capture_files(client, django_elasticapm_client): } else: assert error['errors'][0]['context']['request']['body'] == '[REDACTED]' + + +@pytest.mark.parametrize('django_elasticapm_client', [ + {'capture_body': 'transactions'}, +], indirect=True) +def test_options_request(client, django_elasticapm_client): + with override_settings(**middleware_setting(django.VERSION, [ + 'elasticapm.contrib.django.middleware.TracingMiddleware' + ])): + client.options('/') + transactions = django_elasticapm_client.instrumentation_store.get_all() + assert transactions[0]['context']['request']['method'] == 'OPTIONS' diff --git a/tests/contrib/flask/flask_tests.py b/tests/contrib/flask/flask_tests.py index e62c72251..17f7e7028 100644 --- a/tests/contrib/flask/flask_tests.py +++ b/tests/contrib/flask/flask_tests.py @@ -232,3 +232,12 @@ def test_post_files(flask_apm_client): } else: assert event['context']['request']['body'] == '[REDACTED]' + + +@pytest.mark.parametrize('elasticapm_client', [ + {'capture_body': 'transactions'}, +], indirect=True) +def test_options_request(flask_apm_client): + resp = flask_apm_client.app.test_client().options('/') + transactions = flask_apm_client.client.instrumentation_store.get_all() + assert transactions[0]['context']['request']['method'] == 'OPTIONS'