diff --git a/src/sentry/interfaces/http.py b/src/sentry/interfaces/http.py index bc5c96c39e3d16..1be88fa798c0b7 100644 --- a/src/sentry/interfaces/http.py +++ b/src/sentry/interfaces/http.py @@ -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) diff --git a/src/sentry/utils/http.py b/src/sentry/utils/http.py index 7ac23514234bff..2116e7e533edf6 100644 --- a/src/sentry/utils/http.py +++ b/src/sentry/utils/http.py @@ -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): diff --git a/tests/sentry/interfaces/test_http.py b/tests/sentry/interfaces/test_http.py index 60013aae30f516..468e9235843a70 100644 --- a/tests/sentry/interfaces/test_http.py +++ b/tests/sentry/interfaces/test_http.py @@ -79,7 +79,7 @@ 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', @@ -87,7 +87,43 @@ def test_form_encoded_data(self): 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( diff --git a/tests/sentry/utils/http/tests.py b/tests/sentry/utils/http/tests.py index 43ddc424413f83..c4a8d8e06e545d 100644 --- a/tests/sentry/utils/http/tests.py +++ b/tests/sentry/utils/http/tests.py @@ -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' diff --git a/tests/sentry/web/api/tests.py b/tests/sentry/web/api/tests.py index 8898e0ba59dab2..2be3afe8fc7f62 100644 --- a/tests/sentry/web/api/tests.py +++ b/tests/sentry/web/api/tests.py @@ -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): @@ -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): @@ -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): @@ -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): @@ -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): @@ -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):