1
0
mirror of https://github.com/httpie/cli.git synced 2024-11-28 08:38:44 +02:00

Added exit status for timed-out requests.

This commit is contained in:
Jakub Roztocil 2012-08-07 18:22:47 +02:00
parent 76feea2f68
commit c01dd8d64a
6 changed files with 52 additions and 40 deletions

View File

@ -7,7 +7,7 @@ v0.2.8dev
`README for stable version`_
HTTPie is a **command line HTTP client** whose goal is to make CLI interaction
with HTTP-based services as **human-friendly** as possible. It provides a
with web services as **human-friendly** as possible. It provides a
simple ``http`` command that allows for sending arbitrary HTTP requests with a
simple and natural syntax, and displays colorized responses. HTTPie can be used
for **testing, debugging**, and generally **interacting** with HTTP servers.
@ -82,7 +82,8 @@ Or, you can install the **development version** directly from GitHub:
There are also packages available for `Ubuntu`_, `Debian`_, and possibly other
Linux distributions as well.
Linux distributions as well. However, they may be a significant delay between
releases and package updates.
=====
@ -809,16 +810,18 @@ When using HTTPie from **shell scripts**, it can be handy to set the
``--check-status`` flag. It instructs HTTPie to exit with an error if the
HTTP status is one of ``3xx``, ``4xx``, or ``5xx``. The exit status will
be ``3`` (unless ``--allow-redirects`` is set), ``4``, or ``5``,
respectively:
respectively. Also, the ``--timeout`` option allows to overwrite the default
30s timeout:
.. code-block:: bash
#!/bin/bash
if http --check-status HEAD example.org/health &> /dev/null; then
if http --timeout=2.5 --check-status HEAD example.org/health &> /dev/null; then
echo 'OK!'
else
case $? in
2) echo 'Request timed out!' ;;
3) echo 'Unexpected HTTP 3xx Redirection!' ;;
4) echo 'HTTP 4xx Client Error!' ;;
5) echo 'HTTP 5xx Server Error!' ;;
@ -933,6 +936,7 @@ Changelog
=========
* `0.2.8dev`_
* Added exit status code ``2`` for timed-out requests.
* Added ``--colors`` and ``--format`` in addition to ``--pretty``, to
be able to separate colorizing and formatting.
* `0.2.7`_ (2012-08-07)

View File

@ -10,7 +10,9 @@ __licence__ = 'BSD'
class EXIT:
OK = 0
ERROR = 1
# Used only when requested:
ERROR_TIMEOUT = 2
# Used only when requested with --check-status:
ERROR_HTTP_3XX = 3
ERROR_HTTP_4XX = 4
ERROR_HTTP_5XX = 5

View File

