mirror of
https://github.com/httpie/cli.git
synced 2025-02-26 22:40:52 +01:00
parent
38e8ef14ec
commit
dc4da527db
@ -10,6 +10,8 @@ This project adheres to `Semantic Versioning <http://semver.org/>`_.
|
|||||||
-------------------------
|
-------------------------
|
||||||
|
|
||||||
* Added ``Content-Type`` of files uploaded in ``multipart/form-data`` requests
|
* Added ``Content-Type`` of files uploaded in ``multipart/form-data`` requests
|
||||||
|
* Added ``--ssl=<PROTOCOL>`` to specify SSL/TLS the desired protocol version
|
||||||
|
to use for HTTPS requests.
|
||||||
* Added ``--show-redirects, -R`` to show intermediate responses with ``--follow``
|
* Added ``--show-redirects, -R`` to show intermediate responses with ``--follow``
|
||||||
* Added ``--max-redirects`` (default 30)
|
* Added ``--max-redirects`` (default 30)
|
||||||
* Added ``-A`` as short name for ``--auth-type``
|
* Added ``-A`` as short name for ``--auth-type``
|
||||||
|
16
README.rst
16
README.rst
@ -730,6 +730,22 @@ path of the key file with ``--cert-key``:
|
|||||||
$ http --cert=client.crt --cert-key=client.key https://example.org
|
$ http --cert=client.crt --cert-key=client.key https://example.org
|
||||||
|
|
||||||
|
|
||||||
|
-----------
|
||||||
|
SSL version
|
||||||
|
-----------
|
||||||
|
|
||||||
|
Use the ``--ssl=<PROTOCOL>`` to specify the desired protocol version to use.
|
||||||
|
This will default to SSL v2.3 which will negotiate the highest protocol that both
|
||||||
|
the server and your installation of OpenSSL support. The available protocols
|
||||||
|
are ``ssl2.3``, ``ssl3``, ``tls1``, ``tls1.1``, ```tls1.2``. (The actually
|
||||||
|
available set of protocols may vary depending your on OpenSSL installation.)
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
# Specify the vulnerable SSL v3 protocol to talk to an outdated server:
|
||||||
|
$ http --ssl=ssl3 https://vulnerable.example.org
|
||||||
|
|
||||||
|
|
||||||
----------------------------
|
----------------------------
|
||||||
SNI (Server Name Indication)
|
SNI (Server Name Indication)
|
||||||
----------------------------
|
----------------------------
|
||||||
|
@ -20,7 +20,7 @@ from httpie.input import (HTTPieArgumentParser,
|
|||||||
OUT_RESP_BODY, OUTPUT_OPTIONS,
|
OUT_RESP_BODY, OUTPUT_OPTIONS,
|
||||||
OUTPUT_OPTIONS_DEFAULT, PRETTY_MAP,
|
OUTPUT_OPTIONS_DEFAULT, PRETTY_MAP,
|
||||||
PRETTY_STDOUT_TTY_ONLY, SessionNameValidator,
|
PRETTY_STDOUT_TTY_ONLY, SessionNameValidator,
|
||||||
readable_file_arg)
|
readable_file_arg, SSL_VERSION_ARG_MAPPING)
|
||||||
|
|
||||||
|
|
||||||
class HTTPieHelpFormatter(RawDescriptionHelpFormatter):
|
class HTTPieHelpFormatter(RawDescriptionHelpFormatter):
|
||||||
@ -485,29 +485,6 @@ network.add_argument(
|
|||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
|
||||||
network.add_argument(
|
|
||||||
'--cert',
|
|
||||||
default=None,
|
|
||||||
type=readable_file_arg,
|
|
||||||
help="""
|
|
||||||
You can specify a local cert to use as client side SSL certificate.
|
|
||||||
This file may either contain both private key and certificate or you may
|
|
||||||
specify --cert-key separately.
|
|
||||||
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
|
|
||||||
network.add_argument(
|
|
||||||
'--cert-key',
|
|
||||||
default=None,
|
|
||||||
type=readable_file_arg,
|
|
||||||
help="""
|
|
||||||
The private key to use with SSL. Only needed if --cert is given and the
|
|
||||||
certificate file does not contain the private key.
|
|
||||||
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
|
|
||||||
network.add_argument(
|
network.add_argument(
|
||||||
'--timeout',
|
'--timeout',
|
||||||
type=float,
|
type=float,
|
||||||
@ -537,6 +514,46 @@ network.add_argument(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
#######################################################################
|
||||||
|
# SSL
|
||||||
|
#######################################################################
|
||||||
|
|
||||||
|
ssl = parser.add_argument_group(title='SSL')
|
||||||
|
ssl.add_argument(
|
||||||
|
'--ssl', # TODO: Maybe something more general, such as --secure-protocol?
|
||||||
|
dest='ssl_version',
|
||||||
|
choices=list(sorted(SSL_VERSION_ARG_MAPPING.keys())),
|
||||||
|
help="""
|
||||||
|
The desired protocol version to use. This will default to
|
||||||
|
SSL v2.3 which will negotiate the highest protocol that both
|
||||||
|
the server and your installation of OpenSSL support. Available protocols
|
||||||
|
may vary depending on OpenSSL installation (only the supported ones
|
||||||
|
are shown here).
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
ssl.add_argument(
|
||||||
|
'--cert',
|
||||||
|
default=None,
|
||||||
|
type=readable_file_arg,
|
||||||
|
help="""
|
||||||
|
You can specify a local cert to use as client side SSL certificate.
|
||||||
|
This file may either contain both private key and certificate or you may
|
||||||
|
specify --cert-key separately.
|
||||||
|
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
ssl.add_argument(
|
||||||
|
'--cert-key',
|
||||||
|
default=None,
|
||||||
|
type=readable_file_arg,
|
||||||
|
help="""
|
||||||
|
The private key to use with SSL. Only needed if --cert is given and the
|
||||||
|
certificate file does not contain the private key.
|
||||||
|
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
#######################################################################
|
#######################################################################
|
||||||
# Troubleshooting
|
# Troubleshooting
|
||||||
#######################################################################
|
#######################################################################
|
||||||
|
@ -3,11 +3,13 @@ import sys
|
|||||||
from pprint import pformat
|
from pprint import pformat
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
|
from requests.adapters import HTTPAdapter
|
||||||
from requests.packages import urllib3
|
from requests.packages import urllib3
|
||||||
|
|
||||||
from httpie import sessions
|
from httpie import sessions
|
||||||
from httpie import __version__
|
from httpie import __version__
|
||||||
from httpie.compat import str
|
from httpie.compat import str
|
||||||
|
from httpie.input import SSL_VERSION_ARG_MAPPING
|
||||||
from httpie.plugins import plugin_manager
|
from httpie.plugins import plugin_manager
|
||||||
|
|
||||||
|
|
||||||
@ -27,8 +29,23 @@ JSON = 'application/json'
|
|||||||
DEFAULT_UA = 'HTTPie/%s' % __version__
|
DEFAULT_UA = 'HTTPie/%s' % __version__
|
||||||
|
|
||||||
|
|
||||||
def get_requests_session():
|
class HTTPieHTTPAdapter(HTTPAdapter):
|
||||||
|
|
||||||
|
def __init__(self, ssl_version=None, **kwargs):
|
||||||
|
self._ssl_version = ssl_version
|
||||||
|
super(HTTPieHTTPAdapter, self).__init__(**kwargs)
|
||||||
|
|
||||||
|
def init_poolmanager(self, *args, **kwargs):
|
||||||
|
kwargs['ssl_version'] = self._ssl_version
|
||||||
|
super(HTTPieHTTPAdapter, self).init_poolmanager(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
def get_requests_session(ssl_version):
|
||||||
requests_session = requests.Session()
|
requests_session = requests.Session()
|
||||||
|
requests_session.mount(
|
||||||
|
'https://',
|
||||||
|
HTTPieHTTPAdapter(ssl_version=ssl_version)
|
||||||
|
)
|
||||||
for cls in plugin_manager.get_transport_plugins():
|
for cls in plugin_manager.get_transport_plugins():
|
||||||
transport_plugin = cls()
|
transport_plugin = cls()
|
||||||
requests_session.mount(prefix=transport_plugin.prefix,
|
requests_session.mount(prefix=transport_plugin.prefix,
|
||||||
@ -38,7 +55,12 @@ def get_requests_session():
|
|||||||
|
|
||||||
def get_response(args, config_dir):
|
def get_response(args, config_dir):
|
||||||
"""Send the request and return a `request.Response`."""
|
"""Send the request and return a `request.Response`."""
|
||||||
requests_session = get_requests_session()
|
|
||||||
|
ssl_version = None
|
||||||
|
if args.ssl_version:
|
||||||
|
ssl_version = SSL_VERSION_ARG_MAPPING[args.ssl_version]
|
||||||
|
|
||||||
|
requests_session = get_requests_session(ssl_version)
|
||||||
requests_session.max_redirects = args.max_redirects
|
requests_session.max_redirects = args.max_redirects
|
||||||
|
|
||||||
if not args.session and not args.session_read_only:
|
if not args.session and not args.session_read_only:
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
import os
|
import os
|
||||||
|
import ssl
|
||||||
import sys
|
import sys
|
||||||
import re
|
import re
|
||||||
import errno
|
import errno
|
||||||
@ -103,6 +104,20 @@ OUTPUT_OPTIONS_DEFAULT = OUT_RESP_HEAD + OUT_RESP_BODY
|
|||||||
OUTPUT_OPTIONS_DEFAULT_STDOUT_REDIRECTED = OUT_RESP_BODY
|
OUTPUT_OPTIONS_DEFAULT_STDOUT_REDIRECTED = OUT_RESP_BODY
|
||||||
|
|
||||||
|
|
||||||
|
SSL_VERSION_ARG_MAPPING = {
|
||||||
|
'ssl2.3': 'PROTOCOL_SSLv23',
|
||||||
|
'ssl3': 'PROTOCOL_SSLv3',
|
||||||
|
'tls1': 'PROTOCOL_TLSv1',
|
||||||
|
'tls1.1': 'PROTOCOL_TLSv1_1',
|
||||||
|
'tls1.2': 'PROTOCOL_TLSv1_2',
|
||||||
|
}
|
||||||
|
SSL_VERSION_ARG_MAPPING = dict(
|
||||||
|
(cli_arg, getattr(ssl, ssl_constant))
|
||||||
|
for cli_arg, ssl_constant in SSL_VERSION_ARG_MAPPING.items()
|
||||||
|
if hasattr(ssl, ssl_constant)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class HTTPieArgumentParser(ArgumentParser):
|
class HTTPieArgumentParser(ArgumentParser):
|
||||||
"""Adds additional logic to `argparse.ArgumentParser`.
|
"""Adds additional logic to `argparse.ArgumentParser`.
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ import pytest_httpbin.certs
|
|||||||
from requests.exceptions import SSLError
|
from requests.exceptions import SSLError
|
||||||
|
|
||||||
from httpie import ExitStatus
|
from httpie import ExitStatus
|
||||||
|
from httpie.input import SSL_VERSION_ARG_MAPPING
|
||||||
from utils import http, HTTP_OK, TESTS_ROOT
|
from utils import http, HTTP_OK, TESTS_ROOT
|
||||||
|
|
||||||
|
|
||||||
@ -18,6 +19,26 @@ CLIENT_PEM = os.path.join(TESTS_ROOT, 'client_certs', 'client.pem')
|
|||||||
CA_BUNDLE = pytest_httpbin.certs.where()
|
CA_BUNDLE = pytest_httpbin.certs.where()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
argnames='ssl_version',
|
||||||
|
argvalues=SSL_VERSION_ARG_MAPPING.keys()
|
||||||
|
)
|
||||||
|
def test_ssl_version(httpbin_secure, ssl_version):
|
||||||
|
try:
|
||||||
|
r = http(
|
||||||
|
'--verify', CA_BUNDLE,
|
||||||
|
'--ssl', ssl_version,
|
||||||
|
httpbin_secure + '/get'
|
||||||
|
)
|
||||||
|
assert HTTP_OK in r
|
||||||
|
except SSLError as e:
|
||||||
|
if ssl_version == 'ssl3':
|
||||||
|
# pytest-httpbin doesn't support ssl3
|
||||||
|
assert 'SSLV3_ALERT_HANDSHAKE_FAILURE' in str(e)
|
||||||
|
else:
|
||||||
|
raise
|
||||||
|
|
||||||
|
|
||||||
class TestClientCert:
|
class TestClientCert:
|
||||||
|
|
||||||
def test_cert_and_key(self, httpbin_secure):
|
def test_cert_and_key(self, httpbin_secure):
|
||||||
|
Loading…
Reference in New Issue
Block a user