-
Notifications
You must be signed in to change notification settings - Fork 3.8k
Improve JSON output when there is leading data before the actual JSON body #1130
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
Merged
BoboTiG
merged 2 commits into
httpie:master
from
BoboTiG:mickael/dev-212-add-support-for-xssi-vulnerability
Sep 21, 2021
Merged
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,49 @@ | ||
| import pygments | ||
|
|
||
|
|
||
| class SimplifiedHTTPLexer(pygments.lexer.RegexLexer): | ||
| """Simplified HTTP lexer for Pygments. | ||
|
|
||
| It only operates on headers and provides a stronger contrast between | ||
| their names and values than the original one bundled with Pygments | ||
| (:class:`pygments.lexers.text import HttpLexer`), especially when | ||
| Solarized color scheme is used. | ||
|
|
||
| """ | ||
| name = 'HTTP' | ||
| aliases = ['http'] | ||
| filenames = ['*.http'] | ||
| tokens = { | ||
| 'root': [ | ||
| # Request-Line | ||
| (r'([A-Z]+)( +)([^ ]+)( +)(HTTP)(/)(\d+\.\d+)', | ||
| pygments.lexer.bygroups( | ||
| pygments.token.Name.Function, | ||
| pygments.token.Text, | ||
| pygments.token.Name.Namespace, | ||
| pygments.token.Text, | ||
| pygments.token.Keyword.Reserved, | ||
| pygments.token.Operator, | ||
| pygments.token.Number | ||
| )), | ||
| # Response Status-Line | ||
| (r'(HTTP)(/)(\d+\.\d+)( +)(\d{3})( +)(.+)', | ||
| pygments.lexer.bygroups( | ||
| pygments.token.Keyword.Reserved, # 'HTTP' | ||
| pygments.token.Operator, # '/' | ||
| pygments.token.Number, # Version | ||
| pygments.token.Text, | ||
| pygments.token.Number, # Status code | ||
| pygments.token.Text, | ||
| pygments.token.Name.Exception, # Reason | ||
| )), | ||
| # Header | ||
| (r'(.*?)( *)(:)( *)(.+)', pygments.lexer.bygroups( | ||
| pygments.token.Name.Attribute, # Name | ||
| pygments.token.Text, | ||
| pygments.token.Operator, # Colon | ||
| pygments.token.Text, | ||
| pygments.token.String # Value | ||
| )) | ||
| ] | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| import re | ||
|
|
||
| from pygments.lexer import bygroups, using, RegexLexer | ||
| from pygments.lexers.data import JsonLexer | ||
| from pygments.token import Token | ||
|
|
||
| PREFIX_TOKEN = Token.Error | ||
| PREFIX_REGEX = r'[^{\["]+' | ||
|
|
||
|
|
||
| class EnhancedJsonLexer(RegexLexer): | ||
| """ | ||
| Enhanced JSON lexer for Pygments. | ||
|
|
||
| It adds support for eventual data prefixing the actual JSON body. | ||
|
|
||
| """ | ||
| name = 'JSON' | ||
| flags = re.IGNORECASE | re.DOTALL | ||
| tokens = { | ||
| 'root': [ | ||
| # Eventual non-JSON data prefix followed by actual JSON body. | ||
| # FIX: data prefix + number (integer or float) are not correctly handled. | ||
| ( | ||
| fr'({PREFIX_REGEX})' + r'((?:[{\["]|true|false|null).+)', | ||
| bygroups(PREFIX_TOKEN, using(JsonLexer)) | ||
| ), | ||
| # JSON body. | ||
| (r'.+', using(JsonLexer)), | ||
| ], | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| import json | ||
| import re | ||
| from typing import Tuple | ||
|
|
||
| from .lexers.json import PREFIX_REGEX | ||
|
|
||
|
|
||
| def load_prefixed_json(data: str) -> Tuple[str, json.JSONDecoder]: | ||
| """Simple JSON loading from `data`. | ||
|
|
||
| """ | ||
| # First, the full data. | ||
| try: | ||
| return '', json.loads(data) | ||
| except ValueError: | ||
| pass | ||
|
|
||
| # Then, try to find the start of the actual body. | ||
| data_prefix, body = parse_prefixed_json(data) | ||
| try: | ||
| return data_prefix, json.loads(body) | ||
| except ValueError: | ||
| raise ValueError('Invalid JSON') | ||
|
|
||
|
|
||
| def parse_prefixed_json(data: str) -> Tuple[str, str]: | ||
| """Find the potential JSON body from `data`. | ||
|
|
||
| Sometimes the JSON body is prefixed with a XSSI magic string, specific to the server. | ||
| Return a tuple (data prefix, actual JSON body). | ||
|
|
||
| """ | ||
| matches = re.findall(PREFIX_REGEX, data) | ||
| data_prefix = matches[0] if matches else '' | ||
| body = data[len(data_prefix):] | ||
| return data_prefix, body |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| import json | ||
|
|
||
| import pytest | ||
| import responses | ||
|
|
||
| from httpie.cli.constants import PRETTY_MAP | ||
| from httpie.compat import is_windows | ||
| from httpie.output.formatters.colors import ColorFormatter | ||
|
|
||
| from .utils import MockEnvironment, http, URL_EXAMPLE | ||
|
|
||
| TEST_JSON_XXSI_PREFIXES = (r")]}',\n", ")]}',", 'while(1);', 'for(;;)', ')', ']', '}') | ||
| TEST_JSON_VALUES = ({}, {'a': 0, 'b': 0}, [], ['a', 'b'], 'foo', True, False, None) # FIX: missing int & float | ||
| TEST_PREFIX_TOKEN_COLOR = '\x1b[38;5;15m' if is_windows else '\x1b[04m\x1b[91m' | ||
|
|
||
|
|
||
| @pytest.mark.parametrize('data_prefix', TEST_JSON_XXSI_PREFIXES) | ||
| @pytest.mark.parametrize('json_data', TEST_JSON_VALUES) | ||
| @pytest.mark.parametrize('pretty', PRETTY_MAP.keys()) | ||
| @responses.activate | ||
| def test_json_formatter_with_body_preceded_by_non_json_data(data_prefix, json_data, pretty): | ||
| """Test JSON bodies preceded by non-JSON data.""" | ||
| body = data_prefix + json.dumps(json_data) | ||
| content_type = 'application/json' | ||
| responses.add(responses.GET, URL_EXAMPLE, body=body, | ||
| content_type=content_type) | ||
|
|
||
| colored_output = pretty in ('all', 'colors') | ||
| env = MockEnvironment(colors=256) if colored_output else None | ||
| r = http('--pretty=' + pretty, URL_EXAMPLE, env=env) | ||
|
|
||
| indent = None if pretty in ('none', 'colors') else 4 | ||
| expected_body = data_prefix + json.dumps(json_data, indent=indent) | ||
| if colored_output: | ||
| fmt = ColorFormatter(env, format_options={'json': {'format': True, 'indent': 4}}) | ||
| expected_body = fmt.format_body(expected_body, content_type) | ||
| # Check to ensure the non-JSON data prefix is colored only one time, | ||
| # meaning it was correctly handled as a whole. | ||
| assert TEST_PREFIX_TOKEN_COLOR + data_prefix in expected_body, expected_body | ||
| assert expected_body in r | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.