Skip to content
Closed
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
2 changes: 1 addition & 1 deletion src/sentry/interfaces/http.py
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ def to_python(cls, data):
inferred_content_type = data.get('inferred_content_type', content_type)

if 'inferred_content_type' not in data and not isinstance(body, dict):
body, inferred_content_type = heuristic_decode(body, content_type)
inferred_content_type = heuristic_decode(body, content_type)

if body:
body = trim(body, settings.SENTRY_MAX_HTTP_BODY_SIZE)
Expand Down
5 changes: 3 additions & 2 deletions src/sentry/utils/http.py
Original file line number Diff line number Diff line change
Expand Up @@ -256,12 +256,13 @@ def heuristic_decode(data, possible_content_type=None):

for decoding_type, decoder in decoders:
try:
return (decoder(data), decoding_type)
decoder(data)
except Exception:
# Try another decoder
continue
return decoding_type

return (data, inferred_content_type)
return inferred_content_type


def percent_encode(val):
Expand Down
40 changes: 38 additions & 2 deletions tests/sentry/interfaces/test_http.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,15 +79,51 @@ def test_data_as_dict(self):
))
assert result.data == {'foo': 'bar'}

def test_form_encoded_data(self):
def test_urlencoded_data(self):
result = Http.to_python(
dict(
url='http://example.com',
headers={'Content-Type': 'application/x-www-form-urlencoded'},
data='foo=bar',
)
)
assert result.data == {'foo': ['bar']}

assert result.data == 'foo=bar'
assert result.inferred_content_type == 'application/x-www-form-urlencoded'

def test_infer_urlencoded_content_type(self):
result = Http.to_python(
dict(
url='http://example.com',
data='foo=bar',
)
)

assert result.data == 'foo=bar'
assert result.inferred_content_type == 'application/x-www-form-urlencoded'

def test_json_data(self):
result = Http.to_python(
dict(
url='http://example.com',
headers={'Content-Type': 'application/json'},
data='{"foo":"bar"}',
)
)

assert result.data == '{"foo":"bar"}'
assert result.inferred_content_type == 'application/json'

def test_infer_json_content_type(self):
result = Http.to_python(
dict(
url='http://example.com',
data='{"foo":"bar"}',
)
)

assert result.data == '{"foo":"bar"}'
assert result.inferred_content_type == 'application/json'

