diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 37e3b70a..2c59d9ca 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -9,9 +9,10 @@ This project adheres to `Semantic Versioning `_.
`2.5.0-dev`_ (unreleased)
-------------------------
-* Fixed ``--continue --download`` with a single byte to be downloaded left. (`#1032`_)
* Added ``--raw`` to allow specifying the raw request body without extra processing as
an alternative to ``stdin``. (`#534`_)
+* Fixed ``--continue --download`` with a single byte to be downloaded left. (`#1032`_)
+* Fixed ``--verbose`` HTTP 307 redirects with streamed request body. (`#1088`_)
`2.4.0`_ (2021-02-06)
@@ -477,6 +478,7 @@ This project adheres to `Semantic Versioning `_.
.. _#128: https://github.com/httpie/httpie/issues/128
.. _#201: https://github.com/httpie/httpie/issues/201
.. _#488: https://github.com/httpie/httpie/issues/488
+.. _#534: https://github.com/httpie/httpie/issues/534
.. _#668: https://github.com/httpie/httpie/issues/668
.. _#684: https://github.com/httpie/httpie/issues/684
.. _#718: https://github.com/httpie/httpie/issues/718
@@ -500,3 +502,4 @@ This project adheres to `Semantic Versioning `_.
.. _#1026: https://github.com/httpie/httpie/issues/1026
.. _#1029: https://github.com/httpie/httpie/issues/1029
.. _#1032: https://github.com/httpie/httpie/issues/1032
+.. _#1088: https://github.com/httpie/httpie/issues/1088
diff --git a/README.rst b/README.rst
index c63c3a0b..e0a36e09 100644
--- a/README.rst
+++ b/README.rst
@@ -1071,6 +1071,10 @@ and show the final response instead, use the ``--follow, -F`` option:
$ http --follow pie.dev/redirect/3
+With ``HTTP 307 Temporary Redirect``, the method and the body of the original request
+are reused to perform the redirected request. Otherwise a body-less ``GET`` request is performed.
+
+
Showing intermediary redirect responses
---------------------------------------
diff --git a/tests/fixtures/.editorconfig b/tests/fixtures/.editorconfig
new file mode 100644
index 00000000..60b05522
--- /dev/null
+++ b/tests/fixtures/.editorconfig
@@ -0,0 +1,6 @@
+# https://editorconfig.org
+
+[{*.txt, *.json}]
+trim_trailing_whitespace = false
+insert_final_newline = false
+
diff --git a/tests/fixtures/test.json b/tests/fixtures/test.json
index b5ea8840..fe547ebc 100644
--- a/tests/fixtures/test.json
+++ b/tests/fixtures/test.json
@@ -1,4 +1,4 @@
{
"name": "Jakub Roztočil",
"unicode": "χρυσαφὶ 太陽 เลิศ ♜♞♝♛♚♝♞♜ оживлённым तान्यहानि 有朋"
-}
+}
\ No newline at end of file
diff --git a/tests/fixtures/test.txt b/tests/fixtures/test.txt
index 21857443..7b953309 100644
--- a/tests/fixtures/test.txt
+++ b/tests/fixtures/test.txt
@@ -1 +1 @@
-[one line of UTF8-encoded unicode text] χρυσαφὶ 太陽 เลิศ ♜♞♝♛♚♝♞♜ оживлённым तान्यहानि 有朋 ஸ்றீனிவாஸ ٱلرَّحْمـَبنِ
+[one line of UTF8-encoded unicode text] χρυσαφὶ 太陽 เลิศ ♜♞♝♛♚♝♞♜ оживлённым तान्यहानि 有朋 ஸ்றீனிவாஸ ٱلرَّحْمـَبنِ
\ No newline at end of file
diff --git a/tests/test_redirects.py b/tests/test_redirects.py
index 9f2648cf..1bf15ef6 100644
--- a/tests/test_redirects.py
+++ b/tests/test_redirects.py
@@ -2,8 +2,9 @@
import pytest
from httpie.status import ExitStatus
-from .fixtures import FILE_PATH_ARG
+from .fixtures import FILE_PATH_ARG, FILE_CONTENT
from .utils import http, HTTP_OK
+from .utils.matching import assert_output_matches, Expect, ExpectSequence
def test_follow_all_redirects_shown(httpbin):
@@ -73,4 +74,11 @@ def test_http_307_allow_redirect_post_verbose(httpbin):
'@' + FILE_PATH_ARG)
assert r.count('POST /redirect-to') == 1
assert r.count('POST /post') == 1
+ assert r.count(FILE_CONTENT) == 3 # two requests + final response contain it
assert HTTP_OK in r
+ assert_output_matches(r, [
+ *ExpectSequence.TERMINAL_REQUEST,
+ Expect.RESPONSE_HEADERS,
+ Expect.SEPARATOR,
+ *ExpectSequence.TERMINAL_EXCHANGE,
+ ])
diff --git a/tests/test_tokens.py b/tests/test_tokens.py
index 519b5453..7281b2a3 100644
--- a/tests/test_tokens.py
+++ b/tests/test_tokens.py
@@ -9,45 +9,10 @@ TODO: cover more scenarios
* streamed uploads
"""
-from .utils.matching import assert_output_matches, Expect
+from .utils.matching import assert_output_matches, Expect, ExpectSequence
from .utils import http, HTTP_OK, MockEnvironment
-RAW_REQUEST = [
- Expect.REQUEST_HEADERS,
- Expect.BODY,
-]
-RAW_RESPONSE = [
- Expect.RESPONSE_HEADERS,
- Expect.BODY,
-]
-RAW_EXCHANGE = [
- *RAW_REQUEST,
- Expect.SEPARATOR, # Good choice?
- *RAW_RESPONSE,
-]
-RAW_BODY = [
- Expect.BODY,
-]
-
-TERMINAL_REQUEST = [
- *RAW_REQUEST,
- Expect.SEPARATOR,
-]
-TERMINAL_RESPONSE = [
- *RAW_RESPONSE,
- Expect.SEPARATOR,
-]
-TERMINAL_EXCHANGE = [
- *TERMINAL_REQUEST,
- *TERMINAL_RESPONSE,
-]
-TERMINAL_BODY = [
- RAW_BODY,
- Expect.SEPARATOR
-]
-
-
def test_headers():
r = http('--print=H', '--offline', 'pie.dev')
assert_output_matches(r, [Expect.REQUEST_HEADERS])
@@ -60,17 +25,17 @@ def test_redirected_headers():
def test_terminal_headers_and_body():
r = http('--print=HB', '--offline', 'pie.dev', 'AAA=BBB')
- assert_output_matches(r, TERMINAL_REQUEST)
+ assert_output_matches(r, ExpectSequence.TERMINAL_REQUEST)
def test_terminal_request_headers_response_body(httpbin):
r = http('--print=Hb', httpbin + '/get')
- assert_output_matches(r, TERMINAL_REQUEST)
+ assert_output_matches(r, ExpectSequence.TERMINAL_REQUEST)
def test_raw_request_headers_response_body(httpbin):
r = http('--print=Hb', httpbin + '/get', env=MockEnvironment(stdout_isatty=False))
- assert_output_matches(r, RAW_REQUEST)
+ assert_output_matches(r, ExpectSequence.RAW_REQUEST)
def test_terminal_request_headers_response_headers(httpbin):
@@ -93,29 +58,29 @@ def test_raw_headers_and_body():
'--print=HB', '--offline', 'pie.dev', 'AAA=BBB',
env=MockEnvironment(stdout_isatty=False),
)
- assert_output_matches(r, RAW_REQUEST)
+ assert_output_matches(r, ExpectSequence.RAW_REQUEST)
def test_raw_body():
r = http('--print=B', '--offline', 'pie.dev', 'AAA=BBB', env=MockEnvironment(stdout_isatty=False))
- assert_output_matches(r, RAW_BODY)
+ assert_output_matches(r, ExpectSequence.RAW_BODY)
def test_raw_exchange(httpbin):
r = http('--verbose', httpbin + '/post', 'a=b', env=MockEnvironment(stdout_isatty=False))
assert HTTP_OK in r
- assert_output_matches(r, RAW_EXCHANGE)
+ assert_output_matches(r, ExpectSequence.RAW_EXCHANGE)
def test_terminal_exchange(httpbin):
r = http('--verbose', httpbin + '/post', 'a=b')
assert HTTP_OK in r
- assert_output_matches(r, TERMINAL_EXCHANGE)
+ assert_output_matches(r, ExpectSequence.TERMINAL_EXCHANGE)
def test_headers_multipart_body_separator():
r = http('--print=HB', '--multipart', '--offline', 'pie.dev', 'AAA=BBB')
- assert_output_matches(r, TERMINAL_REQUEST)
+ assert_output_matches(r, ExpectSequence.TERMINAL_REQUEST)
def test_redirected_headers_multipart_no_separator():
@@ -123,16 +88,16 @@ def test_redirected_headers_multipart_no_separator():
'--print=HB', '--multipart', '--offline', 'pie.dev', 'AAA=BBB',
env=MockEnvironment(stdout_isatty=False),
)
- assert_output_matches(r, RAW_REQUEST)
+ assert_output_matches(r, ExpectSequence.RAW_REQUEST)
def test_verbose_chunked(httpbin_with_chunked_support):
r = http('--verbose', '--chunked', httpbin_with_chunked_support + '/post', 'hello=world')
assert HTTP_OK in r
assert 'Transfer-Encoding: chunked' in r
- assert_output_matches(r, TERMINAL_EXCHANGE)
+ assert_output_matches(r, ExpectSequence.TERMINAL_EXCHANGE)
def test_request_headers_response_body(httpbin):
r = http('--print=Hb', httpbin + '/get')
- assert_output_matches(r, TERMINAL_REQUEST)
+ assert_output_matches(r, ExpectSequence.TERMINAL_REQUEST)
diff --git a/tests/utils/matching/__init__.py b/tests/utils/matching/__init__.py
index 216f65d4..78720728 100644
--- a/tests/utils/matching/__init__.py
+++ b/tests/utils/matching/__init__.py
@@ -1,14 +1,20 @@
+"""
+Utilities for testing output composition.
+
+"""
from typing import Iterable
import pytest
-from .parsing import OutputMatchingError, expect_tokens, Expect
+from .parsing import OutputMatchingError, expect_tokens
+from .tokens import Expect, ExpectSequence
__all__ = [
'assert_output_matches',
'assert_output_does_not_match',
'Expect',
+ 'ExpectSequence',
]
diff --git a/tests/utils/matching/parsing.py b/tests/utils/matching/parsing.py
index 53a4b21b..998fe9a4 100644
--- a/tests/utils/matching/parsing.py
+++ b/tests/utils/matching/parsing.py
@@ -1,22 +1,11 @@
import re
from typing import Iterable
-from enum import Enum, auto
from httpie.output.writer import MESSAGE_SEPARATOR
+from .tokens import Expect
from ...utils import CRLF
-class Expect(Enum):
- """
- Predefined token types we can expect in the output.
-
- """
- REQUEST_HEADERS = auto()
- RESPONSE_HEADERS = auto()
- BODY = auto()
- SEPARATOR = auto()
-
-
SEPARATOR_RE = re.compile(f'^{MESSAGE_SEPARATOR}')
diff --git a/tests/utils/matching/tokens.py b/tests/utils/matching/tokens.py
new file mode 100644
index 00000000..61bc7234
--- /dev/null
+++ b/tests/utils/matching/tokens.py
@@ -0,0 +1,51 @@
+from enum import Enum, auto
+
+
+class Expect(Enum):
+ """
+ Predefined token types we can expect in the output.
+
+ """
+ REQUEST_HEADERS = auto()
+ RESPONSE_HEADERS = auto()
+ BODY = auto()
+ SEPARATOR = auto()
+
+
+class ExpectSequence:
+ """
+ Standard combined chunks. These predefined requests and responses assume a body.
+
+ """
+ RAW_REQUEST = [
+ Expect.REQUEST_HEADERS,
+ Expect.BODY,
+ ]
+ RAW_RESPONSE = [
+ Expect.RESPONSE_HEADERS,
+ Expect.BODY,
+ ]
+ RAW_EXCHANGE = [
+ *RAW_REQUEST,
+ Expect.SEPARATOR, # Good choice?
+ *RAW_RESPONSE,
+ ]
+ RAW_BODY = [
+ Expect.BODY,
+ ]
+ TERMINAL_REQUEST = [
+ *RAW_REQUEST,
+ Expect.SEPARATOR,
+ ]
+ TERMINAL_RESPONSE = [
+ *RAW_RESPONSE,
+ Expect.SEPARATOR,
+ ]
+ TERMINAL_EXCHANGE = [
+ *TERMINAL_REQUEST,
+ *TERMINAL_RESPONSE,
+ ]
+ TERMINAL_BODY = [
+ RAW_BODY,
+ Expect.SEPARATOR
+ ]