mirror of
https://github.com/httpie/cli.git
synced 2024-11-28 18:53:21 +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
|
Redistribution and use in source and binary forms, with or without
|
||||||
modification, are permitted provided that the following conditions are met:
|
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::
|
Most of the flags mirror the arguments understood by ``requests.request``. See ``http -h`` for more details::
|
||||||
|
|
||||||
usage: http [-h] [--version] [--json | --form] [--traceback]
|
usage: http [-h] [--version] [--json | --form] [--traceback]
|
||||||
[--pretty | --ugly] [--headers | --body] [--style STYLE]
|
[--pretty | --ugly]
|
||||||
[--auth AUTH] [--verify VERIFY] [--proxy PROXY]
|
[--print OUTPUT_OPTIONS | --headers | --body]
|
||||||
[--allow-redirects] [--file PATH] [--timeout TIMEOUT]
|
[--style STYLE] [--auth AUTH] [--verify VERIFY]
|
||||||
|
[--proxy PROXY] [--allow-redirects] [--file PATH]
|
||||||
|
[--timeout TIMEOUT]
|
||||||
METHOD URL [items [items ...]]
|
METHOD URL [items [items ...]]
|
||||||
|
|
||||||
HTTPie - cURL for humans.
|
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
|
Type to application/x-www-form-urlencoded, if not
|
||||||
specified.
|
specified.
|
||||||
--traceback Print exception traceback should one occur.
|
--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
|
default (colorized and indented if it is JSON). This
|
||||||
flag ensures prettifying even when stdout is
|
flag ensures prettifying even when stdout is
|
||||||
redirected.
|
redirected.
|
||||||
--ugly, -u Do not prettify the response.
|
--ugly, -u Do not prettify the response.
|
||||||
--headers, -t Print only the response headers.
|
--print OUTPUT_OPTIONS, -p OUTPUT_OPTIONS
|
||||||
--body, -b Print only the response body.
|
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
|
--style STYLE, -s STYLE
|
||||||
Output coloring style, one of autumn, borland, bw,
|
Output coloring style, one of autumn, borland, bw,
|
||||||
colorful, default, emacs, friendly, fruity, manni,
|
colorful, default, emacs, friendly, fruity, manni,
|
||||||
|
@ -3,5 +3,5 @@ HTTPie - cURL for humans.
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
__author__ = 'Jakub Roztocil'
|
__author__ = 'Jakub Roztocil'
|
||||||
__version__ = '0.1.6'
|
__version__ = '0.1.7-dev'
|
||||||
__licence__ = 'BSD'
|
__licence__ = 'BSD'
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import json
|
import json
|
||||||
|
from urlparse import urlparse
|
||||||
import requests
|
import requests
|
||||||
try:
|
try:
|
||||||
from collections import OrderedDict
|
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'
|
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,
|
def main(args=None,
|
||||||
stdin=sys.stdin,
|
stdin=sys.stdin,
|
||||||
stdin_isatty=sys.stdin.isatty(),
|
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:])
|
args = parser.parse_args(args if args is not None else sys.argv[1:])
|
||||||
do_prettify = (args.prettify is True or
|
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.
|
# Parse request headers and data from the command line.
|
||||||
headers = CaseInsensitiveDict()
|
headers = CaseInsensitiveDict()
|
||||||
@ -79,36 +144,31 @@ def main(args=None,
|
|||||||
sys.stderr.write(str(e.message) + '\n')
|
sys.stderr.write(str(e.message) + '\n')
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
# Reconstruct the raw response.
|
prettifier = pretty.PrettyHttp(args.style) if do_prettify else None
|
||||||
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''
|
|
||||||
)
|
|
||||||
|
|
||||||
if do_prettify:
|
output_request = (cli.OUT_REQUEST_HEADERS in args.output_options
|
||||||
prettify = pretty.PrettyHttp(args.style)
|
or cli.OUT_REQUEST_BODY in args.output_options)
|
||||||
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.
|
output_response = (cli.OUT_RESPONSE_HEADERS in args.output_options
|
||||||
# TODO: preserve leading/trailing whitespaces in the body.
|
or cli.OUT_RESPONSE_BODY in args.output_options)
|
||||||
# Some of the Pygments styles add superfluous line breaks.
|
|
||||||
if args.print_headers:
|
if output_request:
|
||||||
stdout.write(status_line.strip())
|
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('\n')
|
||||||
stdout.write(headers.strip().encode('utf-8'))
|
|
||||||
stdout.write('\n\n')
|
if output_response:
|
||||||
if args.print_body:
|
stdout.write(format_http_message(
|
||||||
stdout.write(body.strip().encode('utf-8'))
|
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')
|
stdout.write('\n')
|
||||||
|
|
||||||
|
|
||||||
|
@ -12,6 +12,16 @@ SEP_DATA = '='
|
|||||||
SEP_DATA_RAW_JSON = ':='
|
SEP_DATA_RAW_JSON = ':='
|
||||||
PRETTIFY_STDOUT_TTY_ONLY = object()
|
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):
|
class ParseError(Exception):
|
||||||
pass
|
pass
|
||||||
@ -72,7 +82,19 @@ def _(text):
|
|||||||
return ' '.join(text.strip().split())
|
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)
|
parser.add_argument('--version', action='version', version=version)
|
||||||
|
|
||||||
# Content type.
|
# Content type.
|
||||||
@ -96,7 +118,7 @@ group_type.add_argument(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
# Output options.
|
# output_options options.
|
||||||
#############################################
|
#############################################
|
||||||
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
@ -108,13 +130,12 @@ parser.add_argument(
|
|||||||
|
|
||||||
prettify = parser.add_mutually_exclusive_group(required=False)
|
prettify = parser.add_mutually_exclusive_group(required=False)
|
||||||
prettify.add_argument(
|
prettify.add_argument(
|
||||||
'--pretty', '-p', dest='prettify', action='store_true',
|
'--pretty', dest='prettify', action='store_true',
|
||||||
default=PRETTIFY_STDOUT_TTY_ONLY,
|
default=PRETTIFY_STDOUT_TTY_ONLY,
|
||||||
help=_('''
|
help=_('''
|
||||||
If stdout is a terminal,
|
If stdout is a terminal, the response is prettified
|
||||||
the response is prettified by default (colorized and
|
by default (colorized and indented if it is JSON).
|
||||||
indented if it is JSON). This flag ensures
|
This flag ensures prettifying even when stdout is redirected.
|
||||||
prettifying even when stdout is redirected.
|
|
||||||
''')
|
''')
|
||||||
)
|
)
|
||||||
prettify.add_argument(
|
prettify.add_argument(
|
||||||
@ -124,21 +145,41 @@ prettify.add_argument(
|
|||||||
''')
|
''')
|
||||||
)
|
)
|
||||||
|
|
||||||
only = parser.add_mutually_exclusive_group(required=False)
|
output_options = parser.add_mutually_exclusive_group(required=False)
|
||||||
only.add_argument(
|
output_options.add_argument('--print', '-p', dest='output_options',
|
||||||
'--headers', '-t', dest='print_body',
|
default=OUT_RESPONSE_HEADERS + OUT_RESPONSE_BODY,
|
||||||
action='store_false', default=True,
|
help=_('''
|
||||||
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.
|
Print only the response headers.
|
||||||
''')
|
It's a shortcut for --print={0}.
|
||||||
|
'''.format(OUT_RESPONSE_HEADERS))
|
||||||
)
|
)
|
||||||
only.add_argument(
|
output_options.add_argument(
|
||||||
'--body', '-b', dest='print_headers',
|
'--body', '-b', dest='output_options',
|
||||||
action='store_false', default=True,
|
action='store_const', const=OUT_RESPONSE_BODY,
|
||||||
help=('''
|
help=_('''
|
||||||
Print only the response body.
|
Print only the response body.
|
||||||
''')
|
It's a shortcut for --print={0}.
|
||||||
|
'''.format(OUT_RESPONSE_BODY))
|
||||||
)
|
)
|
||||||
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'--style', '-s', dest='style', default='solarized', metavar='STYLE',
|
'--style', '-s', dest='style', default='solarized', metavar='STYLE',
|
||||||
choices=pretty.AVAILABLE_STYLES,
|
choices=pretty.AVAILABLE_STYLES,
|
||||||
|
@ -8,8 +8,8 @@ from pygments.formatters.terminal256 import Terminal256Formatter
|
|||||||
from pygments.formatters.terminal import TerminalFormatter
|
from pygments.formatters.terminal import TerminalFormatter
|
||||||
from pygments.lexer import RegexLexer, bygroups
|
from pygments.lexer import RegexLexer, bygroups
|
||||||
from pygments.styles import get_style_by_name, STYLE_MAP
|
from pygments.styles import get_style_by_name, STYLE_MAP
|
||||||
from . import solarized
|
|
||||||
from .pygson import JSONLexer
|
from .pygson import JSONLexer
|
||||||
|
from . import solarized
|
||||||
|
|
||||||
|
|
||||||
DEFAULT_STYLE = 'solarized'
|
DEFAULT_STYLE = 'solarized'
|
||||||
|
Loading…
Reference in New Issue
Block a user