mirror of
https://github.com/httpie/cli.git
synced 2024-11-24 16:53:35 +01:00
Added the option to print the request
It is now possible to print any combination of the following request-response bits: - Request headers (H) - Request body (B) - Response headers (h) - Response body (b) The output is controlled by the --print / -p option which defaults to "hb" (i.e., response headers and response body). Note that -p was previously shortcut for --prety. Closes #29.
This commit is contained in:
parent
31c28807c9
commit
02622a4135
2
LICENSE
2
LICENSE
@ -1,4 +1,4 @@
|
||||
Copyright © 2012 Jakub Roztocil
|
||||
Copyright © 2012 Jakub Roztocil <jakub@roztocil.name>
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
22
README.rst
22
README.rst
@ -89,9 +89,11 @@ Flags
|
||||
Most of the flags mirror the arguments understood by ``requests.request``. See ``http -h`` for more details::
|
||||
|
||||
usage: http [-h] [--version] [--json | --form] [--traceback]
|
||||
[--pretty | --ugly] [--headers | --body] [--style STYLE]
|
||||
[--auth AUTH] [--verify VERIFY] [--proxy PROXY]
|
||||
[--allow-redirects] [--file PATH] [--timeout TIMEOUT]
|
||||
[--pretty | --ugly]
|
||||
[--print OUTPUT_OPTIONS | --headers | --body]
|
||||
[--style STYLE] [--auth AUTH] [--verify VERIFY]
|
||||
[--proxy PROXY] [--allow-redirects] [--file PATH]
|
||||
[--timeout TIMEOUT]
|
||||
METHOD URL [items [items ...]]
|
||||
|
||||
HTTPie - cURL for humans.
|
||||
@ -113,13 +115,21 @@ Most of the flags mirror the arguments understood by ``requests.request``. See `
|
||||
Type to application/x-www-form-urlencoded, if not
|
||||
specified.
|
||||
--traceback Print exception traceback should one occur.
|
||||
--pretty, -p If stdout is a terminal, the response is prettified by
|
||||
--pretty If stdout is a terminal, the response is prettified by
|
||||
default (colorized and indented if it is JSON). This
|
||||
flag ensures prettifying even when stdout is
|
||||
redirected.
|
||||
--ugly, -u Do not prettify the response.
|
||||
--headers, -t Print only the response headers.
|
||||
--body, -b Print only the response body.
|
||||
--print OUTPUT_OPTIONS, -p OUTPUT_OPTIONS
|
||||
String specifying what should the output contain. "H"
|
||||
stands for request headers and "B" for request body.
|
||||
"h" stands for response headers and "b" for response
|
||||
body. Defaults to "hb" which means that the whole
|
||||
response (headers and body) is printed.
|
||||
--headers, -t Print only the response headers. It's a shortcut for
|
||||
--print=h.
|
||||
--body, -b Print only the response body. It's a shortcut for
|
||||
--print=b.
|
||||
--style STYLE, -s STYLE
|
||||
Output coloring style, one of autumn, borland, bw,
|
||||
colorful, default, emacs, friendly, fruity, manni,
|
||||
|
@ -3,5 +3,5 @@ HTTPie - cURL for humans.
|
||||
|
||||
"""
|
||||
__author__ = 'Jakub Roztocil'
|
||||
__version__ = '0.1.6'
|
||||
__version__ = '0.1.7-dev'
|
||||
__licence__ = 'BSD'
|
||||
|
@ -2,6 +2,7 @@
|
||||
import os
|
||||
import sys
|
||||
import json
|
||||
from urlparse import urlparse
|
||||
import requests
|
||||
try:
|
||||
from collections import OrderedDict
|
||||
@ -18,6 +19,69 @@ TYPE_FORM = 'application/x-www-form-urlencoded; charset=utf-8'
|
||||
TYPE_JSON = 'application/json; charset=utf-8'
|
||||
|
||||
|
||||
class HTTPMessage(object):
|
||||
|
||||
def __init__(self, line, headers, body, content_type=None):
|
||||
# {Request,Status}-Line
|
||||
self.line = line
|
||||
self.headers = headers
|
||||
self.body = body
|
||||
self.content_type = content_type
|
||||
|
||||
|
||||
def format_http_message(message, prettifier=None,
|
||||
with_headers=True, with_body=True):
|
||||
bits = []
|
||||
if with_headers:
|
||||
if prettifier:
|
||||
bits.append(prettifier.headers(message.line))
|
||||
bits.append(prettifier.headers(message.headers))
|
||||
else:
|
||||
bits.append(message.line)
|
||||
bits.append(message.headers)
|
||||
if with_body:
|
||||
bits.append('\n')
|
||||
if with_body:
|
||||
if prettifier and message.content_type:
|
||||
bits.append(prettifier.body(message.body, message.content_type))
|
||||
else:
|
||||
bits.append(message.body)
|
||||
bits = [bit.strip() for bit in bits]
|
||||
bits.append('')
|
||||
return '\n'.join(bits)
|
||||
|
||||
|
||||
def make_request_message(request):
|
||||
"""Make an `HTTPMessage` from `requests.models.Request`."""
|
||||
url = urlparse(request.url)
|
||||
request_headers = dict(request.headers)
|
||||
request_headers['Host'] = url.netloc
|
||||
return HTTPMessage(
|
||||
line='{method} {path} HTTP/1.1'.format(
|
||||
method=request.method,
|
||||
path=url.path),
|
||||
headers='\n'.join('%s: %s' % (name, value)
|
||||
for name, value
|
||||
in request_headers.iteritems()),
|
||||
body=request._enc_data,
|
||||
content_type=request_headers.get('Content-Type')
|
||||
)
|
||||
|
||||
|
||||
def make_response_message(response):
|
||||
"""Make an `HTTPMessage` from `requests.models.Response`."""
|
||||
encoding = response.encoding or 'ISO-8859-1'
|
||||
original = response.raw._original_response
|
||||
response_headers = response.headers
|
||||
return HTTPMessage(
|
||||
line='HTTP/{version} {status} {reason}'.format(
|
||||
version='.'.join(str(original.version)),
|
||||
status=original.status, reason=original.reason,),
|
||||
headers=str(original.msg).decode(encoding),
|
||||
body=response.content.decode(encoding) if response.content else u'',
|
||||
content_type=response_headers.get('Content-Type'))
|
||||
|
||||
|
||||
def main(args=None,
|
||||
stdin=sys.stdin,
|
||||
stdin_isatty=sys.stdin.isatty(),
|
||||
@ -28,7 +92,8 @@ def main(args=None,
|
||||
|
||||
args = parser.parse_args(args if args is not None else sys.argv[1:])
|
||||
do_prettify = (args.prettify is True or
|
||||
(args.prettify == cli.PRETTIFY_STDOUT_TTY_ONLY and stdout_isatty))
|
||||
(args.prettify == cli.PRETTIFY_STDOUT_TTY_ONLY
|
||||
and stdout_isatty))
|
||||
|
||||
# Parse request headers and data from the command line.
|
||||
headers = CaseInsensitiveDict()
|
||||
@ -79,36 +144,31 @@ def main(args=None,
|
||||
sys.stderr.write(str(e.message) + '\n')
|
||||
sys.exit(1)
|
||||
|
||||
# Reconstruct the raw response.
|
||||
encoding = response.encoding or 'ISO-8859-1'
|
||||
original = response.raw._original_response
|
||||
status_line, headers, body = (
|
||||
'HTTP/{version} {status} {reason}'.format(
|
||||
version='.'.join(str(original.version)),
|
||||
status=original.status, reason=original.reason,
|
||||
),
|
||||
str(original.msg).decode(encoding),
|
||||
response.content.decode(encoding) if response.content else u''
|
||||
)
|
||||
prettifier = pretty.PrettyHttp(args.style) if do_prettify else None
|
||||
|
||||
if do_prettify:
|
||||
prettify = pretty.PrettyHttp(args.style)
|
||||
if args.print_headers:
|
||||
status_line = prettify.headers(status_line)
|
||||
headers = prettify.headers(headers)
|
||||
if args.print_body and 'Content-Type' in response.headers:
|
||||
body = prettify.body(body, response.headers['Content-Type'])
|
||||
output_request = (cli.OUT_REQUEST_HEADERS in args.output_options
|
||||
or cli.OUT_REQUEST_BODY in args.output_options)
|
||||
|
||||
# Output.
|
||||
# TODO: preserve leading/trailing whitespaces in the body.
|
||||
# Some of the Pygments styles add superfluous line breaks.
|
||||
if args.print_headers:
|
||||
stdout.write(status_line.strip())
|
||||
output_response = (cli.OUT_RESPONSE_HEADERS in args.output_options
|
||||
or cli.OUT_RESPONSE_BODY in args.output_options)
|
||||
|
||||
if output_request:
|
||||
stdout.write(format_http_message(
|
||||
message=make_request_message(response.request),
|
||||
prettifier=prettifier,
|
||||
with_headers=cli.OUT_REQUEST_HEADERS in args.output_options,
|
||||
with_body=cli.OUT_REQUEST_BODY in args.output_options
|
||||
).encode('utf-8'))
|
||||
if output_response:
|
||||
stdout.write('\n')
|
||||
stdout.write(headers.strip().encode('utf-8'))
|
||||
stdout.write('\n\n')
|
||||
if args.print_body:
|
||||
stdout.write(body.strip().encode('utf-8'))
|
||||
|
||||
if output_response:
|
||||
stdout.write(format_http_message(
|
||||
message=make_response_message(response),
|
||||
prettifier=prettifier,
|
||||
with_headers=cli.OUT_RESPONSE_HEADERS in args.output_options,
|
||||
with_body=cli.OUT_RESPONSE_BODY in args.output_options
|
||||
).encode('utf-8'))
|
||||
stdout.write('\n')
|
||||
|
||||
|
||||
|
@ -12,6 +12,16 @@ SEP_DATA = '='
|
||||
SEP_DATA_RAW_JSON = ':='
|
||||
PRETTIFY_STDOUT_TTY_ONLY = object()
|
||||
|
||||
OUT_REQUEST_HEADERS = 'H'
|
||||
OUT_REQUEST_BODY = 'B'
|
||||
OUT_RESPONSE_HEADERS = 'h'
|
||||
OUT_RESPONSE_BODY = 'b'
|
||||
|
||||
OUTPUT_OPTIONS = [OUT_REQUEST_HEADERS,
|
||||
OUT_REQUEST_BODY,
|
||||
OUT_RESPONSE_HEADERS,
|
||||
OUT_RESPONSE_BODY]
|
||||
|
||||
|
||||
class ParseError(Exception):
|
||||
pass
|
||||
@ -72,7 +82,19 @@ def _(text):
|
||||
return ' '.join(text.strip().split())
|
||||
|
||||
|
||||
parser = argparse.ArgumentParser(description=doc.strip(),)
|
||||
class HTTPieArgumentParser(argparse.ArgumentParser):
|
||||
def parse_args(self, args=None, namespace=None):
|
||||
args = super(HTTPieArgumentParser, self).parse_args(args, namespace)
|
||||
self._validate_output_options(args)
|
||||
return args
|
||||
|
||||
def _validate_output_options(self, args):
|
||||
unknown_output_options = set(args.output_options) - set(OUTPUT_OPTIONS)
|
||||
if unknown_output_options:
|
||||
self.error('Unknown output options: %s' % ','.join(unknown_output_options))
|
||||
|
||||
|
||||
parser = HTTPieArgumentParser(description=doc.strip(),)
|
||||
parser.add_argument('--version', action='version', version=version)
|
||||
|
||||
# Content type.
|
||||
@ -96,7 +118,7 @@ group_type.add_argument(
|
||||
)
|
||||
|
||||
|
||||
# Output options.
|
||||
# output_options options.
|
||||
#############################################
|
||||
|
||||
parser.add_argument(
|
||||
@ -108,13 +130,12 @@ parser.add_argument(
|
||||
|
||||
prettify = parser.add_mutually_exclusive_group(required=False)
|
||||
prettify.add_argument(
|
||||
'--pretty', '-p', dest='prettify', action='store_true',
|
||||
'--pretty', dest='prettify', action='store_true',
|
||||
default=PRETTIFY_STDOUT_TTY_ONLY,
|
||||
help=_('''
|
||||
If stdout is a terminal,
|
||||
the response is prettified by default (colorized and
|
||||
indented if it is JSON). This flag ensures
|
||||
prettifying even when stdout is redirected.
|
||||
If stdout is a terminal, the response is prettified
|
||||
by default (colorized and indented if it is JSON).
|
||||
This flag ensures prettifying even when stdout is redirected.
|
||||
''')
|
||||
)
|
||||
prettify.add_argument(
|
||||
@ -124,21 +145,41 @@ prettify.add_argument(
|
||||
''')
|
||||
)
|
||||
|
||||
only = parser.add_mutually_exclusive_group(required=False)
|
||||
only.add_argument(
|
||||
'--headers', '-t', dest='print_body',
|
||||
action='store_false', default=True,
|
||||
help=('''
|
||||
output_options = parser.add_mutually_exclusive_group(required=False)
|
||||
output_options.add_argument('--print', '-p', dest='output_options',
|
||||
default=OUT_RESPONSE_HEADERS + OUT_RESPONSE_BODY,
|
||||
help=_('''
|
||||
String specifying what should the output contain.
|
||||
"{request_headers}" stands for request headers and
|
||||
"{request_body}" for request body.
|
||||
"{response_headers}" stands for response headers and
|
||||
"{response_body}" for response body.
|
||||
Defaults to "hb" which means that the whole response
|
||||
(headers and body) is printed.
|
||||
'''.format(
|
||||
request_headers=OUT_REQUEST_HEADERS,
|
||||
request_body=OUT_REQUEST_BODY,
|
||||
response_headers=OUT_RESPONSE_HEADERS,
|
||||
response_body=OUT_RESPONSE_BODY,
|
||||
))
|
||||
)
|
||||
output_options.add_argument(
|
||||
'--headers', '-t', dest='output_options',
|
||||
action='store_const', const=OUT_RESPONSE_HEADERS,
|
||||
help=_('''
|
||||
Print only the response headers.
|
||||
''')
|
||||
It's a shortcut for --print={0}.
|
||||
'''.format(OUT_RESPONSE_HEADERS))
|
||||
)
|
||||
only.add_argument(
|
||||
'--body', '-b', dest='print_headers',
|
||||
action='store_false', default=True,
|
||||
help=('''
|
||||
output_options.add_argument(
|
||||
'--body', '-b', dest='output_options',
|
||||
action='store_const', const=OUT_RESPONSE_BODY,
|
||||
help=_('''
|
||||
Print only the response body.
|
||||
''')
|
||||
It's a shortcut for --print={0}.
|
||||
'''.format(OUT_RESPONSE_BODY))
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--style', '-s', dest='style', default='solarized', metavar='STYLE',
|
||||
choices=pretty.AVAILABLE_STYLES,
|
||||
|
@ -8,8 +8,8 @@ from pygments.formatters.terminal256 import Terminal256Formatter
|
||||
from pygments.formatters.terminal import TerminalFormatter
|
||||
from pygments.lexer import RegexLexer, bygroups
|
||||
from pygments.styles import get_style_by_name, STYLE_MAP
|
||||
from . import solarized
|
||||
from .pygson import JSONLexer
|
||||
from . import solarized
|
||||
|
||||
|
||||
DEFAULT_STYLE = 'solarized'
|
||||
|
Loading…
Reference in New Issue
Block a user