diff --git a/MANIFEST.in b/MANIFEST.in index a09a3037eb..da82b78fe4 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -6,3 +6,7 @@ include docs/README.md # recursive-include tests/ * +include extras/httpie-completion.fish +include extras/httpie-completion.bash +include extras/fish/http.fish +include extras/bash-completion/http diff --git a/extras/bash-completion/http b/extras/bash-completion/http new file mode 100644 index 0000000000..6abbc2176a --- /dev/null +++ b/extras/bash-completion/http @@ -0,0 +1,20 @@ +_http_complete() { + local cur_word=${COMP_WORDS[COMP_CWORD]} + local prev_word=${COMP_WORDS[COMP_CWORD - 1]} + + if [[ "$cur_word" == -* ]]; then + _http_complete_options "$cur_word" + fi +} + +complete -o default -F _http_complete http httpie.http httpie.https https + +_http_complete_options() { + local cur_word=$1 + local options="-j --json -f --form --pretty -s --style -p --print + -v --verbose -h --headers -b --body -S --stream -o --output -d --download + -c --continue --session --session-read-only -a --auth --auth-type --proxy + --follow --verify --cert --cert-key --timeout --check-status --ignore-stdin + --help --version --traceback --debug --raw" + COMPREPLY=( $( compgen -W "$options" -- "$cur_word" ) ) +} diff --git a/extras/fish/http.fish b/extras/fish/http.fish new file mode 100644 index 0000000000..c0cfc20ad9 --- /dev/null +++ b/extras/fish/http.fish @@ -0,0 +1,119 @@ +function __fish_httpie_styles + printf '%s\n' abap algol algol_nu arduino auto autumn borland bw colorful default emacs friendly fruity gruvbox-dark gruvbox-light igor inkpot lovelace manni material monokai murphy native paraiso-dark paraiso-light pastie perldoc pie pie-dark pie-light rainbow_dash rrt sas solarized solarized-dark solarized-light stata stata-dark stata-light tango trac vim vs xcode zenburn +end + +function __fish_httpie_mime_types + test -r /usr/share/mime/types && cat /usr/share/mime/types +end + +function __fish_httpie_print_args + set -l arg (commandline -t) + string match -qe H "$arg" || echo -e $arg"H\trequest headers" + string match -qe B "$arg" || echo -e $arg"B\trequest body" + string match -qe h "$arg" || echo -e $arg"h\tresponse headers" + string match -qe b "$arg" || echo -e $arg"b\tresponse body" + string match -qe m "$arg" || echo -e $arg"m\tresponse metadata" +end + +function __fish_httpie_auth_types + echo -e "basic\tBasic HTTP auth" + echo -e "digest\tDigest HTTP auth" + echo -e "bearer\tBearer HTTP Auth" +end + +function __fish_http_verify_options + echo -e "yes\tEnable cert verification" + echo -e "no\tDisable cert verification" +end + + +# Predefined Content Types + +complete -c http -s j -l json -d 'Data items are serialized as a JSON object' +complete -c http -s f -l form -d 'Data items are serialized as form fields' +complete -c http -l multipart -d 'Always sends a multipart/form-data request' +complete -c http -l boundary -x -d 'Custom boundary string for multipart/form-data requests' +complete -c http -l raw -x -d 'Pass raw request data without extra processing' + + +# Content Processing Options + +complete -c http -s x -l compress -d 'Content compressed with Deflate algorithm' + + +# Output Processing + +complete -c http -l pretty -xa "all colors format none" -d 'Controls output processing' +complete -c http -s s -l style -xa "(__fish_httpie_styles)" -d 'Output coloring style' +complete -c http -l unsorted -d 'Disables all sorting while formatting output' +complete -c http -l sorted -d 'Re-enables all sorting options while formatting output' +complete -c http -l response-charset -x -d 'Override the response encoding' +complete -c http -l response-mime -xa "(__fish_httpie_mime_types)" -d 'Override the response mime type for coloring and formatting' +complete -c http -l format-options -x -d 'Controls output formatting' + + +# Output Options + +complete -c http -s p -l print -xa "(__fish_httpie_print_args)" -d 'String specifying what the output should contain' +complete -c http -s h -l headers -d 'Print only the response headers' +complete -c http -s m -l meta -d 'Print only the response metadata' +complete -c http -s b -l body -d 'Print only the response body' +complete -c http -s v -l verbose -d 'Print the whole request as well as the response' +complete -c http -l all -d 'Show any intermediary requests/responses' +complete -c http -s S -l stream -d 'Always stream the response body by line' +complete -c http -s o -l output -F -d 'Save output to FILE' +complete -c http -s d -l download -d 'Download a file' +complete -c http -s c -l continue -d 'Resume an interrupted download' +complete -c http -s q -l quiet -d 'Do not print to stdout or stderr' + + +# Sessions + +complete -c http -l session -F -d 'Create, or reuse and update a session' +complete -c http -l session-read-only -F -d 'Create or read a session without updating it' + + +# Authentication + +complete -c http -s a -l auth -x -d 'Username and password for authentication' +complete -c http -s A -l auth-type -xa "(__fish_httpie_auth_types)" -d 'The authentication mechanism to be used' +complete -c http -l ignore-netrc -d 'Ignore credentials from .netrc' + + +# Network + +complete -c http -l offline -d 'Build the request and print it but don\'t actually send it' +complete -c http -l proxy -x -d 'String mapping protocol to the URL of the proxy' +complete -c http -s F -l follow -d 'Follow 30x Location redirects' +complete -c http -l max-redirects -x -d 'Set maximum number of redirects' +complete -c http -l max-headers -x -d 'Maximum number of response headers to be read before giving up' +complete -c http -l timeout -x -d 'Connection timeout in seconds' +complete -c http -l check-status -d 'Error with non-200 HTTP status code' +complete -c http -l path-as-is -d 'Bypass dot segment URL squashing' +complete -c http -l chunked -d 'Enable streaming via chunked transfer encoding' + + +# SSL + +complete -c http -l verify -xa "(__fish_http_verify_options)" -d 'Enable/disable cert verification' +complete -c http -l ssl -x -d 'Desired protocol version to use' +complete -c http -l ciphers -x -d 'String in the OpenSSL cipher list format' +complete -c http -l cert -F -d 'Client side SSL certificate' +complete -c http -l cert-key -F -d 'Private key to use with SSL' +complete -c http -l cert-key-pass -x -d 'Passphrase for the given private key' + + +# Troubleshooting + +complete -c http -s I -l ignore-stdin -d 'Do not attempt to read stdin' +complete -c http -l help -d 'Show help' +complete -c http -l manual -d 'Show the full manual' +complete -c http -l version -d 'Show version' +complete -c http -l traceback -d 'Prints exception traceback should one occur' +complete -c http -l default-scheme -x -d 'The default scheme to use' +complete -c http -l debug -d 'Show debugging output' + + +# Alias for https to http + +complete -c https -w http diff --git a/setup.cfg b/setup.cfg index 85490981aa..0e984fc3b4 100644 --- a/setup.cfg +++ b/setup.cfg @@ -103,8 +103,3 @@ test = pytest-mock werkzeug<2.1.0 -[options.data_files] -share/man/man1 = - extras/man/http.1 - extras/man/https.1 - extras/man/httpie.1 diff --git a/setup.py b/setup.py index 606849326a..5c3be7b755 100644 --- a/setup.py +++ b/setup.py @@ -1,3 +1,22 @@ from setuptools import setup -setup() +setup( + data_files=[ + ( + "share/man/man1", + [ + "extras/man/http.1", + "extras/man/https.1", + "extras/man/httpie.1", + ], + ), + ( + "share/fish/vendor_completions.d", + ["extras/fish/http.fish"], + ), + ( + "share/bash-completion/completions", + ["extras/bash-completion/http"], + ), + ], +) diff --git a/tests/test_encoding.py b/tests/test_encoding.py index 62814161ed..4affecc75b 100644 --- a/tests/test_encoding.py +++ b/tests/test_encoding.py @@ -4,6 +4,7 @@ """ import pytest import responses +from charset_normalizer import from_bytes from charset_normalizer.constant import TOO_SMALL_SEQUENCE from httpie.cli.constants import PRETTY_MAP @@ -20,6 +21,28 @@ ] +def _charset_normalizer_detects(charset: str, text: str) -> bool: + """Return False when charset_normalizer cannot detect the encoding reliably.""" + if charset == UTF8: + return True + match = from_bytes(text.encode(charset)).best() + if not match or not match.encoding: + return False + detected = match.encoding.lower().replace('_', '-') + expected = charset.lower().replace('_', '-') + return detected == expected or detected.startswith(expected.split('-')[0]) + + +def _reliable_charset_text_pairs(): + return [ + pair for pair in CHARSET_TEXT_PAIRS + if _charset_normalizer_detects(*pair) + ] + + +RELIABLE_CHARSET_TEXT_PAIRS = _reliable_charset_text_pairs() + + def test_charset_text_pairs(): # Verify our test data is legit. for charset, text in CHARSET_TEXT_PAIRS: @@ -134,7 +157,7 @@ def test_unicode_digest_auth(httpbin): f'{httpbin}/digest-auth/auth/test/{UNICODE}') -@pytest.mark.parametrize('charset, text', CHARSET_TEXT_PAIRS) +@pytest.mark.parametrize('charset, text', RELIABLE_CHARSET_TEXT_PAIRS) @responses.activate def test_terminal_output_response_charset_detection(text, charset): responses.add( @@ -147,7 +170,7 @@ def test_terminal_output_response_charset_detection(text, charset): assert text in r -@pytest.mark.parametrize('charset, text', CHARSET_TEXT_PAIRS) +@pytest.mark.parametrize('charset, text', RELIABLE_CHARSET_TEXT_PAIRS) @responses.activate def test_terminal_output_response_content_type_charset(charset, text): responses.add( @@ -160,7 +183,7 @@ def test_terminal_output_response_content_type_charset(charset, text): assert text in r -@pytest.mark.parametrize('charset, text', CHARSET_TEXT_PAIRS) +@pytest.mark.parametrize('charset, text', RELIABLE_CHARSET_TEXT_PAIRS) @pytest.mark.parametrize('pretty', PRETTY_MAP.keys()) @responses.activate def test_terminal_output_response_content_type_charset_with_stream(charset, text, pretty): @@ -175,7 +198,7 @@ def test_terminal_output_response_content_type_charset_with_stream(charset, text assert text in r -@pytest.mark.parametrize('charset, text', CHARSET_TEXT_PAIRS) +@pytest.mark.parametrize('charset, text', RELIABLE_CHARSET_TEXT_PAIRS) @pytest.mark.parametrize('pretty', PRETTY_MAP.keys()) @responses.activate def test_terminal_output_response_charset_override(charset, text, pretty): @@ -194,7 +217,7 @@ def test_terminal_output_response_charset_override(charset, text, pretty): assert text in r -@pytest.mark.parametrize('charset, text', CHARSET_TEXT_PAIRS) +@pytest.mark.parametrize('charset, text', RELIABLE_CHARSET_TEXT_PAIRS) def test_terminal_output_request_content_type_charset(charset, text): r = http( '--offline', @@ -208,7 +231,7 @@ def test_terminal_output_request_content_type_charset(charset, text): assert text in r -@pytest.mark.parametrize('charset, text', CHARSET_TEXT_PAIRS) +@pytest.mark.parametrize('charset, text', RELIABLE_CHARSET_TEXT_PAIRS) def test_terminal_output_request_charset_detection(charset, text): r = http( '--offline',