Use CRLF for headers in the output.

This commit is contained in:
Jakub Roztocil 2012-08-10 01:07:01 +02:00
parent 27f08920c4
commit 68640a81b3
3 changed files with 90 additions and 24 deletions

View File

@ -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):
@ -93,8 +92,18 @@ class HTTPResponse(HTTPMessage):
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):

View File

@ -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'
for chunk in self._body():
yield chunk
for chunk in it:
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):

View File

@ -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.
#################################################################