@ -11,13 +11,11 @@ from . import __doc__
from . import __version__
from .output import AVAILABLE_STYLES, DEFAULT_STYLE
from .input import (Parser, AuthCredentialsArgType, KeyValueArgType,
PRETTY_STDOUT_TTY_ONLY,
SEP_PROXY, SEP_CREDENTIALS, SEP_GROUP_ITEMS,
OUT_REQ_HEAD, OUT_REQ_BODY, OUT_RESP_HEAD,
OUT_RESP_BODY, OUTPUT_OPTIONS,
PRETTY_STDOUT_TTY_ONLY, PRETTY_ALL,
PRETTY_FORMAT,
PRETTY_COLORS)
PRETTY_FORMAT, PRETTY_COLORS)
def _(text):
@ -49,7 +47,7 @@ group_type.add_argument(
The Content-Type is set to application/x-www-form-urlencoded
(if not specified).
The presence of any file fields results
into a multipart/form-data request.
in a multipart/form-data request.
''')
)
@ -57,7 +55,6 @@ group_type.add_argument(
# Output options.
#############################################
parser.add_argument(
'--output', '-o', type=argparse.FileType('w+b'),
metavar='FILE',
@ -65,7 +62,7 @@ parser.add_argument(
'''
Save output to FILE.
This option is a replacement for piping output to FILE,
which would on Windows result into corrupted data
which would on Windows result in corrupted data
being saved.
'''
@ -151,8 +148,8 @@ parser.add_argument(
''') % (', '.join(sorted(AVAILABLE_STYLES)), DEFAULT_STYLE)
)
parser.add_argument('--stream', '-S', action='store_true', default=False, help=_(
'''
parser.add_argument('--stream', '-S', action='store_true', default=False,
help=_('''
Always stream the output by line, i.e., behave like `tail -f'.
Without --stream and with --pretty (either set or implied),
@ -187,7 +184,7 @@ parser.add_argument(
# ``requests.request`` keyword arguments.
parser.add_argument(
'--auth', '-a',
'--auth', '-a', metavar='USER:PASS',
type=AuthCredentialsArgType(SEP_CREDENTIALS),
help=_('''
username:password.
@ -230,10 +227,10 @@ parser.add_argument(
''')
)
parser.add_argument(
'--timeout', type=float, default=30,
'--timeout', type=float, default=30, metavar='SECONDS',
help=_('''
The timeout of the request in seconds. The default value is 30
seconds.
The connection timeout of the request in seconds.
The default value is 30 seconds.
''')
)
parser.add_argument(

View File

@ -10,6 +10,7 @@ Invocation flow:
5. Exit.
"""
from _socket import gaierror
import sys
import json
import errno
@ -143,7 +144,7 @@ def main(args=sys.argv[1:], env=Environment()):
except IOError as e:
if not traceback and e.errno == errno.EPIPE:
# Ignore broken pipes unless --debug.
# Ignore broken pipes unless --traceback.
env.stderr.write('\n')
else:
raise
@ -153,7 +154,9 @@ def main(args=sys.argv[1:], env=Environment()):
raise
env.stderr.write('\n')
status = EXIT.ERROR
except requests.Timeout:
status = EXIT.ERROR_TIMEOUT
error('Request timed out (%ss).', args.timeout)
except Exception as e:
# TODO: distinguish between expected and unexpected errors.
# network errors vs. bugs, etc.

View File

@ -20,10 +20,9 @@ from .input import (OUT_REQ_BODY, OUT_REQ_HEAD,
OUT_RESP_HEAD, OUT_RESP_BODY)
# Colors on Windows via colorama aren't that great and fruity
# seems to give the best result there.
# Colors on Windows via colorama don't look that
# great and fruity seems to give the best result there.
DEFAULT_STYLE = 'solarized' if not is_windows else 'fruity'
#noinspection PySetFunctionToLiteral
AVAILABLE_STYLES = set([DEFAULT_STYLE]) | set(STYLE_MAP.keys())
@ -335,10 +334,9 @@ class BaseProcessor(object):
def __init__(self, env, **kwargs):
"""
:param env:
an class:`Environment` instance
:param kwargs:
additional keyword argument that some processor might require.
:param env: an class:`Environment` instance
:param kwargs: additional keyword argument that some
processor might require.
"""
self.env = env
@ -347,8 +345,7 @@ class BaseProcessor(object):
def process_headers(self, headers):
"""Return processed `headers`
:param headers:
The headers as text.
:param headers: The headers as text.
"""
return headers
@ -356,14 +353,9 @@ class BaseProcessor(object):
def process_body(self, content, content_type, subtype):
"""Return processed `content`.
:param content:
The body content as text
:param content_type:
Full content type, e.g., 'application/atom+xml'.
:param subtype:
E.g. 'xml'.
:param content: The body content as text
:param content_type: Full content type, e.g., 'application/atom+xml'.
:param subtype: E.g. 'xml'.
"""
return content
@ -458,13 +450,18 @@ class OutputProcessor(object):
}
def __init__(self, env, groups, **kwargs):
"""
:param env: a :class:`models.Environment` instance
:param groups: the groups of processors to be applied
:param kwargs: additional keyword arguments for processors
processors = []
"""
self.processors = []
for group in groups:
for cls in self.installed_processors[group]:
processors.append(cls(env, **kwargs))
self.processors = [p for p in processors if p.enabled]
processor = cls(env, **kwargs)
if processor.enable:
self.processors.append(processor)
def process_headers(self, headers):
for processor in self.processors:

View File

@ -860,6 +860,15 @@ class ExitStatusTest(BaseTestCase):
)
self.assertIn('HTTP/1.1 500', r)
self.assertEqual(r.exit_status, EXIT.OK)
self.assertTrue(not r.stderr)
def test_timeout_exit_status(self):
r = http(
'--timeout=0.5',
'GET',
httpbin('/delay/1')
)
self.assertEqual(r.exit_status, EXIT.ERROR_TIMEOUT)
def test_3xx_check_status_exits_3_and_stderr_when_stdout_redirected(self):
r = http(