Skip to content
This repository was archived by the owner on Jun 11, 2018. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
14 changes: 9 additions & 5 deletions opbeat/contrib/django/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,15 +106,19 @@ def get_data_from_request(self, request):

if request.method != 'GET':
try:
if hasattr(request, 'body'):
try:
# Django 1.4+
# NOTE: on Python 2.7 `hasattr(request, 'body')` returns
# False, while it might throw the exception from Django in
# Python 3.
raw_data = request.body
else:
except AttributeError:
raw_data = request.raw_post_data
data = raw_data if raw_data else request.POST
except Exception:
# assume we had a partial read:
data = '<unavailable>'
except Exception as exc:
# Assume we had a partial read, or multipart/form-data:
data = '<unavailable ({0}: {1})>\nrequest.POST: {2}'.format(
exc.__class__.__name__, exc, request.POST)
else:
data = None

Expand Down
65 changes: 61 additions & 4 deletions tests/contrib/django/django_tests.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
import pytest # isort:skip

django = pytest.importorskip("django") # isort:skip
django = pytest.importorskip("django") # noqa: E402 isort:skip

import datetime
import logging
Expand All @@ -21,6 +21,7 @@
from django.test import TestCase
from django.test.client import Client as _TestClient
from django.test.client import ClientHandler as _TestClientHandler
from django.test.client import FakePayload
from django.test.utils import override_settings

import mock
Expand Down Expand Up @@ -518,7 +519,12 @@ def test_raw_post_data_partial_read(self):
self.assertTrue('http' in event)
http = event['http']
self.assertEquals(http['method'], 'POST')
self.assertEquals(http['data'], '<unavailable>')
if django.VERSION >= (1, 7):
expected_exception = 'RawPostDataException'
else:
expected_exception = 'Exception'
self.assertEquals(http['data'], "<unavailable ({0}: You cannot access body after reading from request's data stream)>\nrequest.POST: {1}".format(expected_exception, request.POST))
self.assertEquals(request.POST, {})

def test_post_data(self):
request = WSGIRequest(environ={
Expand Down Expand Up @@ -598,7 +604,7 @@ def test_disallowed_hosts_error_django_18(self):
self.assertEqual(event['http']['url'], None)

# This test only applies to Django 1.3+
def test_request_capture(self):
def test_request_capture_partial_read(self):
if django.VERSION[:2] < (1, 3):
return
request = WSGIRequest(environ={
Expand All @@ -619,7 +625,12 @@ def test_request_capture(self):
self.assertTrue('http' in event)
http = event['http']
self.assertEquals(http['method'], 'POST')
self.assertEquals(http['data'], '<unavailable>')
if django.VERSION >= (1, 7):
expected_exception = 'RawPostDataException'
else:
expected_exception = 'Exception'
self.assertEquals(http['data'], "<unavailable ({0}: You cannot access body after reading from request's data stream)>\nrequest.POST: {1}".format(expected_exception, request.POST))
# self.assertEquals(http['data'], '{}')
self.assertTrue('headers' in http)
headers = http['headers']
self.assertTrue('Content-Type' in headers, headers.keys())
Expand All @@ -630,6 +641,52 @@ def test_request_capture(self):
self.assertTrue('SERVER_PORT' in env, env.keys())
self.assertEquals(env['SERVER_PORT'], '80')

def test_request_capture_multipart_formdata(self):
if django.VERSION[:2] < (1, 3):
return

payload = FakePayload("\r\n".join([
'--boundary',
'Content-Disposition: form-data; name="name"',
'',
'value',
'--boundary--'
'']))
request = WSGIRequest({
'REQUEST_METHOD': 'POST',
'SERVER_NAME': 'testserver',
'SERVER_PORT': '80',
'CONTENT_TYPE': 'multipart/form-data; boundary=boundary',
'CONTENT_LENGTH': 78,
'wsgi.input': payload})

# Read POST data to trigger exception when accessing request.body.
self.assertEqual(request.POST, {'name': ['value']})

self.opbeat.capture('Message', message='foo', request=request)

self.assertEquals(len(self.opbeat.events), 1)
event = self.opbeat.events.pop(0)

self.assertTrue('http' in event)
http = event['http']
self.assertEquals(http['method'], 'POST')
if django.VERSION >= (1, 7):
expected_exception = 'RawPostDataException'
else:
expected_exception = 'Exception'
self.assertEquals(http['data'], "<unavailable ({0}: You cannot access body after reading from request's data stream)>\nrequest.POST: {1}".format(expected_exception, request.POST))
# self.assertEquals(http['data'], '{}')
self.assertTrue('headers' in http)
headers = http['headers']
self.assertTrue('Content-Type' in headers, headers.keys())
self.assertEquals(headers['Content-Type'], 'multipart/form-data; boundary=boundary')
env = http['env']
self.assertTrue('SERVER_NAME' in env, env.keys())
self.assertEquals(env['SERVER_NAME'], 'testserver')
self.assertTrue('SERVER_PORT' in env, env.keys())
self.assertEquals(env['SERVER_PORT'], '80')

def test_transaction_metrics(self):
self.opbeat.instrumentation_store.get_all() # clear the store
with self.settings(MIDDLEWARE_CLASSES=[
Expand Down