forked from extern/httpie-cli
Use CRLF for headers in the output.
This commit is contained in:
parent
27f08920c4
commit
68640a81b3
@ -82,8 +82,7 @@ class HTTPResponse(HTTPMessage):
|
||||
return self._orig.iter_content(chunk_size=chunk_size)
|
||||
|
||||
def iter_lines(self, chunk_size):
|
||||
for line in self._orig.iter_lines(chunk_size):
|
||||
yield line, b'\n'
|
||||
return ((line, b'\n') for line in self._orig.iter_lines(chunk_size))
|
||||
|
||||
@property
|
||||
def headers(self):
|
||||
@ -92,9 +91,19 @@ class HTTPResponse(HTTPMessage):
|
||||
version='.'.join(str(original.version)),
|
||||
status=original.status,
|
||||
reason=original.reason
|
||||
)
|
||||
headers = str(original.msg)
|
||||
return '\n'.join([status_line, headers]).strip()
|
||||
)
|
||||
headers = [status_line]
|
||||
try:
|
||||
# `original.msg` is a `http.client.HTTPMessage` on Python 3
|
||||
# `_headers` is a 2-tuple
|
||||
headers.extend(
|
||||
'%s: %s' % header for header in original.msg._headers)
|
||||
except AttributeError:
|
||||
# and a `httplib.HTTPMessage` on Python 2.x
|
||||
# `headers` is a list of `name: val<CRLF>`.
|
||||
headers.extend(h.strip() for h in original.msg.headers)
|
||||
|
||||
return '\r\n'.join(headers)
|
||||
|
||||
@property
|
||||
def encoding(self):
|
||||
@ -151,7 +160,7 @@ class HTTPRequest(HTTPMessage):
|
||||
|
||||
headers.insert(0, request_line)
|
||||
|
||||
return '\n'.join(headers).strip()
|
||||
return '\r\n'.join(headers).strip()
|
||||
|
||||
@property
|
||||
def encoding(self):
|
||||
|
@ -85,8 +85,9 @@ def output_stream(args, env, request, response):
|
||||
with_headers=req_h,
|
||||
with_body=req_b))
|
||||
|
||||
if req and resp:
|
||||
output.append([b'\n\n\n'])
|
||||
if req_b and resp:
|
||||
# Request/Response separator.
|
||||
output.append([b'\n\n'])
|
||||
|
||||
if resp:
|
||||
output.append(Stream(
|
||||
@ -94,7 +95,9 @@ def output_stream(args, env, request, response):
|
||||
with_headers=resp_h,
|
||||
with_body=resp_b))
|
||||
|
||||
if env.stdout_isatty:
|
||||
if env.stdout_isatty and resp_b:
|
||||
# Ensure a blank line after the response body.
|
||||
# For terminal output only.
|
||||
output.append([b'\n\n'])
|
||||
|
||||
return chain(*output)
|
||||
@ -150,21 +153,12 @@ class BaseStream(object):
|
||||
"""Return an iterator over `self.msg`."""
|
||||
if self.with_headers:
|
||||
yield self._headers()
|
||||
yield b'\r\n\r\n'
|
||||
|
||||
if self.with_body:
|
||||
it = self._body()
|
||||
|
||||
try:
|
||||
if self.with_headers:
|
||||
# Yield the headers/body separator only if needed.
|
||||
chunk = next(it)
|
||||
if chunk:
|
||||
yield b'\n\n'
|
||||
yield chunk
|
||||
|
||||
for chunk in it:
|
||||
for chunk in self._body():
|
||||
yield chunk
|
||||
|
||||
except BinarySuppressedError as e:
|
||||
if self.with_headers:
|
||||
yield b'\n'
|
||||
@ -433,7 +427,7 @@ class HeadersProcessor(BaseProcessor):
|
||||
def process_headers(self, headers):
|
||||
lines = headers.splitlines()
|
||||
headers = sorted(lines[1:], key=lambda h: h.split(':')[0])
|
||||
return '\n'.join(lines[:1] + headers)
|
||||
return '\r\n'.join(lines[:1] + headers)
|
||||
|
||||
|
||||
class OutputProcessor(object):
|
||||
@ -460,7 +454,7 @@ class OutputProcessor(object):
|
||||
for group in groups:
|
||||
for cls in self.installed_processors[group]:
|
||||
processor = cls(env, **kwargs)
|
||||
if processor.enable:
|
||||
if processor.enabled:
|
||||
self.processors.append(processor)
|
||||
|
||||
def process_headers(self, headers):
|
||||
|
@ -26,6 +26,8 @@ import json
|
||||
import argparse
|
||||
import tempfile
|
||||
import unittest
|
||||
|
||||
CRLF = '\r\n'
|
||||
try:
|
||||
from urllib.request import urlopen
|
||||
except ImportError:
|
||||
@ -174,7 +176,6 @@ def http(*args, **kwargs):
|
||||
env.stderr.seek(0)
|
||||
|
||||
output = env.stdout.read()
|
||||
|
||||
try:
|
||||
r = StrResponse(output.decode('utf8'))
|
||||
except UnicodeDecodeError:
|
||||
@ -187,7 +188,7 @@ def http(*args, **kwargs):
|
||||
r.json = json.loads(r)
|
||||
elif r.count('Content-Type:') == 1 and 'application/json' in r:
|
||||
try:
|
||||
j = r.strip()[r.strip().rindex('\n\n'):]
|
||||
j = r.strip()[r.strip().rindex('\r\n\r\n'):]
|
||||
except ValueError:
|
||||
pass
|
||||
else:
|
||||
@ -1005,6 +1006,68 @@ class StreamTest(BaseTestCase):
|
||||
self.assertIn(BIN_FILE_CONTENT, r)
|
||||
|
||||
|
||||
class LineEndingsTest(BaseTestCase):
|
||||
"""Test that CRLF is properly used in headers and
|
||||
as the headers/body separator."""
|
||||
|
||||
def _validate_crlf(self, msg):
|
||||
#noinspection PyUnresolvedReferences
|
||||
lines = iter(msg.splitlines(True))
|
||||
for header in lines:
|
||||
if header == CRLF:
|
||||
break
|
||||
self.assertTrue(header.endswith(CRLF), repr(header))
|
||||
else:
|
||||
self.fail('CRLF between headers and body not found in %r' % msg)
|
||||
body = ''.join(lines)
|
||||
self.assertNotIn(CRLF, body)
|
||||
return body
|
||||
|
||||
def test_CRLF_headers_only(self):
|
||||
r = http(
|
||||
'--headers',
|
||||
'GET',
|
||||
httpbin('/get')
|
||||
)
|
||||
body = self._validate_crlf(r)
|
||||
self.assertFalse(body, 'Garbage after headers: %r' % r)
|
||||
|
||||
def test_CRLF_ugly_response(self):
|
||||
r = http(
|
||||
'--ugly',
|
||||
'GET',
|
||||
httpbin('/get')
|
||||
)
|
||||
self._validate_crlf(r)
|
||||
|
||||
def test_CRLF_formatted_response(self):
|
||||
r = http(
|
||||
'--format',
|
||||
'GET',
|
||||
httpbin('/get')
|
||||
)
|
||||
self.assertEqual(r.exit_status,0)
|
||||
self._validate_crlf(r)
|
||||
|
||||
def test_CRLF_ugly_request(self):
|
||||
r = http(
|
||||
'--ugly',
|
||||
'--print=HB',
|
||||
'GET',
|
||||
httpbin('/get')
|
||||
)
|
||||
self._validate_crlf(r)
|
||||
|
||||
def test_CRLF_formatted_request(self):
|
||||
r = http(
|
||||
'--format',
|
||||
'--print=HB',
|
||||
'GET',
|
||||
httpbin('/get')
|
||||
)
|
||||
self._validate_crlf(r)
|
||||
|
||||
|
||||
#################################################################
|
||||
# CLI argument parsing related tests.
|
||||
#################################################################
|
||||
|
Loading…
Reference in New Issue
Block a user