def test_cookies_as_string(self):
result = Http.to_python(dict(
Expand Down
18 changes: 6 additions & 12 deletions tests/sentry/utils/http/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -351,30 +351,24 @@ class HeuristicDecodeTestCase(TestCase):
url_body = 'key=value&key2=value2'

def test_json(self):
data, content_type = heuristic_decode(self.json_body, 'application/json')
assert data == {'key': 'value', 'key2': 'value2'}
content_type = heuristic_decode(self.json_body, 'application/json')
assert content_type == 'application/json'

def test_url_encoded(self):
data, content_type = heuristic_decode(self.url_body, 'application/x-www-form-urlencoded')
assert data == {'key': ['value'], 'key2': ['value2']}
content_type = heuristic_decode(self.url_body, 'application/x-www-form-urlencoded')
assert content_type == 'application/x-www-form-urlencoded'

def test_possible_type_mismatch(self):
data, content_type = heuristic_decode(self.json_body, 'application/x-www-form-urlencoded')
assert data == {'key': 'value', 'key2': 'value2'}
content_type = heuristic_decode(self.json_body, 'application/x-www-form-urlencoded')
assert content_type == 'application/json'

data, content_type = heuristic_decode(self.url_body, 'application/json')
assert data == {'key': ['value'], 'key2': ['value2']}
content_type = heuristic_decode(self.url_body, 'application/json')
assert content_type == 'application/x-www-form-urlencoded'

def test_no_possible_type(self):
data, content_type = heuristic_decode(self.json_body)
assert data == {'key': 'value', 'key2': 'value2'}
content_type = heuristic_decode(self.json_body)
assert content_type == 'application/json'

def test_unable_to_decode(self):
data, content_type = heuristic_decode('string body', 'text/plain')
assert data == 'string body'
content_type = heuristic_decode('string body', 'text/plain')
assert content_type == 'text/plain'
42 changes: 6 additions & 36 deletions tests/sentry/web/api/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -464,12 +464,7 @@ def test_scrub_data_off(self, mock_insert_data_to_database):
assert resp.status_code == 200, (resp.status_code, resp.content)

call_data = mock_insert_data_to_database.call_args[0][0]
assert call_data['request']['data'] == {
'password': ['lol'],
'foo': ['1'],
'bar': ['2'],
'baz': ['3']
}
assert call_data['request']['data'] == "password=lol&foo=1&bar=2&baz=3"

@mock.patch('sentry.coreapi.ClientApiHelper.insert_data_to_database')
def test_scrub_data_on(self, mock_insert_data_to_database):
Expand All @@ -490,12 +485,7 @@ def test_scrub_data_on(self, mock_insert_data_to_database):
assert resp.status_code == 200, (resp.status_code, resp.content)

call_data = mock_insert_data_to_database.call_args[0][0]
assert call_data['request']['data'] == {
'password': ['lol'],
'foo': ['1'],
'bar': ['2'],
'baz': ['3']
}
assert call_data['request']['data'] == "password=lol&foo=1&bar=2&baz=3"

@mock.patch('sentry.coreapi.ClientApiHelper.insert_data_to_database')
def test_scrub_data_defaults(self, mock_insert_data_to_database):
Expand All @@ -516,12 +506,7 @@ def test_scrub_data_defaults(self, mock_insert_data_to_database):
assert resp.status_code == 200, (resp.status_code, resp.content)

call_data = mock_insert_data_to_database.call_args[0][0]
assert call_data['request']['data'] == {
'password': ['[Filtered]'],
'foo': ['1'],
'bar': ['2'],
'baz': ['3']
}
assert call_data['request']['data'] == "password=[Filtered]&foo=1&bar=2&baz=3"

@mock.patch('sentry.coreapi.ClientApiHelper.insert_data_to_database')
def test_scrub_data_sensitive_fields(self, mock_insert_data_to_database):
Expand All @@ -543,12 +528,7 @@ def test_scrub_data_sensitive_fields(self, mock_insert_data_to_database):
assert resp.status_code == 200, (resp.status_code, resp.content)

call_data = mock_insert_data_to_database.call_args[0][0]
assert call_data['request']['data'] == {
'password': ['[Filtered]'],
'foo': ['[Filtered]'],
'bar': ['[Filtered]'],
'baz': ['3']
}
assert call_data['request']['data'] == "password=[Filtered]&foo=[Filtered]&bar=[Filtered]&baz=3"

@mock.patch('sentry.coreapi.ClientApiHelper.insert_data_to_database')
def test_scrub_data_org_override(self, mock_insert_data_to_database):
Expand All @@ -571,12 +551,7 @@ def test_scrub_data_org_override(self, mock_insert_data_to_database):
assert resp.status_code == 200, (resp.status_code, resp.content)

call_data = mock_insert_data_to_database.call_args[0][0]
assert call_data['request']['data'] == {
'password': ['[Filtered]'],
'foo': ['1'],
'bar': ['2'],
'baz': ['3']
}
assert call_data['request']['data'] == "password=[Filtered]&foo=1&bar=2&baz=3"

@mock.patch('sentry.coreapi.ClientApiHelper.insert_data_to_database')
def test_scrub_data_org_override_sensitive_fields(self, mock_insert_data_to_database):
Expand All @@ -599,12 +574,7 @@ def test_scrub_data_org_override_sensitive_fields(self, mock_insert_data_to_data
assert resp.status_code == 200, (resp.status_code, resp.content)

call_data = mock_insert_data_to_database.call_args[0][0]
assert call_data['request']['data'] == {
'password': ['[Filtered]'],
'foo': ['[Filtered]'],
'bar': ['[Filtered]'],
'baz': ['[Filtered]']
}
assert call_data['request']['data'] == "password=[Filtered]&foo=[Filtered]&bar=[Filtered]&baz=[Filtered]"

@mock.patch('sentry.coreapi.ClientApiHelper.insert_data_to_database')
def test_uses_client_as_sdk(self, mock_insert_data_to_database):
Expand Down