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
20 changes: 18 additions & 2 deletions httpie/cli/nested_json/parse.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,15 +137,16 @@ def send_buffer() -> Iterator[Token]:
value = ''.join(buffer)
kind = TokenKind.TEXT
if not backslashes:
for variation, kind in [
(int, TokenKind.NUMBER),
for variation, variation_kind in [
(canonical_int, TokenKind.NUMBER),
(check_escaped_int, TokenKind.TEXT),
]:
try:
value = variation(value)
except ValueError:
continue
else:
kind = variation_kind
break
yield Token(
kind=kind,
Expand Down Expand Up @@ -189,5 +190,20 @@ def check_escaped_int(value: str) -> str:
return value[1:]


def canonical_int(value: str) -> int:
"""Convert to int only when the value has no leading zeros.

A literal such as ``01`` is a valid JSON *key*, not a number - JSON
numbers can't have leading zeros. Coercing it to ``int`` silently
rewrites the key to ``1`` and can collide with a real ``1`` key.
"""
if not value:
raise ValueError('Not an int')
converted = int(value)
if str(converted) != value:
raise ValueError('Not a canonical int')
return converted


def assert_cant_happen():
raise ValueError('Unexpected value')
2 changes: 1 addition & 1 deletion httpie/output/writer.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ def get_stream_type_and_kwargs(
raw_content_type_header = headers.get('Content-Type', None)
if raw_content_type_header:
content_type_header, _ = parse_content_type_header(raw_content_type_header)
is_stream = (content_type_header == 'text/event-stream')
is_stream = (content_type_header.lower() == 'text/event-stream')

if not env.stdout_isatty and not prettify_groups:
stream_class = RawStream
Expand Down
10 changes: 10 additions & 0 deletions tests/test_json.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,16 @@ def test_complex_json_arguments_with_non_json(httpbin, request_type, value):
],
{'bottle-on-wall': [1, 2, 3]},
),
(
# Leading-zero keys stay keys and don't collide with '1'
['01=x', '1=y'],
{'01': 'x', '1': 'y'},
),
(
# ...but canonical integers still become numeric indices in paths
['kids[0]=Thelma', 'kids[10]=Ashley'],
{'kids': ['Thelma', None, None, None, None, None, None, None, None, None, 'Ashley']},
),
(
[
'pet[species]=Dahut',
Expand Down
4 changes: 4 additions & 0 deletions tests/test_stream.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,10 @@ def test_redirected_stream(httpbin):
['Accept:text/event-stream; charset=utf-8'],
3
),
(
['Accept:Text/Event-Stream'],
3
),
(
['Accept:text/plain'],
1
Expand Down
Loading