mirror of
https://github.com/httpie/cli.git
synced 2025-08-10 10:07:44 +02:00
Compare commits
24 Commits
Author | SHA1 | Date | |
---|---|---|---|
70a78249c1 | |||
fc85988368 | |||
83bd8059de | |||
3af5f1f305 | |||
4351650691 | |||
770976a66e | |||
29b692d597 | |||
8936d1b71e | |||
4f32b76223 | |||
c9d770017e | |||
cdf691c212 | |||
684a4708d7 | |||
5754e33a75 | |||
14fe7dbb27 | |||
3a6ac7d126 | |||
e9080e6b22 | |||
c73858b9c3 | |||
7340b2b64d | |||
8d246415fd | |||
381dd4f619 | |||
e6bad645ed | |||
6e9cd139a6 | |||
deee2dffd0 | |||
c3be722188 |
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@ -1,5 +1,5 @@
|
||||
name: Build
|
||||
on: [push]
|
||||
on: [push, pull_request]
|
||||
jobs:
|
||||
extras:
|
||||
# Run coverage and extra tests only once
|
||||
|
@ -6,6 +6,18 @@ This document records all notable changes to `HTTPie <https://httpie.org>`_.
|
||||
This project adheres to `Semantic Versioning <https://semver.org/>`_.
|
||||
|
||||
|
||||
`2.1.0`_ (2020-04-18)
|
||||
---------------------
|
||||
|
||||
* Added ``--path-as-is`` to bypass dot segment (``/../`` or ``/./``)
|
||||
URL squashing (#895).
|
||||
* Changed the default value ``Accept`` header value for JSON requests from
|
||||
``application/json, */*`` to ``application/json, */*;q=0.5``
|
||||
to clearly indicate preference (#488).
|
||||
* Fixed ``--form`` file upload mixed with redirected ``stdin`` error handling
|
||||
(#840).
|
||||
|
||||
|
||||
`2.0.0`_ (2020-01-12)
|
||||
-------------------------
|
||||
* Removed Python 2.7 support (`EOL Jan 2020 <https://www.python.org/doc/sunset-python-2/>`_).
|
||||
@ -14,7 +26,7 @@ This project adheres to `Semantic Versioning <https://semver.org/>`_.
|
||||
* Replaced the old collect-all-then-process handling of HTTP communication
|
||||
with one-by-one processing of each HTTP request or response as they become
|
||||
available. This means that you can see headers immediately,
|
||||
see what is being send even when the request fails, etc.
|
||||
see what is being sent even if the request fails, etc.
|
||||
* Removed automatic config file creation to avoid concurrency issues.
|
||||
* Removed the default 30-second connection ``--timeout`` limit.
|
||||
* Removed Python’s default limit of 100 response headers.
|
||||
@ -409,4 +421,9 @@ This project adheres to `Semantic Versioning <https://semver.org/>`_.
|
||||
.. _1.0.2: https://github.com/jakubroztocil/httpie/compare/1.0.1...1.0.2
|
||||
.. _1.0.3: https://github.com/jakubroztocil/httpie/compare/1.0.2...1.0.3
|
||||
.. _2.0.0: https://github.com/jakubroztocil/httpie/compare/1.0.3...2.0.0
|
||||
.. _2.1.0-dev: https://github.com/jakubroztocil/httpie/compare/2.0.0...master
|
||||
.. _2.1.0: https://github.com/jakubroztocil/httpie/compare/2.0.0...2.1.0
|
||||
|
||||
|
||||
.. _#488:https://github.com/jakubroztocil/httpie/issues/488
|
||||
.. _#840:https://github.com/jakubroztocil/httpie/issues/840
|
||||
.. _#895:https://github.com/jakubroztocil/httpie/issues/895
|
||||
|
2
LICENSE
2
LICENSE
@ -1,4 +1,4 @@
|
||||
Copyright © 2012-2019 Jakub Roztocil <jakub@roztocil.co>
|
||||
Copyright © 2012-2020 Jakub Roztocil <jakub@roztocil.co>
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
374
README.rst
374
README.rst
@ -27,11 +27,20 @@ generally interacting with HTTP servers.
|
||||
.. section-numbering::
|
||||
|
||||
|
||||
About this document
|
||||
===================
|
||||
|
||||
This documentation is best viewed at `httpie.org/docs <https://httpie.org/docs>`_,
|
||||
where you can select your corresponding HTTPie version as well as run examples directly from the
|
||||
browser using a `termible.io <https://termible.io?utm_source=httpie-readme>`_ embedded terminal.
|
||||
If you are reading this on GitHub, then this text covers the current *development* version.
|
||||
You are invited to submit fixes and improvements to the the docs by editing
|
||||
`README.rst <https://github.com/jakubroztocil/httpie/blob/master/README.rst>`_.
|
||||
|
||||
|
||||
Main features
|
||||
=============
|
||||
|
||||
|
||||
* Expressive and intuitive syntax
|
||||
* Formatted and colorized terminal output
|
||||
* Built-in JSON support
|
||||
@ -86,7 +95,7 @@ system package manager, for example:
|
||||
.. code-block:: bash
|
||||
|
||||
# Debian, Ubuntu, etc.
|
||||
$ apt-get install httpie
|
||||
$ apt install httpie
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
@ -157,13 +166,13 @@ Otherwise with ``pip``:
|
||||
|
||||
|
||||
Verify that now we have the
|
||||
`current development version identifier <https://github.com/jakubroztocil/httpie/blob/0af6ae1be444588bbc4747124e073423151178a0/httpie/__init__.py#L5>`_
|
||||
`current development version identifier <https://github.com/jakubroztocil/httpie/blob/master/httpie/__init__.py#L6>`_
|
||||
with the ``-dev`` suffix, for example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ http --version
|
||||
1.0.0-dev
|
||||
# 2.0.0-dev
|
||||
|
||||
|
||||
Usage
|
||||
@ -175,7 +184,7 @@ Hello World:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ http httpie.org
|
||||
$ http https://httpie.org/hello
|
||||
|
||||
|
||||
Synopsis:
|
||||
@ -195,21 +204,28 @@ Custom `HTTP method`_, `HTTP headers`_ and `JSON`_ data:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ http PUT example.org X-API-Token:123 name=John
|
||||
$ http PUT httpbin.org/put X-API-Token:123 name=John
|
||||
|
||||
|
||||
Submitting `forms`_:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ http -f POST example.org hello=World
|
||||
$ http -f POST httpbin.org/post hello=World
|
||||
|
||||
|
||||
See the request that is being sent using one of the `output options`_:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ http -v example.org
|
||||
$ http -v httpbin.org/get
|
||||
|
||||
|
||||
Build and print a request without sending it using `offline mode`_:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ http --offline httpbin.org/post hello=offline
|
||||
|
||||
|
||||
Use `Github API`_ to post a comment on an
|
||||
@ -225,29 +241,33 @@ Upload a file using `redirected input`_:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ http example.org < file.json
|
||||
$ http httpbin.org/post < files/data.json
|
||||
|
||||
|
||||
Download a file and save it via `redirected output`_:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ http example.org/file > file
|
||||
$ http httpbin.org/image/png > image.png
|
||||
|
||||
|
||||
Download a file ``wget`` style:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ http --download example.org/file
|
||||
$ http --download httpbin.org/image/png
|
||||
|
||||
Use named `sessions`_ to make certain aspects or the communication persistent
|
||||
Use named `sessions`_ to make certain aspects of the communication persistent
|
||||
between requests to the same host:
|
||||
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ http --session=logged-in -a username:password httpbin.org/get API-Key:123
|
||||
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ http --session=logged-in httpbin.org/headers
|
||||
|
||||
|
||||
@ -267,14 +287,14 @@ The name of the HTTP method comes right before the URL argument:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ http DELETE example.org/todos/7
|
||||
$ http DELETE httpbin.org/delete
|
||||
|
||||
|
||||
Which looks similar to the actual ``Request-Line`` that is sent:
|
||||
|
||||
.. code-block:: http
|
||||
|
||||
DELETE /todos/7 HTTP/1.1
|
||||
DELETE /delete HTTP/1.1
|
||||
|
||||
|
||||
When the ``METHOD`` argument is omitted from the command, HTTPie defaults to
|
||||
@ -296,7 +316,7 @@ If you find yourself manually constructing URLs with querystring parameters
|
||||
on the terminal, you may appreciate the ``param==value`` syntax for appending
|
||||
URL parameters.
|
||||
|
||||
With that, you don't have to worry about escaping the ``&``
|
||||
With that, you don’t have to worry about escaping the ``&``
|
||||
separators for your shell. Additionally, any special characters in the
|
||||
parameter name or value get automatically URL-escaped
|
||||
(as opposed to parameters specified in the full URL, which HTTPie doesn’t
|
||||
@ -380,6 +400,34 @@ Example for the `httpie-unixsocket <https://github.com/httpie/httpie-unixsocket>
|
||||
# Now the scheme can be omitted
|
||||
$ http-unix %2Fvar%2Frun%2Fdocker.sock/info
|
||||
|
||||
|
||||
``--path-as-is``
|
||||
----------------
|
||||
|
||||
The standard behaviour of HTTP clients is to normalize the path portion of URLs by squashing dot segments
|
||||
as a typically filesystem would:
|
||||
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ http -v example.org/./../../etc/password
|
||||
|
||||
.. code-block:: http
|
||||
|
||||
GET /etc/password HTTP/1.1
|
||||
|
||||
|
||||
The ``--path-as-is`` option allows you to disable this behavior:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ http --path-as-is -v example.org/./../../etc/password
|
||||
|
||||
.. code-block:: http
|
||||
|
||||
GET /../../etc/password HTTP/1.1
|
||||
|
||||
|
||||
Request items
|
||||
=============
|
||||
|
||||
@ -420,14 +468,14 @@ their type is distinguished only by the separator used:
|
||||
+-----------------------+-----------------------------------------------------+
|
||||
|
||||
|
||||
Note that data fields aren't the only way to specify request data:
|
||||
Note that data fields aren’t the only way to specify request data:
|
||||
`Redirected input`_ is a mechanism for passing arbitrary request data.
|
||||
|
||||
|
||||
Escaping rules
|
||||
--------------
|
||||
|
||||
You can use ``\`` to escape characters that shouldn't be used as separators
|
||||
You can use ``\`` to escape characters that shouldn’t be used as separators
|
||||
(or parts thereof). For instance, ``foo\==bar`` will become a data key/value
|
||||
pair (``foo=`` and ``bar``) instead of a URL parameter.
|
||||
|
||||
@ -464,15 +512,15 @@ Simple example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ http PUT example.org name=John email=john@example.org
|
||||
$ http PUT httpbin.org/put name=John email=john@example.org
|
||||
|
||||
.. code-block:: http
|
||||
|
||||
PUT / HTTP/1.1
|
||||
Accept: application/json, */*
|
||||
Accept: application/json, */*;q=0.5
|
||||
Accept-Encoding: gzip, deflate
|
||||
Content-Type: application/json
|
||||
Host: example.org
|
||||
Host: httpbin.org
|
||||
|
||||
{
|
||||
"name": "John",
|
||||
@ -490,7 +538,7 @@ both of which can be overwritten:
|
||||
|
||||
================ =======================================
|
||||
``Content-Type`` ``application/json``
|
||||
``Accept`` ``application/json, */*``
|
||||
``Accept`` ``application/json, */*;q=0.5``
|
||||
================ =======================================
|
||||
|
||||
|
||||
@ -499,8 +547,8 @@ Explicit JSON
|
||||
|
||||
You can use ``--json, -j`` to explicitly set ``Accept``
|
||||
to ``application/json`` regardless of whether you are sending data
|
||||
(it's a shortcut for setting the header via the usual header notation:
|
||||
``http url Accept:'application/json, */*'``). Additionally,
|
||||
(it’s a shortcut for setting the header via the usual header notation:
|
||||
``http url Accept:'application/json, */*;q=0.5'``). Additionally,
|
||||
HTTPie will try to detect JSON responses even when the
|
||||
``Content-Type`` is incorrectly ``text/plain`` or unknown.
|
||||
|
||||
@ -509,25 +557,28 @@ HTTPie will try to detect JSON responses even when the
|
||||
Non-string JSON fields
|
||||
----------------------
|
||||
|
||||
Non-string fields use the ``:=`` separator, which allows you to embed raw JSON
|
||||
into the resulting object. Text and raw JSON files can also be embedded into
|
||||
Non-string JSON fields use the ``:=`` separator, which allows you to embed arbitrary JSON data
|
||||
into the resulting JSON object. Additionally, text and raw JSON files can also be embedded into
|
||||
fields using ``=@`` and ``:=@``:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ http PUT api.example.com/person/1 \
|
||||
name=John \
|
||||
age:=29 married:=false hobbies:='["http", "pies"]' \ # Raw JSON
|
||||
description=@about-john.txt \ # Embed text file
|
||||
bookmarks:=@bookmarks.json # Embed JSON file
|
||||
$ http PUT httpbin.org/put \
|
||||
name=John \ # String (default)
|
||||
age:=29 \ # Raw JSON — Number
|
||||
married:=false \ # Raw JSON — Boolean
|
||||
hobbies:='["http", "pies"]' \ # Raw JSON — Array
|
||||
favorite:='{"tool": "HTTPie"}' \ # Raw JSON — Object
|
||||
bookmarks:=@files/data.json \ # Embed JSON file
|
||||
description=@files/text.txt # Embed text file
|
||||
|
||||
|
||||
.. code-block:: http
|
||||
|
||||
PUT /person/1 HTTP/1.1
|
||||
Accept: application/json, */*
|
||||
Accept: application/json, */*;q=0.5
|
||||
Content-Type: application/json
|
||||
Host: api.example.com
|
||||
Host: httpbin.org
|
||||
|
||||
{
|
||||
"age": 29,
|
||||
@ -538,19 +589,33 @@ fields using ``=@`` and ``:=@``:
|
||||
"description": "John is a nice guy who likes pies.",
|
||||
"married": false,
|
||||
"name": "John",
|
||||
"favorite": {
|
||||
"tool": "HTTPie"
|
||||
},
|
||||
"bookmarks": {
|
||||
"HTTPie": "https://httpie.org",
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Please note that with this syntax the command gets unwieldy when sending
|
||||
complex data. In that case it's always better to use `redirected input`_:
|
||||
Raw and complex JSON
|
||||
--------------------
|
||||
|
||||
Please note that with the `request items`_ data field syntax, commands
|
||||
can quickly become unwieldy when sending complex structures.
|
||||
In such cases, it’s better to pass the full raw JSON data via
|
||||
`redirected input`_, for example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ http POST api.example.com/person/1 < person.json
|
||||
$ echo '{"hello": "world"}' | http POST httpbin.org/post
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ http POST httpbin.org/post < files/data.json
|
||||
|
||||
Furthermore, this syntax only allows you to send an object as the JSON document, but not an array, etc.
|
||||
Here, again, the solution is to use `redirected input`_.
|
||||
|
||||
Forms
|
||||
=====
|
||||
@ -568,12 +633,12 @@ Regular forms
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ http --form POST api.example.org/person/1 name='John Smith'
|
||||
$ http --form POST httpbin.org/post name='John Smith'
|
||||
|
||||
|
||||
.. code-block:: http
|
||||
|
||||
POST /person/1 HTTP/1.1
|
||||
POST /post HTTP/1.1
|
||||
Content-Type: application/x-www-form-urlencoded; charset=utf-8
|
||||
|
||||
name=John+Smith
|
||||
@ -587,7 +652,7 @@ If one or more file fields is present, the serialization and content type is
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ http -f POST example.com/jobs name='John Smith' cv@~/Documents/cv.pdf
|
||||
$ http -f POST httpbin.org/post name='John Smith' cv@~/files/data.xml
|
||||
|
||||
|
||||
The request above is the same as if the following HTML form were
|
||||
@ -611,17 +676,17 @@ To set custom headers you can use the ``Header:Value`` notation:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ http example.org User-Agent:Bacon/1.0 'Cookie:valued-visitor=yes;foo=bar' \
|
||||
$ http httpbin.org/headers User-Agent:Bacon/1.0 'Cookie:valued-visitor=yes;foo=bar' \
|
||||
X-Foo:Bar Referer:https://httpie.org/
|
||||
|
||||
|
||||
.. code-block:: http
|
||||
|
||||
GET / HTTP/1.1
|
||||
GET /headers HTTP/1.1
|
||||
Accept: */*
|
||||
Accept-Encoding: gzip, deflate
|
||||
Cookie: valued-visitor=yes;foo=bar
|
||||
Host: example.org
|
||||
Host: httpbin.org
|
||||
Referer: https://httpie.org/
|
||||
User-Agent: Bacon/1.0
|
||||
X-Foo: Bar
|
||||
@ -679,6 +744,50 @@ HTTPie reads before giving up (the default ``0``, i.e., there’s no limit).
|
||||
|
||||
|
||||
|
||||
Offline mode
|
||||
============
|
||||
|
||||
Use ``--offline`` to construct HTTP requests without sending them anywhere.
|
||||
With ``--offline``, HTTPie builds a request based on the specified options and arguments, prints it to ``stdout``,
|
||||
and then exists. It works completely offline; no network connection is ever made.
|
||||
This has a number of use cases, including:
|
||||
|
||||
|
||||
Generating API documentation examples that you can copy & paste without sending a request:
|
||||
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ http --offline POST server.chess/api/games API-Key:ZZZ w=magnus b=hikaru t=180 i=2
|
||||
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ http --offline MOVE server.chess/api/games/123 API-Key:ZZZ p=b a=R1a3 t=77
|
||||
|
||||
|
||||
Generating raw requests that can be sent with any other client:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# 1. save a raw request to a file:
|
||||
$ http --offline POST httpbin.org/post hello=world > request.http
|
||||
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# 2. send it over the wire with, for example, the fantastic netcat tool:
|
||||
$ nc httpbin.org 80 < request.http
|
||||
|
||||
|
||||
You can also use the ``--offline`` mode for debugging and exploring HTTP and HTTPie, and for “dry runs”.
|
||||
|
||||
``--offline`` has the side-effect of automatically activating ``--print=HB``, i.e., both the request headers and the body
|
||||
are printed. You can customize the output with the usual `output options`_, with the exception that there
|
||||
is not response to be printed. You can use ``--offline`` in combination with all the other options (e.g., ``--session``).
|
||||
|
||||
|
||||
|
||||
Cookies
|
||||
=======
|
||||
|
||||
@ -691,7 +800,7 @@ Send a single cookie:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ http example.org Cookie:sessionid=foo
|
||||
$ http httpbin.org/cookies Cookie:sessionid=foo
|
||||
|
||||
.. code-block:: http
|
||||
|
||||
@ -700,7 +809,7 @@ Send a single cookie:
|
||||
Accept-Encoding: gzip, deflate
|
||||
Connection: keep-alive
|
||||
Cookie: sessionid=foo
|
||||
Host: example.org
|
||||
Host: httpbin.org
|
||||
User-Agent: HTTPie/0.9.9
|
||||
|
||||
|
||||
@ -709,7 +818,7 @@ Send multiple cookies
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ http example.org 'Cookie:sessionid=foo;another-cookie=bar'
|
||||
$ http httpbin.org/cookies 'Cookie:sessionid=foo;another-cookie=bar'
|
||||
|
||||
.. code-block:: http
|
||||
|
||||
@ -718,11 +827,11 @@ Send multiple cookies
|
||||
Accept-Encoding: gzip, deflate
|
||||
Connection: keep-alive
|
||||
Cookie: sessionid=foo;another-cookie=bar
|
||||
Host: example.org
|
||||
Host: httpbin.org
|
||||
User-Agent: HTTPie/0.9.9
|
||||
|
||||
|
||||
If you often deal with cookies in your requests, then chances are you'd appreciate
|
||||
If you often deal with cookies in your requests, then chances are you’d appreciate
|
||||
the `sessions`_ feature.
|
||||
|
||||
|
||||
@ -735,7 +844,7 @@ The currently supported authentication schemes are Basic and Digest
|
||||
=================== ======================================================
|
||||
``--auth, -a`` Pass a ``username:password`` pair as
|
||||
the argument. Or, if you only specify a username
|
||||
(``-a username``), you'll be prompted for
|
||||
(``-a username``), you’ll be prompted for
|
||||
the password before the request is sent.
|
||||
To send an empty password, pass ``username:``.
|
||||
The ``username:password@hostname`` URL syntax is
|
||||
@ -755,7 +864,7 @@ Basic auth
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ http -a username:password example.org
|
||||
$ http -a username:password httpbin.org/basic-auth/username/password
|
||||
|
||||
|
||||
Digest auth
|
||||
@ -764,7 +873,7 @@ Digest auth
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ http -A digest -a username:password example.org
|
||||
$ http -A digest -a username:password httpbin.org/digest-auth/httpie/username/password
|
||||
|
||||
|
||||
Password prompt
|
||||
@ -772,7 +881,15 @@ Password prompt
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ http -a username example.org
|
||||
$ http -a username httpbin.org/basic-auth/username/password
|
||||
|
||||
|
||||
Empty password
|
||||
--------------
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ http -a username: httpbin.org/headers
|
||||
|
||||
|
||||
``.netrc``
|
||||
@ -810,7 +927,7 @@ Auth plugins
|
||||
|
||||
Additional authentication mechanism can be installed as plugins.
|
||||
They can be found on the `Python Package Index <https://pypi.python.org/pypi?%3Aaction=search&term=httpie&submit=search>`_.
|
||||
Here's a few picks:
|
||||
Here’s a few picks:
|
||||
|
||||
* `httpie-api-auth <https://github.com/pd/httpie-api-auth>`_: ApiAuth
|
||||
* `httpie-aws-auth <https://github.com/httpie/httpie-aws-auth>`_: AWS / Amazon S3
|
||||
@ -871,7 +988,7 @@ To change the default limit of maximum ``30`` redirects, use the
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ http --follow --all --max-redirects=5 httpbin.org/redirect/3
|
||||
$ http --follow --all --max-redirects=2 httpbin.org/redirect/3
|
||||
|
||||
|
||||
Proxies
|
||||
@ -913,7 +1030,7 @@ SOCKS
|
||||
-----
|
||||
|
||||
Homebrew-installed HTTPie comes with SOCKS proxy support out of the box.
|
||||
To enable SOCKS proxy support for non-Homebrew installations, you'll
|
||||
To enable SOCKS proxy support for non-Homebrew installations, you’ll
|
||||
might need to install ``requests[socks]`` manually using ``pip``:
|
||||
|
||||
|
||||
@ -935,12 +1052,12 @@ HTTPS
|
||||
Server SSL certificate verification
|
||||
-----------------------------------
|
||||
|
||||
To skip the host's SSL certificate verification, you can pass ``--verify=no``
|
||||
To skip the host’s SSL certificate verification, you can pass ``--verify=no``
|
||||
(default is ``yes``):
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ http --verify=no https://example.org
|
||||
$ http --verify=no https://httpbin.org/get
|
||||
|
||||
|
||||
Custom CA bundle
|
||||
@ -1009,7 +1126,7 @@ documentation examples:
|
||||
|
||||
$ http --verbose PUT httpbin.org/put hello=world
|
||||
PUT /put HTTP/1.1
|
||||
Accept: application/json, */*
|
||||
Accept: application/json, */*;q=0.5
|
||||
Accept-Encoding: gzip, deflate
|
||||
Content-Type: application/json
|
||||
Host: httpbin.org
|
||||
@ -1071,7 +1188,7 @@ authentication is used (``--auth=digest``), etc.
|
||||
|
||||
|
||||
The intermediary requests/response are by default formatted according to
|
||||
``--print, -p`` (and its shortcuts described above). If you'd like to change
|
||||
``--print, -p`` (and its shortcuts described above). If you’d like to change
|
||||
that, use the ``--history-print, -P`` option. It takes the same
|
||||
arguments as ``--print, -p`` but applies to the intermediary requests only.
|
||||
|
||||
@ -1086,22 +1203,22 @@ Conditional body download
|
||||
-------------------------
|
||||
|
||||
As an optimization, the response body is downloaded from the server
|
||||
only if it's part of the output. This is similar to performing a ``HEAD``
|
||||
only if it’s part of the output. This is similar to performing a ``HEAD``
|
||||
request, except that it applies to any HTTP method you use.
|
||||
|
||||
Let's say that there is an API that returns the whole resource when it is
|
||||
Let’s say that there is an API that returns the whole resource when it is
|
||||
updated, but you are only interested in the response headers to see the
|
||||
status code after an update:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ http --headers PATCH example.org/Really-Huge-Resource name='New Name'
|
||||
$ http --headers PATCH httpbin.org/patch name='New Name'
|
||||
|
||||
|
||||
Since we are only printing the HTTP headers here, the connection to the server
|
||||
is closed as soon as all the response headers have been received.
|
||||
Therefore, bandwidth and time isn't wasted downloading the body
|
||||
which you don't care about. The response headers are downloaded always,
|
||||
Therefore, bandwidth and time isn’t wasted downloading the body
|
||||
which you don’t care about. The response headers are downloaded always,
|
||||
even if they are not part of the output
|
||||
|
||||
|
||||
@ -1117,28 +1234,28 @@ Redirect from a file:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ http PUT example.com/person/1 X-API-Token:123 < person.json
|
||||
$ http PUT httpbin.org/put X-API-Token:123 < files/data.json
|
||||
|
||||
|
||||
Or the output of another program:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ grep '401 Unauthorized' /var/log/httpd/error_log | http POST example.org/intruders
|
||||
$ grep '401 Unauthorized' /var/log/httpd/error_log | http POST httpbin.org/post
|
||||
|
||||
|
||||
You can use ``echo`` for simple data:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ echo '{"name": "John"}' | http PATCH example.com/person/1 X-API-Token:123
|
||||
$ echo '{"name": "John"}' | http PATCH httpbin.org/patch X-API-Token:123
|
||||
|
||||
|
||||
You can also use a Bash *here string*:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ http example.com/ <<<'{"name": "John"}'
|
||||
$ http httpbin.org/post <<<'{"name": "John"}'
|
||||
|
||||
|
||||
You can even pipe web services together using HTTPie:
|
||||
@ -1152,14 +1269,14 @@ You can use ``cat`` to enter multiline data on the terminal:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ cat | http POST example.com
|
||||
$ cat | http POST httpbin.org/post
|
||||
<paste>
|
||||
^D
|
||||
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ cat | http POST example.com/todos Content-Type:text/plain
|
||||
$ cat | http POST httpbin.org/post Content-Type:text/plain
|
||||
- buy milk
|
||||
- call parents
|
||||
^D
|
||||
@ -1169,7 +1286,7 @@ On OS X, you can send the contents of the clipboard with ``pbpaste``:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ pbpaste | http PUT example.com
|
||||
$ pbpaste | http PUT httpbin.org/put
|
||||
|
||||
|
||||
Passing data through ``stdin`` cannot be combined with data fields specified
|
||||
@ -1198,7 +1315,7 @@ verbatim contents of that XML file with ``Content-Type: application/xml``:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ http PUT httpbin.org/put @/data/file.xml
|
||||
$ http PUT httpbin.org/put @files/data.xml
|
||||
|
||||
|
||||
Terminal output
|
||||
@ -1213,8 +1330,16 @@ Colors and formatting
|
||||
|
||||
Syntax highlighting is applied to HTTP headers and bodies (where it makes
|
||||
sense). You can choose your preferred color scheme via the ``--style`` option
|
||||
if you don't like the default one (see ``$ http --help`` for the possible
|
||||
values).
|
||||
if you don’t like the default one. There dozens of styles available, here are just a few special or notable ones:
|
||||
|
||||
==================== ========================================================================
|
||||
``auto`` Follows your terminal ANSI color styles. This is the default style used by HTTPie.
|
||||
``default`` Default styles of the underlying Pygments library. Not actually used by default by HTTPie.
|
||||
You can enable it with ``--style=default``
|
||||
``monokai`` A popular color scheme. Enable with ``--style=monokai``.
|
||||
``fruity`` A bold, colorful scheme. Enable with ``--style=fruity``.
|
||||
… See ``$ http --help`` for all the possible ``--style`` values.
|
||||
==================== ========================================================================
|
||||
|
||||
Also, the following formatting is applied:
|
||||
|
||||
@ -1243,7 +1368,7 @@ that the response body is binary,
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ http example.org/Movie.mov
|
||||
$ http httpbin.org/bytes/2000
|
||||
|
||||
|
||||
You will nearly instantly see something like this:
|
||||
@ -1251,10 +1376,7 @@ You will nearly instantly see something like this:
|
||||
.. code-block:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Accept-Ranges: bytes
|
||||
Content-Encoding: gzip
|
||||
Content-Type: video/quicktime
|
||||
Transfer-Encoding: chunked
|
||||
Content-Type: application/octet-stream
|
||||
|
||||
+-----------------------------------------+
|
||||
| NOTE: binary data not shown in terminal |
|
||||
@ -1267,11 +1389,11 @@ Redirected output
|
||||
HTTPie uses a different set of defaults for redirected output than for
|
||||
`terminal output`_. The differences being:
|
||||
|
||||
* Formatting and colors aren't applied (unless ``--pretty`` is specified).
|
||||
* Formatting and colors aren’t applied (unless ``--pretty`` is specified).
|
||||
* Only the response body is printed (unless one of the `output options`_ is set).
|
||||
* Also, binary data isn't suppressed.
|
||||
* Also, binary data isn’t suppressed.
|
||||
|
||||
The reason is to make piping HTTPie's output to another programs and
|
||||
The reason is to make piping HTTPie’s output to another programs and
|
||||
downloading files work with no extra flags. Most of the time, only the raw
|
||||
response body is of an interest when the output is redirected.
|
||||
|
||||
@ -1279,7 +1401,7 @@ Download a file:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ http example.org/Movie.mov > Movie.mov
|
||||
$ http httpbin.org/image/png > image.png
|
||||
|
||||
|
||||
Download an image of Octocat, resize it using ImageMagick, upload it elsewhere:
|
||||
@ -1294,7 +1416,7 @@ Force colorizing and formatting, and show both the request and the response in
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ http --pretty=all --verbose example.org | less -R
|
||||
$ http --pretty=all --verbose httpbin.org/get | less -R
|
||||
|
||||
|
||||
The ``-R`` flag tells ``less`` to interpret color escape sequences included
|
||||
@ -1373,7 +1495,7 @@ Resuming downloads
|
||||
|
||||
If ``--output, -o`` is specified, you can resume a partial download using the
|
||||
``--continue, -c`` option. This only works with servers that support
|
||||
``Range`` requests and ``206 Partial Content`` responses. If the server doesn't
|
||||
``Range`` requests and ``206 Partial Content`` responses. If the server doesn’t
|
||||
support that, the whole file will simply be downloaded:
|
||||
|
||||
.. code-block:: bash
|
||||
@ -1386,7 +1508,9 @@ Other notes
|
||||
* The ``--download`` option only changes how the response body is treated.
|
||||
* You can still set custom headers, use sessions, ``--verbose, -v``, etc.
|
||||
* ``--download`` always implies ``--follow`` (redirects are followed).
|
||||
* HTTPie exits with status code ``1`` (error) if the body hasn't been fully
|
||||
* ``--download`` also implies ``--check-status``
|
||||
(error HTTP status will result in a non-zero exist static code).
|
||||
* HTTPie exits with status code ``1`` (error) if the body hasn’t been fully
|
||||
downloaded.
|
||||
* ``Accept-Encoding`` cannot be set with ``--download``.
|
||||
|
||||
@ -1424,7 +1548,7 @@ Prettified streamed response:
|
||||
$ http --stream -f -a YOUR-TWITTER-NAME https://stream.twitter.com/1/statuses/filter.json track='Justin Bieber'
|
||||
|
||||
|
||||
Streamed output by small chunks alá ``tail -f``:
|
||||
Streamed output by small chunks à la ``tail -f``:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
@ -1450,11 +1574,19 @@ to the same host.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# Create a new session
|
||||
$ http --session=/tmp/session.json example.org API-Token:123
|
||||
# Create a new session:
|
||||
$ http --session=./session.json httpbin.org/headers API-Token:123
|
||||
|
||||
# Re-use an existing session — API-Token will be set:
|
||||
$ http --session=/tmp/session.json example.org
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# Inspect / edit the generated session file:
|
||||
$ cat session.json
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# Re-use the existing session — the API-Token header will be set:
|
||||
$ http --session=./session.json httpbin.org/headers
|
||||
|
||||
|
||||
All session data, including credentials, cookie data,
|
||||
@ -1469,31 +1601,39 @@ Named sessions
|
||||
|
||||
|
||||
You can create one or more named session per host. For example, this is how
|
||||
you can create a new session named ``user1`` for ``example.org``:
|
||||
you can create a new session named ``user1`` for ``httpbin.org``:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ http --session=user1 -a user1:password example.org X-Foo:Bar
|
||||
$ http --session=user1 -a user1:password httpbin.org/get X-Foo:Bar
|
||||
|
||||
From now on, you can refer to the session by its name. When you choose to
|
||||
use the session again, any previously specified authentication or HTTP headers
|
||||
From now on, you can refer to the session by its name (``user1``). When you choose
|
||||
to use the session again, any previously specified authentication or HTTP headers
|
||||
will automatically be set:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ http --session=user1 example.org
|
||||
$ http --session=user1 httpbin.org/get
|
||||
|
||||
To create or reuse a different session, simple specify a different name:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ http --session=user2 -a user2:password example.org X-Bar:Foo
|
||||
$ http --session=user2 -a user2:password httpbin.org/get X-Bar:Foo
|
||||
|
||||
Named sessions’s data is stored in JSON files in the the ``sessions``
|
||||
subdirectory of the `config`_ directory:
|
||||
``~/.httpie/sessions/<host>/<name>.json``
|
||||
(``%APPDATA%\httpie\sessions\<host>\<name>.json`` on Windows).
|
||||
|
||||
If you have executed the above commands on a unix machine,
|
||||
you should be able list the generated sessions files using:
|
||||
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ ls -l ~/.httpie/sessions/httpbin.org
|
||||
|
||||
|
||||
Anonymous sessions
|
||||
------------------
|
||||
@ -1503,19 +1643,43 @@ allows for sessions to be re-used across multiple hosts:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# Create a session:
|
||||
$ http --session=/tmp/session.json example.org
|
||||
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# Use the session to make a request to another host:
|
||||
$ http --session=/tmp/session.json admin.example.org
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# You can also refer to a previously created named session:
|
||||
$ http --session=~/.httpie/sessions/another.example.org/test.json example.org
|
||||
$ http --session-read-only=/tmp/session.json example.org
|
||||
|
||||
|
||||
When creating anonymous sessions, please remember to always include at least
|
||||
one ``/``, even if the session files is located in the current directory
|
||||
(i.e., ``--session=./session.json`` instead of just ``--session=session.json``),
|
||||
otherwise HTTPie assumes a named session instead.
|
||||
|
||||
|
||||
Readonly session
|
||||
----------------
|
||||
|
||||
To use an existing session file without updating it from the request/response
|
||||
exchange once it is created, specify the session name via
|
||||
exchange after it has been created, specify the session name via
|
||||
``--session-read-only=SESSION_NAME_OR_PATH`` instead.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# If the session file doesn’t exist, then it is created:
|
||||
$ http --session-read-only=./ro-session.json httpbin.org/headers Custom-Header:orig-value
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# But it is not updated:
|
||||
$ http --session-read-only=./ro-session.json httpbin.org/headers Custom-Header:new-value
|
||||
|
||||
Config
|
||||
======
|
||||
@ -1536,7 +1700,7 @@ environment variable:
|
||||
.. code-block:: bash
|
||||
|
||||
$ export HTTPIE_CONFIG_DIR=/tmp/httpie
|
||||
$ http example.org
|
||||
$ http httpbin.org/get
|
||||
|
||||
To view the exact location run ``http --debug``.
|
||||
|
||||
@ -1598,7 +1762,7 @@ respectively.
|
||||
|
||||
#!/bin/bash
|
||||
|
||||
if http --check-status --ignore-stdin --timeout=2.5 HEAD example.org/health &> /dev/null; then
|
||||
if http --check-status --ignore-stdin --timeout=2.5 HEAD httpbin.org/get &> /dev/null; then
|
||||
echo 'OK!'
|
||||
else
|
||||
case $? in
|
||||
@ -1624,7 +1788,7 @@ What happens is that when HTTPie is invoked for example from a cron job,
|
||||
``stdin`` is not connected to a terminal.
|
||||
Therefore, rules for `redirected input`_ apply, i.e., HTTPie starts to read it
|
||||
expecting that the request body will be passed through.
|
||||
And since there's no data nor ``EOF``, it will be stuck. So unless you're
|
||||
And since there’s no data nor ``EOF``, it will be stuck. So unless you’re
|
||||
piping some data to HTTPie, this flag should be used in scripts.
|
||||
|
||||
Also, it might be good to set a connection ``--timeout`` limit to prevent
|
||||
@ -1639,14 +1803,15 @@ Interface design
|
||||
----------------
|
||||
|
||||
The syntax of the command arguments closely corresponds to the actual HTTP
|
||||
requests sent over the wire. It has the advantage that it's easy to remember
|
||||
requests sent over the wire. It has the advantage that it’s easy to remember
|
||||
and read. It is often possible to translate an HTTP request to an HTTPie
|
||||
argument list just by inlining the request elements. For example, compare this
|
||||
HTTP request:
|
||||
|
||||
.. code-block:: http
|
||||
|
||||
POST /collection HTTP/1.1
|
||||
POST /post HTTP/1.1
|
||||
Host: httpbin.org
|
||||
X-API-Key: 123
|
||||
User-Agent: Bacon/1.0
|
||||
Content-Type: application/x-www-form-urlencoded
|
||||
@ -1658,7 +1823,7 @@ with the HTTPie command that sends it:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ http -f POST example.org/collection \
|
||||
$ http -f POST httpbin.org/post \
|
||||
X-API-Key:123 \
|
||||
User-Agent:Bacon/1.0 \
|
||||
name=value \
|
||||
@ -1667,7 +1832,7 @@ with the HTTPie command that sends it:
|
||||
|
||||
Notice that both the order of elements and the syntax is very similar,
|
||||
and that only a small portion of the command is used to control HTTPie and
|
||||
doesn't directly correspond to any part of the request (here it's only ``-f``
|
||||
doesn’t directly correspond to any part of the request (here it’s only ``-f``
|
||||
asking HTTPie to send a form request).
|
||||
|
||||
The two modes, ``--pretty=all`` (default for terminal) and ``--pretty=none``
|
||||
@ -1793,4 +1958,3 @@ have contributed.
|
||||
.. |downloads| image:: https://pepy.tech/badge/httpie
|
||||
:target: https://pepy.tech/project/httpie
|
||||
:alt: Download count
|
||||
|
||||
|
@ -9,22 +9,23 @@ class Httpie < Formula
|
||||
|
||||
desc "User-friendly cURL replacement (command-line HTTP client)"
|
||||
homepage "https://httpie.org/"
|
||||
url "https://files.pythonhosted.org/packages/d5/a4/ab61c1dbfdef33c7b7f5f7df0d79eb5cd55a106601a4acc17f983f320b4a/httpie-1.0.3.tar.gz"
|
||||
sha256 "6d1b6e21da7d3ec030ae95536d4032c1129bdaf9de4adc72c596b87e5f646e80"
|
||||
url "https://files.pythonhosted.org/packages/35/6c/93da2ebd4eb768c3733437ce01b5fae297522434fdeabeeabdc4f42aabd3/httpie-2.0.0.tar.gz"
|
||||
sha256 "8c04f9756f1a7eac71a6dfa0834d0f6813dc8a982d8564f3a7418dcd19107c09"
|
||||
revision 1
|
||||
head "https://github.com/jakubroztocil/httpie.git"
|
||||
|
||||
bottle do
|
||||
cellar :any_skip_relocation
|
||||
sha256 "158258be68ac93de13860be2bef02da6fd8b68aa24b2e6609bcff1ec3f93e7a0" => :mojave
|
||||
sha256 "54352116b6fa2c3bd65f26136fdcb57986dbff8a52de5febf7aea59c126d29e1" => :high_sierra
|
||||
sha256 "9cce71768fe388808e11b26d651b44a6b54219f5406845b4273b5099f5c1f76f" => :sierra
|
||||
sha256 "19694b5ec311939a8b73cc329ca49386155ed3a17e4eca691779c725d36286b5" => :catalina
|
||||
sha256 "8c7d93d55ea3351e25fadfdd3748ca0a3ff7dd62ab9dbf31b7243fba76890c4d" => :mojave
|
||||
sha256 "e0d5269bb5d03a1797c8612005fa46d6a35f2b84eb76e9607ef1169464b566ea" => :high_sierra
|
||||
end
|
||||
|
||||
depends_on "python"
|
||||
depends_on "python@3.8"
|
||||
|
||||
resource "Pygments" do
|
||||
url "https://files.pythonhosted.org/packages/7e/ae/26808275fc76bf2832deb10d3a3ed3107bc4de01b85dcccbe525f2cd6d1e/Pygments-2.4.2.tar.gz"
|
||||
sha256 "881c4c157e45f30af185c1ffe8d549d48ac9127433f2c380c24b84572ad66297"
|
||||
url "https://files.pythonhosted.org/packages/cb/9f/27d4844ac5bf158a33900dbad7985951e2910397998e85712da03ce125f0/Pygments-2.5.2.tar.gz"
|
||||
sha256 "98c8aa5a9f778fcd1026a17361ddaf7330d1b7c62ae97c3bb0ae73e0b9b6b0fe"
|
||||
end
|
||||
|
||||
resource "requests" do
|
||||
@ -33,13 +34,13 @@ class Httpie < Formula
|
||||
end
|
||||
|
||||
resource "certifi" do
|
||||
url "https://files.pythonhosted.org/packages/c5/67/5d0548226bcc34468e23a0333978f0e23d28d0b3f0c71a151aef9c3f7680/certifi-2019.6.16.tar.gz"
|
||||
sha256 "945e3ba63a0b9f577b1395204e13c3a231f9bc0223888be653286534e5873695"
|
||||
url "https://files.pythonhosted.org/packages/41/bf/9d214a5af07debc6acf7f3f257265618f1db242a3f8e49a9b516f24523a6/certifi-2019.11.28.tar.gz"
|
||||
sha256 "25b64c7da4cd7479594d035c08c2d809eb4aab3a26e5a990ea98cc450c320f1f"
|
||||
end
|
||||
|
||||
resource "urllib3" do
|
||||
url "https://files.pythonhosted.org/packages/4c/13/2386233f7ee40aa8444b47f7463338f3cbdf00c316627558784e3f542f07/urllib3-1.25.3.tar.gz"
|
||||
sha256 "dbe59173209418ae49d485b87d1681aefa36252ee85884c31346debd19463232"
|
||||
url "https://files.pythonhosted.org/packages/ad/fc/54d62fa4fc6e675678f9519e677dfc29b8964278d75333cf142892caf015/urllib3-1.25.7.tar.gz"
|
||||
sha256 "f3c5fd51747d450d4dcf6f923c81f78f811aab8205fda64b0aba34a4e48b0745"
|
||||
end
|
||||
|
||||
resource "idna" do
|
||||
@ -53,8 +54,8 @@ class Httpie < Formula
|
||||
end
|
||||
|
||||
resource "PySocks" do
|
||||
url "https://files.pythonhosted.org/packages/15/ab/35824cfdee1aac662e3298275fa1e6cbedb52126d1785f8977959b769ccf/PySocks-1.7.0.tar.gz"
|
||||
sha256 "d9031ea45fdfacbe59a99273e9f0448ddb33c1580fe3831c1b09557c5718977c"
|
||||
url "https://files.pythonhosted.org/packages/bd/11/293dd436aea955d45fc4e8a35b6ae7270f5b8e00b53cf6c024c83b657a11/PySocks-1.7.1.tar.gz"
|
||||
sha256 "3f8804571ebe159c380ac6de37643bb4685970655d3bba243530d6558b799aa0"
|
||||
end
|
||||
|
||||
def install
|
||||
|
@ -3,6 +3,6 @@ HTTPie - a CLI, cURL-like tool for humans.
|
||||
|
||||
"""
|
||||
|
||||
__version__ = '2.0.0'
|
||||
__version__ = '2.1.0'
|
||||
__author__ = 'Jakub Roztocil'
|
||||
__licence__ = 'BSD'
|
||||
|
@ -78,7 +78,7 @@ class HTTPieArgumentParser(argparse.ArgumentParser):
|
||||
|
||||
# Arguments processing and environment setup.
|
||||
self._apply_no_options(no_options)
|
||||
self._validate_download_options()
|
||||
self._process_download_options()
|
||||
self._setup_standard_streams()
|
||||
self._process_output_options()
|
||||
self._process_pretty_options()
|
||||
@ -243,10 +243,11 @@ class HTTPieArgumentParser(argparse.ArgumentParser):
|
||||
Bytes are always read.
|
||||
|
||||
"""
|
||||
if self.args.data:
|
||||
if self.args.data or self.args.files:
|
||||
self.error('Request body (from stdin or a file) and request '
|
||||
'data (key=value) cannot be mixed. Pass '
|
||||
'--ignore-stdin to let key/value take priority.')
|
||||
'--ignore-stdin to let key/value take priority. '
|
||||
'See https://httpie.org/doc#scripting for details.')
|
||||
self.args.data = getattr(fd, 'buffer', fd).read()
|
||||
|
||||
def _guess_method(self):
|
||||
@ -378,7 +379,11 @@ class HTTPieArgumentParser(argparse.ArgumentParser):
|
||||
# noinspection PyTypeChecker
|
||||
self.args.prettify = PRETTY_MAP[self.args.prettify]
|
||||
|
||||
def _validate_download_options(self):
|
||||
def _process_download_options(self):
|
||||
if self.args.offline:
|
||||
self.args.download = False
|
||||
self.args.download_resume = False
|
||||
return
|
||||
if not self.args.download:
|
||||
if self.args.download_resume:
|
||||
self.error('--continue only works with --download')
|
||||
|
@ -552,6 +552,15 @@ network.add_argument(
|
||||
|
||||
"""
|
||||
)
|
||||
network.add_argument(
|
||||
'--path-as-is',
|
||||
default=False,
|
||||
action='store_true',
|
||||
help="""
|
||||
Bypass dot segment (/../ or /./) URL squashing.
|
||||
|
||||
"""
|
||||
)
|
||||
|
||||
#######################################################################
|
||||
# SSL
|
||||
|
@ -6,6 +6,7 @@ import zlib
|
||||
from contextlib import contextmanager
|
||||
from pathlib import Path
|
||||
from typing import Iterable, Union
|
||||
from urllib.parse import urlparse, urlunparse
|
||||
|
||||
import requests
|
||||
from requests.adapters import HTTPAdapter
|
||||
@ -29,7 +30,7 @@ except (ImportError, AttributeError):
|
||||
|
||||
FORM_CONTENT_TYPE = 'application/x-www-form-urlencoded; charset=utf-8'
|
||||
JSON_CONTENT_TYPE = 'application/json'
|
||||
JSON_ACCEPT = f'{JSON_CONTENT_TYPE}, */*'
|
||||
JSON_ACCEPT = f'{JSON_CONTENT_TYPE}, */*;q=0.5'
|
||||
DEFAULT_UA = f'HTTPie/{__version__}'
|
||||
|
||||
|
||||
@ -77,6 +78,11 @@ def collect_messages(
|
||||
|
||||
request = requests.Request(**request_kwargs)
|
||||
prepared_request = requests_session.prepare_request(request)
|
||||
if args.path_as_is:
|
||||
prepared_request.url = ensure_path_as_is(
|
||||
orig_url=args.url,
|
||||
prepped_url=prepared_request.url,
|
||||
)
|
||||
if args.compress and prepared_request.body:
|
||||
compress_body(prepared_request, always=args.compress > 1)
|
||||
response_count = 0
|
||||
@ -278,3 +284,30 @@ def make_request_kwargs(
|
||||
}
|
||||
|
||||
return kwargs
|
||||
|
||||
|
||||
def ensure_path_as_is(orig_url: str, prepped_url: str) -> str:
|
||||
"""
|
||||
Handle `--path-as-is` by replacing the path component of the prepared
|
||||
URL with the path component from the original URL. Other parts stay
|
||||
untouched because other (welcome) processing on the URL might have
|
||||
taken place.
|
||||
|
||||
<https://github.com/jakubroztocil/httpie/issues/895>
|
||||
|
||||
|
||||
<https://ec.haxx.se/http/http-basics#path-as-is>
|
||||
<https://curl.haxx.se/libcurl/c/CURLOPT_PATH_AS_IS.html>
|
||||
|
||||
>>> ensure_path_as_is('http://foo/../', 'http://foo/?foo=bar')
|
||||
'http://foo/../?foo=bar'
|
||||
|
||||
"""
|
||||
parsed_orig, parsed_prepped = urlparse(orig_url), urlparse(prepped_url)
|
||||
final_dict = {
|
||||
# noinspection PyProtectedMember
|
||||
**parsed_prepped._asdict(),
|
||||
'path': parsed_orig.path,
|
||||
}
|
||||
final_url = urlunparse(tuple(final_dict.values()))
|
||||
return final_url
|
||||
|
@ -1,7 +1,6 @@
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from typing import Union, IO, Optional
|
||||
from typing import IO, Optional
|
||||
|
||||
|
||||
try:
|
||||
|
@ -90,7 +90,7 @@ def main(
|
||||
exit_status = ExitStatus.ERROR_TOO_MANY_REDIRECTS
|
||||
env.log_error(
|
||||
f'Too many redirects'
|
||||
f' (--max-redirects=parsed_args.max_redirects).'
|
||||
f' (--max-redirects={parsed_args.max_redirects}).'
|
||||
)
|
||||
except Exception as e:
|
||||
# TODO: Further distinction between expected and unexpected errors.
|
||||
|
@ -196,7 +196,6 @@ class Downloader:
|
||||
"""
|
||||
:param resume: Should the download resume if partial download
|
||||
already exists.
|
||||
:type resume: bool
|
||||
|
||||
:param output_file: The file to store response body in. If not
|
||||
provided, it will be guessed from the response.
|
||||
@ -322,7 +321,6 @@ class Downloader:
|
||||
|
||||
:param chunk: A chunk of response body data that has just
|
||||
been downloaded and written to the output.
|
||||
:type chunk: bytes
|
||||
|
||||
"""
|
||||
self.status.chunk_downloaded(len(chunk))
|
||||
|
37
setup.py
37
setup.py
@ -10,8 +10,11 @@ import httpie
|
||||
|
||||
|
||||
class PyTest(TestCommand):
|
||||
# `$ python setup.py test' simply installs minimal requirements
|
||||
# and runs the tests with no fancy stuff like parallel execution.
|
||||
"""
|
||||
Running `$ python setup.py test' simply installs minimal requirements
|
||||
and runs the tests with no fancy stuff like parallel execution.
|
||||
|
||||
"""
|
||||
def finalize_options(self):
|
||||
TestCommand.finalize_options(self)
|
||||
self.test_args = [
|
||||
@ -26,8 +29,6 @@ class PyTest(TestCommand):
|
||||
|
||||
|
||||
tests_require = [
|
||||
# Pytest needs to come last.
|
||||
# https://bitbucket.org/pypa/setuptools/issue/196/
|
||||
'pytest-httpbin',
|
||||
'pytest',
|
||||
'mock',
|
||||
@ -38,28 +39,24 @@ install_requires = [
|
||||
'requests>=2.22.0',
|
||||
'Pygments>=2.5.2',
|
||||
]
|
||||
|
||||
install_requires_win_only = [
|
||||
'colorama>=0.2.4',
|
||||
]
|
||||
|
||||
# Conditional dependencies:
|
||||
|
||||
# sdist
|
||||
if 'bdist_wheel' not in sys.argv:
|
||||
try:
|
||||
# noinspection PyUnresolvedReferences
|
||||
import argparse
|
||||
except ImportError:
|
||||
install_requires.append('argparse>=1.2.1')
|
||||
|
||||
if 'win32' in str(sys.platform).lower():
|
||||
# Terminal colors for Windows
|
||||
install_requires.append('colorama>=0.2.4')
|
||||
install_requires.extend(install_requires_win_only)
|
||||
|
||||
|
||||
# bdist_wheel
|
||||
extras_require = {
|
||||
# https://wheel.readthedocs.io/en/latest/#defining-conditional-dependencies
|
||||
'python_version == "3.0" or python_version == "3.1"': ['argparse>=1.2.1'],
|
||||
':sys_platform == "win32"': ['colorama>=0.2.4'],
|
||||
':sys_platform == "win32"': install_requires_win_only,
|
||||
}
|
||||
|
||||
|
||||
@ -74,7 +71,7 @@ setup(
|
||||
description=httpie.__doc__.strip(),
|
||||
long_description=long_description(),
|
||||
url='https://httpie.org/',
|
||||
download_url='https://github.com/jakubroztocil/httpie',
|
||||
download_url=f'https://github.com/jakubroztocil/httpie/archive/{httpie.__version__}.tar.gz',
|
||||
author=httpie.__author__,
|
||||
author_email='jakub@roztocil.co',
|
||||
license=httpie.__licence__,
|
||||
@ -85,6 +82,7 @@ setup(
|
||||
'https = httpie.__main__:main',
|
||||
],
|
||||
},
|
||||
python_requires='>=3.6',
|
||||
extras_require=extras_require,
|
||||
install_requires=install_requires,
|
||||
tests_require=tests_require,
|
||||
@ -92,9 +90,7 @@ setup(
|
||||
classifiers=[
|
||||
'Development Status :: 5 - Production/Stable',
|
||||
'Programming Language :: Python',
|
||||
'Programming Language :: Python :: 3.5',
|
||||
'Programming Language :: Python :: 3.6',
|
||||
'Programming Language :: Python :: 3.7',
|
||||
'Programming Language :: Python :: 3 :: Only',
|
||||
'Environment :: Console',
|
||||
'Intended Audience :: Developers',
|
||||
'Intended Audience :: System Administrators',
|
||||
@ -106,4 +102,11 @@ setup(
|
||||
'Topic :: Text Processing',
|
||||
'Topic :: Utilities'
|
||||
],
|
||||
project_urls={
|
||||
'Documentation': 'https://httpie.org/docs',
|
||||
'Source': 'https://github.com/jakubroztocil/httpie',
|
||||
'Online Demo': 'https://httpie.org/run',
|
||||
'Donate': 'https://httpie.org/donate',
|
||||
'Twitter': 'https://twitter.com/clihttp',
|
||||
},
|
||||
)
|
||||
|
@ -22,6 +22,7 @@ def test_default_headers_case_insensitive(httpbin):
|
||||
assert 'Content-Type' not in r
|
||||
|
||||
|
||||
# noinspection PyPep8Naming
|
||||
class TestImplicitHTTPMethod:
|
||||
def test_implicit_GET(self, httpbin):
|
||||
r = http(httpbin.url + '/get')
|
||||
@ -51,9 +52,9 @@ class TestImplicitHTTPMethod:
|
||||
|
||||
class TestAutoContentTypeAndAcceptHeaders:
|
||||
"""
|
||||
Test that Accept and Content-Type correctly defaults to JSON,
|
||||
but can still be overridden. The same with Content-Type when --form
|
||||
-f is used.
|
||||
Test that `Accept` and `Content-Type` correctly default to JSON,
|
||||
but can still be overridden. The same with Content-Type when `--form`
|
||||
`-f` is used.
|
||||
|
||||
"""
|
||||
|
||||
@ -84,7 +85,7 @@ class TestAutoContentTypeAndAcceptHeaders:
|
||||
assert r.json['headers']['Accept'] == JSON_ACCEPT
|
||||
assert r.json['headers']['Content-Type'] == 'application/json'
|
||||
|
||||
def test_POST_explicit_JSON_auto_JSON_accept(self, httpbin):
|
||||
def test_POST_explicit_JSON_JSON_ACCEPT(self, httpbin):
|
||||
r = http('--json', 'POST', httpbin.url + '/post')
|
||||
assert HTTP_OK in r
|
||||
assert r.json['headers']['Accept'] == JSON_ACCEPT
|
||||
|
@ -55,6 +55,25 @@ def test_GET(httpbin_both):
|
||||
assert HTTP_OK in r
|
||||
|
||||
|
||||
def test_path_dot_normalization():
|
||||
r = http(
|
||||
'--offline',
|
||||
'example.org/../../etc/password',
|
||||
'param==value'
|
||||
)
|
||||
assert 'GET /etc/password?param=value' in r
|
||||
|
||||
|
||||
def test_path_as_is():
|
||||
r = http(
|
||||
'--offline',
|
||||
'--path-as-is',
|
||||
'example.org/../../etc/password',
|
||||
'param==value'
|
||||
)
|
||||
assert 'GET /../../etc/password?param=value' in r
|
||||
|
||||
|
||||
def test_DELETE(httpbin_both):
|
||||
r = http('DELETE', httpbin_both + '/delete')
|
||||
assert HTTP_OK in r
|
||||
@ -98,6 +117,27 @@ def test_POST_file(httpbin_both):
|
||||
assert FILE_CONTENT in r
|
||||
|
||||
|
||||
def test_form_POST_file_redirected_stdin(httpbin):
|
||||
"""
|
||||
<https://github.com/jakubroztocil/httpie/issues/840>
|
||||
|
||||
"""
|
||||
with open(FILE_PATH) as f:
|
||||
r = http(
|
||||
'--form',
|
||||
'POST',
|
||||
httpbin + '/post',
|
||||
'file@' + FILE_PATH,
|
||||
tolerate_error_exit_status=True,
|
||||
env=MockEnvironment(
|
||||
stdin=f,
|
||||
stdin_isatty=False,
|
||||
),
|
||||
)
|
||||
assert r.exit_status == ExitStatus.ERROR
|
||||
assert 'cannot be mixed' in r.stderr
|
||||
|
||||
|
||||
def test_headers(httpbin_both):
|
||||
r = http('GET', httpbin_both + '/headers', 'Foo:bar')
|
||||
assert HTTP_OK in r
|
||||
@ -141,3 +181,21 @@ def test_json_input_preserve_order(httpbin_both):
|
||||
assert HTTP_OK in r
|
||||
assert r.json['data'] == \
|
||||
'{"order": {"map": {"1": "first", "2": "second"}}}'
|
||||
|
||||
|
||||
def test_offline():
|
||||
r = http(
|
||||
'--offline',
|
||||
'https://this-should.never-resolve/foo',
|
||||
)
|
||||
assert 'GET /foo' in r
|
||||
|
||||
|
||||
def test_offline_download():
|
||||
"""Absence of response should be handled gracefully with --download"""
|
||||
r = http(
|
||||
'--offline',
|
||||
'--download',
|
||||
'https://this-should.never-resolve/foo',
|
||||
)
|
||||
assert 'GET /foo' in r
|
||||
|
@ -3,6 +3,7 @@ import os
|
||||
import pytest
|
||||
|
||||
from httpie.cli.exceptions import ParseError
|
||||
from httpie.status import ExitStatus
|
||||
from utils import MockEnvironment, http, HTTP_OK
|
||||
from fixtures import FILE_PATH_ARG, FILE_PATH, FILE_CONTENT
|
||||
|
||||
@ -77,4 +78,5 @@ class TestRequestBodyFromFilePath:
|
||||
env=env,
|
||||
tolerate_error_exit_status=True,
|
||||
)
|
||||
assert r.exit_status == ExitStatus.ERROR
|
||||
assert 'cannot be mixed' in r.stderr
|
||||
|
Reference in New Issue
Block a user