Compare commits

..

8 Commits

Author SHA1 Message Date
9d2e2afede Add failing reproduction test case 2022-06-07 14:50:56 +02:00
418b12bbd6 Cleanup 2022-06-07 14:31:15 +02:00
ecff53f2d5 Have naked $ make list all tasks 2022-06-07 14:29:19 +02:00
41da87f7c8 Install .[test] reqs in make install-reqs 2022-06-07 14:26:48 +02:00
4f172a61b4 Fix installation 2022-06-07 14:23:52 +02:00
542a2d35de Fix typos in comment lines (#1405)
* httpie/internal/daemons.py
* httpie/utils.py
2022-05-19 16:22:50 +03:00
d9e1dc08c9 Package man pages into the deb packages as well. (#1403) 2022-05-16 18:19:49 +03:00
3b734fb0bc Fix a misput backtick 2022-05-16 10:10:51 +03:00
27 changed files with 223 additions and 933 deletions

View File

@ -59,8 +59,10 @@ $ git checkout -b my_topical_branch
#### Setup
The [Makefile](https://github.com/httpie/httpie/blob/master/Makefile) contains a bunch of tasks to get you started. Just run
the following command, which:
The [Makefile](https://github.com/httpie/httpie/blob/master/Makefile) contains a bunch of tasks to get you started.
You can run `$ make` to see all the available tasks.
To get started, run the command below, which:
- Creates an isolated Python virtual environment inside `./venv`
(via the standard library [venv](https://docs.python.org/3/library/venv.html) tool);
@ -70,7 +72,7 @@ the following command, which:
- and runs tests (It is the same as running `make install test`).
```bash
$ make
$ make all
```
#### Python virtual environment

View File

@ -22,6 +22,26 @@ VENV_PYTHON=$(VENV_BIN)/python
export PATH := $(VENV_BIN):$(PATH)
default: list-tasks
###############################################################################
# Default task to get a list of tasks when `make' is run without args.
# <https://stackoverflow.com/questions/4219255>
###############################################################################
list-tasks:
@echo Available tasks:
@echo ----------------
@$(MAKE) -pRrq -f $(lastword $(MAKEFILE_LIST)) : 2>/dev/null | awk -v RS= -F: '/^# File/,/^# Finished Make data base/ {if ($$1 !~ "^[#.]") {print $$1}}' | sort | egrep -v -e '^[^[:alnum:]]' -e '^$@$$'
@echo
###############################################################################
# Installation
###############################################################################
all: uninstall-httpie install test
@ -33,7 +53,7 @@ install-reqs:
$(VENV_PIP) install --upgrade pip wheel build
@echo $(H1)Installing dev requirements$(H1END)
$(VENV_PIP) install --upgrade --editable '.[dev]'
$(VENV_PIP) install --upgrade '.[dev]' '.[test]'
@echo $(H1)Installing HTTPie$(H1END)
$(VENV_PIP) install --upgrade --editable .

View File

@ -2425,7 +2425,7 @@ You can check whether a new update is available for your system by running `http
In the past `pip` was used to install/uninstall plugins, but on some environments (e.g., brew installed
packages) it wasnt working properly. The new interface is a very simple overlay on top of `pip` to allow
plugin installations on every installation method.
plugin installations on every installation method.
By default, the plugins (and their missing dependencies) will be stored under the configuration directory,
but this can be modified through `plugins_dir` variable on the config.

View File

@ -17,13 +17,13 @@ docs-structure:
Windows:
- chocolatey
Linux:
- snap-linux
- brew-linux
- apt
- dnf
- yum
- pacman
- single-binary
- snap-linux
- brew-linux
- pacman
FreeBSD:
- pkg
@ -191,6 +191,7 @@ tools:
commands:
install:
- https --download packages.httpie.io/binaries/linux/http-latest -o http
- chmod +x ./http
- ln -ls ./http ./https
- chmod +x ./http ./https
upgrade:
- https --download packages.httpie.io/binaries/linux/http-latest -o http

View File

@ -1,53 +0,0 @@
METHODS=("GET" "POST" "PUT" "DELETE" "HEAD" "OPTIONS" "PATCH" "TRACE" "CONNECT" )
NORMARG=1 # TO-DO: dynamically calculate this?
_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"
else
if (( COMP_CWORD == NORMARG + 0 )); then
_http_complete_methods "$cur_word"
fi
if (( COMP_CWORD == NORMARG + 0 )); then
_http_complete_url "$cur_word"
fi
if (( COMP_CWORD == NORMARG + 1 )) && [[ " ${METHODS[*]} " =~ " ${prev_word} " ]]; then
_http_complete_url "$cur_word"
fi
if (( COMP_CWORD >= NORMARG + 2 )); then
_httpie_complete_request_item "$cur_word"
fi
if (( COMP_CWORD >= NORMARG + 1 )) && ! [[ " ${METHODS[*]} " =~ " ${prev_word} " ]]; then
_httpie_complete_request_item "$cur_word"
fi
fi
}
complete -o default -F _http_complete http httpie.http httpie.https https
_http_complete_methods() {
local cur_word=$1
local options="GET POST PUT DELETE HEAD OPTIONS PATCH TRACE CONNECT"
COMPREPLY+=( $( compgen -W "$options" -- "$cur_word" ) )
}
_http_complete_url() {
local cur_word=$1
local options="http:// https://"
COMPREPLY+=( $( compgen -W "$options" -- "$cur_word" ) )
}
_httpie_complete_request_item() {
local cur_word=$1
COMPREPLY+=("==" "=" ":=" ":=@")
}
_http_complete_options() {
local cur_word=$1
local options="--json -j --form -f --multipart --boundary --raw --compress -x --pretty --style -s --unsorted --sorted --response-charset --response-mime --format-options --print -p --headers -h --meta -m --body -b --verbose -v --all --stream -S --output -o --download -d --continue -c --quiet -q --session --session-read-only --auth -a --auth-type -A --ignore-netrc --offline --proxy --follow -F --max-redirects --max-headers --timeout --check-status --path-as-is --chunked --verify --ssl --ciphers --cert --cert-key --cert-key-pass --ignore-stdin -I --help --manual --version --traceback --default-scheme --debug "
COMPREPLY=( $( compgen -W "$options" -- "$cur_word" ) )
}

View File

@ -1,51 +0,0 @@
complete -c http -s --json -l -j -d '(default) Serialize data items from the command line as a JSON object.'
complete -c http -s --form -l -f -d 'Serialize data items from the command line as form field data.'
complete -c http -l --multipart -d 'Similar to --form, but always sends a multipart/form-data request (i.e., even without files).'
complete -c http -l --boundary -d 'Specify a custom boundary string for multipart/form-data requests. Only has effect only together with --form.'
complete -c http -l --raw -d 'Pass raw request data without extra processing.'
complete -c http -s --compress -l -x -d 'Compress the content with Deflate algorithm.'
complete -c http -l --pretty -xa "all colors format none" -d 'Control the processing of console outputs.'
complete -c http -s --style -l -s -d 'Output coloring style (default is "auto").'
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 -d 'Override the response encoding for terminal display purposes.'
complete -c http -l --response-mime -d 'Override the response mime type for coloring and formatting for the terminal.'
complete -c http -l --format-options -d 'Controls output formatting.'
complete -c http -s --print -l -p -d 'Options to specify what the console output should contain.'
complete -c http -s --headers -l -h -d 'Print only the response headers.'
complete -c http -s --meta -l -m -d 'Print only the response metadata.'
complete -c http -s --body -l -b -d 'Print only the response body.'
complete -c http -s --verbose -l -v -d 'Make output more verbose.'
complete -c http -l --all -d 'Show any intermediary requests/responses.'
complete -c http -s --stream -l -S -d 'Always stream the response body by line, i.e., behave like `tail -f`.'
complete -c http -s --output -l -o -d 'Save output to FILE instead of stdout.'
complete -c http -s --download -l -d -d 'Download the body to a file instead of printing it to stdout.'
complete -c http -s --continue -l -c -d 'Resume an interrupted download (--output needs to be specified).'
complete -c http -s --quiet -l -q -d 'Do not print to stdout or stderr, except for errors and warnings when provided once.'
complete -c http -l --session -d 'Create, or reuse and update a session.'
complete -c http -l --session-read-only -d 'Create or read a session without updating it'
complete -c http -s --auth -l -a -d 'Credentials for the selected (-A) authentication method.'
complete -c http -s --auth-type -l -A -d 'The authentication mechanism to be used.'
complete -c http -l --ignore-netrc -d 'Ignore credentials from .netrc.'
complete -c http -l --offline -d 'Build the request and print it but dont actually send it.'
complete -c http -l --proxy -d 'String mapping of protocol to the URL of the proxy.'
complete -c http -s --follow -l -F -d 'Follow 30x Location redirects.'
complete -c http -l --max-redirects -d 'The maximum number of redirects that should be followed (with --follow).'
complete -c http -l --max-headers -d 'The maximum number of response headers to be read before giving up (default 0, i.e., no limit).'
complete -c http -l --timeout -d 'The connection timeout of the request in seconds.'
complete -c http -l --check-status -d 'Exit with an error status code if the server replies with an error.'
complete -c http -l --path-as-is -d 'Bypass dot segment (/../ or /./) URL squashing.'
complete -c http -l --chunked -d 'Enable streaming via chunked transfer encoding. The Transfer-Encoding header is set to chunked.'
complete -c http -l --verify -d 'If "no", skip SSL verification. If a file path, use it as a CA bundle.'
complete -c http -l --ssl -xa "ssl2.3 tls1 tls1.1 tls1.2" -d 'The desired protocol version to used.'
complete -c http -l --ciphers -d 'A string in the OpenSSL cipher list format.'
complete -c http -l --cert -d 'Specifys a local cert to use as client side SSL certificate.'
complete -c http -l --cert-key -d 'The private key to use with SSL. Only needed if --cert is given.'
complete -c http -l --cert-key-pass -d 'The passphrase to be used to with the given private key.'
complete -c http -s --ignore-stdin -l -I -d 'Do not attempt to read stdin'
complete -c http -l --help -d 'Show this help message and exit.'
complete -c http -l --manual -d 'Show the full manual.'
complete -c http -l --version -d 'Show version and exit.'
complete -c http -l --traceback -d 'Prints the exception traceback should one occur.'
complete -c http -l --default-scheme -d 'The default scheme to use if not specified in the URL.'
complete -c http -l --debug -d 'Print useful diagnostic information for bug reports.'

View File

@ -1,146 +0,0 @@
#compdef http
# Copyright (c) 2015 Github zsh-users
# Based on the initial work of http://github.com/zsh-users
METHODS=("GET" "POST" "PUT" "DELETE" "HEAD" "OPTIONS" "PATCH" "TRACE" "CONNECT" )
_httpie_params () {
local ret=1 expl
local current=$words[$CURRENT]
if (( CURRENT > NORMARG )); then
local predecessor=$words[(( $CURRENT - 1 ))]
fi
if ! [[ $current == -* ]]; then
if (( CURRENT == NORMARG + 0 )); then
_httpie_method && ret=0
fi
if (( CURRENT == NORMARG + 0 )); then
_httpie_url && ret=0
fi
if (( CURRENT == NORMARG + 1 )) && [[ ${METHODS[(ie)$predecessor]} -le ${#METHODS} ]]; then
_httpie_url && ret=0
fi
if (( CURRENT >= NORMARG + 2 )); then
_httpie_request_item && ret=0
fi
if (( CURRENT >= NORMARG + 1 )) && ! [[ ${METHODS[(ie)$predecessor]} -le ${#METHODS} ]]; then
_httpie_request_item && ret=0
fi
fi
return $ret
}
_httpie_request_item() {
compset -P '(#b)([^:@=]#)'
local name=$match[1]
if false; then
false;
elif compset -P ':'; then
_message "$name HTTP Headers"
elif compset -P '=='; then
_message "$name URL Parameters"
elif compset -P '='; then
_message "$name Data Fields"
elif compset -P ':='; then
_message "$name Raw JSON Fields"
elif compset -P '@'; then
_files
else
typeset -a ops
ops=(
"\::Arbitrary HTTP header, e.g X-API-Token:123"
"==:Querystring parameter to the URL, e.g limit==50"
"=:Data fields to be serialized as JSON (default) or Form Data (with --form)"
"\:=:Data field for real JSON types."
"@:Path field for uploading a file."
)
_describe -t httpparams 'parameter types' ops -Q -S ''
fi
return 1;
}
_httpie_method() {
_wanted http_method expl 'Request Method' \
compadd GET POST PUT DELETE HEAD OPTIONS PATCH TRACE CONNECT && ret=0
return 1;
}
_httpie_url() {
local ret=1
if ! [[ -prefix [-+.a-z0-9]#:// ]]; then
local expl
compset -S '[^:/]*' && compstate[to_end]=''
_wanted url-schemas expl 'URL schema' compadd -S '' http:// https:// && ret=0
else
_urls && ret=0
fi
return $ret
}
integer NORMARG
_arguments -n -C -s \
{--json,-j}'[(default) Serialize data items from the command line as a JSON object.]' \
{--form,-f}'[Serialize data items from the command line as form field data.]' \
'--multipart[Similar to --form, but always sends a multipart/form-data request (i.e., even without files).]' \
'--boundary=[Specify a custom boundary string for multipart/form-data requests. Only has effect only together with --form.]' \
'--raw=[Pass raw request data without extra processing.]' \
{--compress,-x}'[Compress the content with Deflate algorithm.]' \
'--pretty=[Control the processing of console outputs.]:PRETTY:(all colors format none)' \
{--style,-s}'=[Output coloring style (default is "auto").]:STYLE:' \
'--unsorted[Disables all sorting while formatting output.]' \
'--sorted[Re-enables all sorting options while formatting output.]' \
'--response-charset=[Override the response encoding for terminal display purposes.]:ENCODING:' \
'--response-mime=[Override the response mime type for coloring and formatting for the terminal.]:MIME_TYPE:' \
'--format-options=[Controls output formatting.]' \
{--print,-p}'=[Options to specify what the console output should contain.]:WHAT:' \
{--headers,-h}'[Print only the response headers.]' \
{--meta,-m}'[Print only the response metadata.]' \
{--body,-b}'[Print only the response body.]' \
{--verbose,-v}'[Make output more verbose.]' \
'--all[Show any intermediary requests/responses.]' \
{--stream,-S}'[Always stream the response body by line, i.e., behave like `tail -f`.]' \
{--output,-o}'=[Save output to FILE instead of stdout.]:FILE:' \
{--download,-d}'[Download the body to a file instead of printing it to stdout.]' \
{--continue,-c}'[Resume an interrupted download (--output needs to be specified).]' \
{--quiet,-q}'[Do not print to stdout or stderr, except for errors and warnings when provided once.]' \
'--session=[Create, or reuse and update a session.]:SESSION_NAME_OR_PATH:' \
'--session-read-only=[Create or read a session without updating it]:SESSION_NAME_OR_PATH:' \
{--auth,-a}'=[Credentials for the selected (-A) authentication method.]:USER[\:PASS] | TOKEN:' \
{--auth-type,-A}'=[The authentication mechanism to be used.]' \
'--ignore-netrc[Ignore credentials from .netrc.]' \
'--offline[Build the request and print it but dont actually send it.]' \
'--proxy=[String mapping of protocol to the URL of the proxy.]:PROTOCOL\:PROXY_URL:' \
{--follow,-F}'[Follow 30x Location redirects.]' \
'--max-redirects=[The maximum number of redirects that should be followed (with --follow).]' \
'--max-headers=[The maximum number of response headers to be read before giving up (default 0, i.e., no limit).]' \
'--timeout=[The connection timeout of the request in seconds.]:SECONDS:' \
'--check-status[Exit with an error status code if the server replies with an error.]' \
'--path-as-is[Bypass dot segment (/../ or /./) URL squashing.]' \
'--chunked[Enable streaming via chunked transfer encoding. The Transfer-Encoding header is set to chunked.]' \
'--verify=[If "no", skip SSL verification. If a file path, use it as a CA bundle.]' \
'--ssl=[The desired protocol version to used.]:SSL:(ssl2.3 tls1 tls1.1 tls1.2)' \
'--ciphers=[A string in the OpenSSL cipher list format.]' \
'--cert=[Specifys a local cert to use as client side SSL certificate.]' \
'--cert-key=[The private key to use with SSL. Only needed if --cert is given.]' \
'--cert-key-pass=[The passphrase to be used to with the given private key.]' \
{--ignore-stdin,-I}'[Do not attempt to read stdin]' \
'--help[Show this help message and exit.]' \
'--manual[Show the full manual.]' \
'--version[Show version and exit.]' \
'--traceback[Prints the exception traceback should one occur.]' \
'--default-scheme=[The default scheme to use if not specified in the URL.]' \
'--debug[Print useful diagnostic information for bug reports.]' \
'*:args:_httpie_params' && return 0

View File

@ -1,40 +0,0 @@
METHODS=({% for method in methods -%} "{{ method }}" {% endfor -%})
NORMARG=1 # TO-DO: dynamically calculate this?
_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"
else
{% for flow_item in generate_flow() -%}
{{ compile_bash(flow_item) | indent(width=8) }}
{% endfor %}
fi
}
complete -o default -F _http_complete http httpie.http httpie.https https
_http_complete_methods() {
local cur_word=$1
local options="{{' '.join(methods)}}"
COMPREPLY+=( $( compgen -W "$options" -- "$cur_word" ) )
}
_http_complete_url() {
local cur_word=$1
local options="http:// https://"
COMPREPLY+=( $( compgen -W "$options" -- "$cur_word" ) )
}
_httpie_complete_request_item() {
local cur_word=$1
COMPREPLY+=("==" "=" ":=" ":=@")
}
_http_complete_options() {
local cur_word=$1
local options="{% for argument in arguments -%} {{ ' '.join(argument.aliases) }} {% endfor -%}"
COMPREPLY=( $( compgen -W "$options" -- "$cur_word" ) )
}

View File

@ -1,3 +0,0 @@
{% for argument in arguments -%}
{{ serialize_argument_to_fish(argument) }}
{% endfor -%}

View File

@ -1,76 +0,0 @@
#compdef http
# Copyright (c) 2015 Github zsh-users
# Based on the initial work of http://github.com/zsh-users
METHODS=({% for method in methods -%} "{{ method }}" {% endfor -%})
_httpie_params () {
local ret=1 expl
local current=$words[$CURRENT]
if (( CURRENT > NORMARG )); then
local predecessor=$words[(( $CURRENT - 1 ))]
fi
if ! [[ $current == -* ]]; then
{% for flow_item in generate_flow() -%}
{{ compile_zsh(flow_item) | indent(width=8) }}
{% endfor %}
fi
return $ret
}
_httpie_request_item() {
compset -P '(#b)([^:@=]#)'
local name=$match[1]
if false; then
false;
{% for option_name, _, operator, desc in request_items.nested_options -%}
elif compset -P '{{ operator }}'; then
{% if is_file_based_operator(operator) -%}
_files
{% else -%}
_message "$name {{ option_name }}"
{% endif %}
{% endfor -%}
else
typeset -a ops
ops=(
{% for option_name, _, operator, desc in request_items.nested_options -%}
"{{ escape_zsh(operator) }}:{{ desc }}"
{% endfor -%}
)
_describe -t httpparams 'parameter types' ops -Q -S ''
fi
return 1;
}
_httpie_method() {
_wanted http_method expl 'Request Method' \
compadd {% for method in methods -%} {{ method }} {% endfor -%} && ret=0
return 1;
}
_httpie_url() {
local ret=1
if ! [[ -prefix [-+.a-z0-9]#:// ]]; then
local expl
compset -S '[^:/]*' && compstate[to_end]=''
_wanted url-schemas expl 'URL schema' compadd -S '' http:// https:// && ret=0
else
_urls && ret=0
fi
return $ret
}
integer NORMARG
_arguments -n -C -s \
{% for argument in arguments -%}
{{ serialize_argument_to_zsh(argument) }} \
{% endfor -%}
'*:args:_httpie_params' && return 0

View File

@ -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" ) )
}

View File

@ -0,0 +1,114 @@
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'

View File

@ -6,6 +6,9 @@ from typing import Iterator, Tuple
BUILD_DIR = Path(__file__).parent
HTTPIE_DIR = BUILD_DIR.parent.parent.parent
EXTRAS_DIR = HTTPIE_DIR / 'extras'
MAN_PAGES_DIR = EXTRAS_DIR / 'man'
SCRIPT_DIR = BUILD_DIR / Path('scripts')
HOOKS_DIR = SCRIPT_DIR / 'hooks'
@ -50,6 +53,11 @@ def build_packages(http_binary: Path, httpie_binary: Path) -> None:
(http_binary, '/usr/bin/https'),
(httpie_binary, '/usr/bin/httpie'),
]
files.extend(
(man_page, f'/usr/share/man/man1/{man_page.name}')
for man_page in MAN_PAGES_DIR.glob('*.1')
)
# A list of additional dependencies
deps = [
'python3 >= 3.7',

View File

@ -1,83 +0,0 @@
from enum import Enum
from functools import singledispatch
from completion_flow import (
And,
Check,
Condition,
If,
Node,
Not,
Suggest,
Suggestion,
Variable,
generate_flow,
)
class BashVariable(str, Enum):
CURRENT = 'COMP_CWORD'
NORMARG = 'NORMARG'
CURRENT_WORD = 'cur_word'
PREDECESSOR = 'prev_word'
METHODS = 'METHODS'
SUGGESTION_TO_FUNCTION = {
Suggestion.METHOD: '_http_complete_methods',
Suggestion.URL: '_http_complete_url',
Suggestion.REQUEST_ITEM: '_httpie_complete_request_item',
}
@singledispatch
def compile_bash(node: Node) -> ...:
raise NotImplementedError(f'{type(node)} is not supported')
@compile_bash.register(If)
def compile_if(node: If) -> str:
check = compile_bash(node.check)
action = compile_bash(node.action)
return f'if {check}; then\n {action}\nfi'
@compile_bash.register(Check)
def compile_check(node: Check) -> str:
args = [
BashVariable(arg.name) if isinstance(arg, Variable) else arg
for arg in node.args
]
if node.condition is Condition.POSITION_EQ:
return f'(( {BashVariable.CURRENT} == {BashVariable.NORMARG} + {args[0]} ))'
elif node.condition is Condition.POSITION_GE:
return f'(( {BashVariable.CURRENT} >= {BashVariable.NORMARG} + {args[0]} ))'
elif node.condition is Condition.CONTAINS_PREDECESSOR:
parts = [
'[[ ',
'" ${',
BashVariable.METHODS,
'[*]} " =~ " ${',
BashVariable.PREDECESSOR,
'} " ]]',
]
return ''.join(parts)
@compile_bash.register(And)
def compile_and(node: And) -> str:
return ' && '.join(compile_bash(check) for check in node.checks)
@compile_bash.register(Not)
def compile_not(node: Not) -> str:
return f'! {compile_bash(node.check)}'
@compile_bash.register(Suggest)
def compile_suggest(node: Suggest) -> str:
return (
SUGGESTION_TO_FUNCTION[node.suggestion]
+ f' "${BashVariable.CURRENT_WORD}"'
)

View File

@ -1,116 +0,0 @@
from dataclasses import dataclass, field
from enum import Enum, auto
from typing import Iterator, List
class Condition(Enum):
# $N = check.arguments[N]
# $words = a list of splitted arguments on the completion
# current = index in the $words
# Check whether the $words[current][0] matches the $1
STARTSWITH = auto()
# Check whether the $1 contains the $words[current-1]
CONTAINS_PREDECESSOR = auto()
# Check whether current == $1
POSITION_EQ = auto()
# Check whether current >= $1
POSITION_GE = auto()
class Suggestion(Enum):
OPTION = auto()
METHOD = auto()
URL = auto()
REQUEST_ITEM = auto()
class Variable(Enum):
METHODS = auto()
class Node:
...
@dataclass
class Check(Node):
condition: Condition
args: List[str] = field(default_factory=list)
@dataclass
class Suggest(Node):
suggestion: Suggestion
@dataclass
class If(Node):
check: Node
action: Node
@dataclass
class And(Node):
checks: List[Node]
def __init__(self, *checks) -> None:
self.checks = checks
@dataclass
class Not(Node):
check: Node
def generate_flow() -> Iterator[Node]:
# yield from suggest_option()
yield from suggest_method()
yield from suggest_url()
yield from suggest_request_items()
def suggest_option():
yield If(
Check(Condition.STARTSWITH, args=['-']),
action=Suggest(Suggestion.OPTION),
)
def suggest_method():
yield If(
Check(Condition.POSITION_EQ, args=[0]),
action=Suggest(Suggestion.METHOD),
)
def suggest_url():
yield If(
Check(Condition.POSITION_EQ, args=[0]), action=Suggest(Suggestion.URL)
)
yield If(
And(
Check(Condition.POSITION_EQ, args=[1]),
Check(Condition.CONTAINS_PREDECESSOR, args=[Variable.METHODS]),
),
action=Suggest(Suggestion.URL),
)
def suggest_request_items():
yield If(
Check(Condition.POSITION_GE, args=[2]),
action=Suggest(Suggestion.REQUEST_ITEM),
)
yield If(
And(
Check(Condition.POSITION_GE, args=[1]),
Not(
Check(Condition.CONTAINS_PREDECESSOR, args=[Variable.METHODS])
),
),
action=Suggest(Suggestion.REQUEST_ITEM),
)

View File

@ -1,231 +0,0 @@
import functools
import string
import textwrap
from atexit import register
from pathlib import Path
from typing import Any, Callable, Dict, TypeVar
from completion_flow import generate_flow
from jinja2 import Template
from httpie.cli.constants import SEPARATOR_FILE_UPLOAD
from httpie.cli.definition import options
from httpie.cli.options import Argument, ParserSpec
T = TypeVar('T')
EXTRAS_DIR = Path(__file__).parent.parent.parent
COMPLETION_DIR = EXTRAS_DIR / 'completion'
TEMPLATES_DIR = COMPLETION_DIR / 'templates'
COMPLETION_TEMPLATE_BASE = TEMPLATES_DIR / 'completion'
COMPLETION_SCRIPT_BASE = COMPLETION_DIR / 'completion'
COMMON_HTTP_METHODS = [
'GET',
'POST',
'PUT',
'DELETE',
'HEAD',
'OPTIONS',
'PATCH',
'TRACE',
'CONNECT',
]
COMPLETERS = {}
def use_template(shell_type):
def decorator(func):
@functools.wraps(func)
def wrapper(spec):
template_file = COMPLETION_TEMPLATE_BASE.with_suffix(
f'.{shell_type}.j2'
)
compiletion_script_file = COMPLETION_SCRIPT_BASE.with_suffix(
f'.{shell_type}'
)
jinja_template = Template(template_file.read_text())
jinja_template.globals.update(prepare_objects(spec))
extra_variables = func(spec)
compiletion_script_file.write_text(
jinja_template.render(**extra_variables)
)
COMPLETERS[shell_type] = wrapper
return wrapper
return decorator
BASE_FUNCTIONS = {}
def prepare_objects(spec: ParserSpec) -> Dict[str, Any]:
global_objects = {
**BASE_FUNCTIONS,
}
global_objects['request_items'] = find_argument_by_target_name(
spec, 'REQUEST_ITEM'
)
global_objects['arguments'] = [
argument
for group in spec.groups
for argument in group.arguments
if not argument.is_hidden
if not argument.is_positional
]
global_objects['methods'] = COMMON_HTTP_METHODS
global_objects['generate_flow'] = generate_flow
return global_objects
def register_function(func: T) -> T:
BASE_FUNCTIONS[func.__name__] = func
return func
@register_function
def is_file_based_operator(operator: str) -> bool:
return operator in {SEPARATOR_FILE_UPLOAD}
def escape_zsh(text: str) -> str:
return text.replace(':', '\\:')
def serialize_argument_to_zsh(argument):
# The argument format is the following:
# $prefix'$alias$has_value[$short_desc]:$metavar$:($choice_1 $choice_2)'
prefix = ''
declaration = []
has_choices = 'choices' in argument.configuration
# The format for the argument declaration canges depending on the
# the number of aliases. For a single $alias, we'll embed it directly
# in the declaration string, but for multiple of them, we'll use a
# $prefix.
if len(argument.aliases) > 1:
prefix = '{' + ','.join(argument.aliases) + '}'
else:
declaration.append(argument.aliases[0])
if not argument.is_flag:
declaration.append('=')
declaration.append('[' + argument.short_help + ']')
if 'metavar' in argument.configuration:
metavar = argument.metavar
elif has_choices:
# Choices always require a metavar, so even if we don't have one
# we can generate it from the argument aliases.
metavar = (
max(argument.aliases, key=len)
.lstrip('-')
.replace('-', '_')
.upper()
)
else:
metavar = None
if metavar:
# Strip out any whitespace, and escape any characters that would
# conflict with the shell.
metavar = escape_zsh(metavar.strip(' '))
declaration.append(f':{metavar}:')
if has_choices:
declaration.append('(' + ' '.join(argument.choices) + ')')
return prefix + f"'{''.join(declaration)}'"
def serialize_argument_to_fish(argument):
# The argument format is defined here
# <https://fishshell.com/docs/current/completions.html>
declaration = [
'complete',
'-c',
'http',
]
try:
short_form, long_form = argument.aliases
except ValueError:
short_form = None
(long_form,) = argument.aliases
if short_form:
declaration.append('-s')
declaration.append(short_form)
declaration.append('-l')
declaration.append(long_form)
if 'choices' in argument.configuration:
declaration.append('-xa')
declaration.append('"' + ' '.join(argument.choices) + '"')
elif 'lazy_choices' in argument.configuration:
declaration.append('-x')
declaration.append('-d')
declaration.append("'" + argument.short_help.replace("'", r"\'") + "'")
return '\t'.join(declaration)
def find_argument_by_target_name(spec: ParserSpec, name: str) -> Argument:
for group in spec.groups:
for argument in group.arguments:
if argument.aliases:
targets = argument.aliases
else:
targets = [argument.metavar]
if name in targets:
return argument
raise ValueError(f'Could not find argument with name {name}')
@use_template('zsh')
def zsh_completer(spec: ParserSpec) -> Dict[str, Any]:
from zsh import compile_zsh
return {
'escape_zsh': escape_zsh,
'serialize_argument_to_zsh': serialize_argument_to_zsh,
'compile_zsh': compile_zsh,
}
@use_template('fish')
def fish_completer(spec: ParserSpec) -> Dict[str, Any]:
return {
'serialize_argument_to_fish': serialize_argument_to_fish,
}
@use_template('bash')
def fish_completer(spec: ParserSpec) -> Dict[str, Any]:
from bash import compile_bash
return {
'compile_bash': compile_bash,
}
def main():
for shell_type, completer in COMPLETERS.items():
print(f'Generating {shell_type} completer.')
completer(options)
if __name__ == '__main__':
main()

View File

@ -1,84 +0,0 @@
from enum import Enum
from functools import singledispatch
from completion_flow import (
And,
Check,
Condition,
If,
Node,
Not,
Suggest,
Suggestion,
Variable,
)
class ZSHVariable(str, Enum):
CURRENT = 'CURRENT'
NORMARG = 'NORMARG'
PREDECESSOR = 'predecessor'
METHODS = 'METHODS'
SUGGESTION_TO_FUNCTION = {
Suggestion.METHOD: '_httpie_method',
Suggestion.URL: '_httpie_url',
Suggestion.REQUEST_ITEM: '_httpie_request_item',
}
@singledispatch
def compile_zsh(node: Node) -> ...:
raise NotImplementedError(f'{type(node)} is not supported')
@compile_zsh.register(If)
def compile_if(node: If) -> str:
check = compile_zsh(node.check)
action = compile_zsh(node.action)
return f'if {check}; then\n {action} && ret=0\nfi'
@compile_zsh.register(Check)
def compile_check(node: Check) -> str:
args = [
ZSHVariable(arg.name) if isinstance(arg, Variable) else arg
for arg in node.args
]
if node.condition is Condition.POSITION_EQ:
return (
f'(( {ZSHVariable.CURRENT} == {ZSHVariable.NORMARG} + {args[0]} ))'
)
elif node.condition is Condition.POSITION_GE:
return (
f'(( {ZSHVariable.CURRENT} >= {ZSHVariable.NORMARG} + {args[0]} ))'
)
elif node.condition is Condition.CONTAINS_PREDECESSOR:
parts = [
'[[ ${',
args[0],
'[(ie)$',
ZSHVariable.PREDECESSOR,
']}',
' -le ${#',
args[0],
'} ]]',
]
return ''.join(parts)
@compile_zsh.register(And)
def compile_and(node: And) -> str:
return ' && '.join(compile_zsh(check) for check in node.checks)
@compile_zsh.register(Not)
def compile_not(node: Not) -> str:
return f'! {compile_zsh(node.check)}'
@compile_zsh.register(Suggest)
def compile_suggest(node: Suggest) -> str:
return SUGGESTION_TO_FUNCTION[node.suggestion]

View File

@ -132,10 +132,3 @@ class RequestType(enum.Enum):
FORM = enum.auto()
MULTIPART = enum.auto()
JSON = enum.auto()
EMPTY_STRING = ''
OPEN_BRACKET = '['
CLOSE_BRACKET = ']'
BACKSLASH = '\\'
HIGHLIGHTER = '^'

View File

@ -13,9 +13,6 @@ from httpie.cli.constants import (BASE_OUTPUT_OPTIONS, DEFAULT_FORMAT_OPTIONS,
OUTPUT_OPTIONS_DEFAULT, PRETTY_MAP,
PRETTY_STDOUT_TTY_ONLY,
SEPARATOR_GROUP_ALL_ITEMS, SEPARATOR_PROXY,
SEPARATOR_HEADER, SEPARATOR_QUERY_PARAM,
SEPARATOR_DATA_STRING, SEPARATOR_DATA_RAW_JSON,
SEPARATOR_FILE_UPLOAD,
SORTED_FORMAT_OPTIONS_STRING,
UNSORTED_FORMAT_OPTIONS_STRING, RequestType)
from httpie.cli.options import ParserSpec, Qualifiers, to_argparse
@ -94,11 +91,11 @@ positional_arguments.add_argument(
'data, files, and URL parameters.'
),
nested_options=[
('HTTP Headers', 'Name:Value', SEPARATOR_HEADER, 'Arbitrary HTTP header, e.g X-API-Token:123'),
('URL Parameters', 'name==value', SEPARATOR_QUERY_PARAM, 'Querystring parameter to the URL, e.g limit==50'),
('Data Fields', 'field=value', SEPARATOR_DATA_STRING, 'Data fields to be serialized as JSON (default) or Form Data (with --form)'),
('Raw JSON Fields', 'field:=json', SEPARATOR_DATA_RAW_JSON, 'Data field for real JSON types.'),
('File upload Fields', 'field@/dir/file', SEPARATOR_FILE_UPLOAD, 'Path field for uploading a file.'),
('HTTP Headers', 'Name:Value', 'Arbitrary HTTP header, e.g X-API-Token:123'),
('URL Parameters', 'name==value', 'Querystring parameter to the URL, e.g limit==50'),
('Data Fields', 'field=value', 'Data fields to be serialized as JSON (default) or Form Data (with --form)'),
('Raw JSON Fields', 'field:=json', 'Data field for real JSON types.'),
('File upload Fields', 'field@/dir/file', 'Path field for uploading a file.'),
],
help=r"""
Optional key-value pairs to be included in the request. The separator used

View File

@ -9,8 +9,14 @@ from typing import (
Type,
Union,
)
from httpie.cli.dicts import NestedJSONArray
from httpie.cli.constants import EMPTY_STRING, OPEN_BRACKET, CLOSE_BRACKET, BACKSLASH, HIGHLIGHTER
from .dicts import NestedJSONArray
EMPTY_STRING = ''
HIGHLIGHTER = '^'
OPEN_BRACKET = '['
CLOSE_BRACKET = ']'
BACKSLASH = '\\'
class HTTPieSyntaxError(ValueError):
@ -31,7 +37,7 @@ class HTTPieSyntaxError(ValueError):
if self.token is not None:
lines.append(self.source)
lines.append(
' ' * (self.token.start)
' ' * self.token.start
+ HIGHLIGHTER * (self.token.end - self.token.start)
)
return '\n'.join(lines)
@ -51,9 +57,15 @@ class TokenKind(Enum):
return 'a ' + self.name.lower()
OPERATORS = {OPEN_BRACKET: TokenKind.LEFT_BRACKET, CLOSE_BRACKET: TokenKind.RIGHT_BRACKET}
OPERATORS = {
OPEN_BRACKET: TokenKind.LEFT_BRACKET,
CLOSE_BRACKET: TokenKind.RIGHT_BRACKET,
}
SPECIAL_CHARS = OPERATORS.keys() | {BACKSLASH}
LITERAL_TOKENS = [TokenKind.TEXT, TokenKind.NUMBER]
LITERAL_TOKENS = [
TokenKind.TEXT,
TokenKind.NUMBER,
]
class Token(NamedTuple):

View File

@ -172,11 +172,6 @@ class Argument(typing.NamedTuple):
def is_hidden(self):
return self.configuration.get('help') is Qualifiers.SUPPRESS
@property
def is_flag(self):
action = getattr(self, 'action', None)
return action in ARGPARSE_FLAG_ACTIONS
def __getattr__(self, attribute_name):
if attribute_name in self.configuration:
return self.configuration[attribute_name]
@ -193,17 +188,6 @@ ARGPARSE_QUALIFIER_MAP = {
Qualifiers.ONE_OR_MORE: argparse.ONE_OR_MORE
}
ARGPARSE_IGNORE_KEYS = ('short_help', 'nested_options')
ARGPARSE_FLAG_ACTIONS = [
"store_true",
"store_false",
"count",
"version",
"help",
"debug",
"manual",
"append_const",
"store_const"
]
def to_argparse(

View File

@ -13,7 +13,8 @@ import urllib3
from . import __version__
from .adapters import HTTPieHTTPAdapter
from .context import Environment
from .cli.constants import EMPTY_STRING, HTTP_OPTIONS
from .cli.constants import HTTP_OPTIONS
from .cli.nested_json import EMPTY_STRING
from .cli.dicts import HTTPHeadersDict, NestedJSONArray
from .encoding import UTF8
from .models import RequestsMessage

View File

@ -1,6 +1,6 @@
"""
This module provides an interface to spawn a detached task to be
runned with httpie.internal.daemon_runner on a separate process. It is
run with httpie.internal.daemon_runner on a separate process. It is
based on DVC's daemon system.
https://github.com/iterative/dvc/blob/main/dvc/daemon.py
"""

View File

@ -193,7 +193,7 @@ def to_help_message(
value,
dec,
)
for key, value, _, dec in argument.nested_options
for key, value, dec in argument.nested_options
]
)

View File

@ -277,7 +277,7 @@ def open_with_lockfile(file: Path, *args, **kwargs) -> Generator[IO[Any], None,
target_file = Path(tempfile.gettempdir()) / file_id
# Have an atomic-like touch here, so we'll tighten the possibility of
# a race occuring between multiple processes accessing the same file.
# a race occurring between multiple processes accessing the same file.
try:
target_file.touch(exist_ok=False)
except FileExistsError as exc:

View File

@ -1,9 +1,12 @@
"""Miscellaneous regression tests"""
import pytest
from httpie.cli.argtypes import KeyValueArgType
from httpie.cli.constants import SEPARATOR_HEADER, SEPARATOR_QUERY_PARAM, SEPARATOR_DATA_STRING
from httpie.cli.requestitems import RequestItems
from httpie.compat import is_windows
from .utils.matching import assert_output_matches, Expect
from .utils import HTTP_OK, MockEnvironment, http
from .utils.matching import assert_output_matches, Expect
def test_Host_header_overwrite(httpbin):
@ -47,3 +50,21 @@ def test_verbose_redirected_stdout_separator(httpbin):
Expect.RESPONSE_HEADERS,
Expect.BODY,
])
@pytest.mark.parametrize(['separator', 'target'], [
(SEPARATOR_HEADER, 'headers'),
(SEPARATOR_QUERY_PARAM, 'params'),
(SEPARATOR_DATA_STRING, 'data'),
])
def test_initial_backslash_number(separator, target):
"""
<https://github.com/httpie/httpie/issues/1408>
"""
back_digit = r'\0'
raw_arg = back_digit + separator + back_digit
expected_parsed_data = {back_digit: back_digit}
parsed_arg = KeyValueArgType(separator)(raw_arg)
items = RequestItems.from_args([parsed_arg])
parsed_data = getattr(items, target)
assert parsed_data == expected_parsed_data