Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions httpx/_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -497,9 +497,8 @@ def _redirect_headers(self, request: Request, url: URL, method: str) -> Headers:
# the origin.
headers.pop("Authorization", None)

# Remove the Host header, so that a new one will be auto-populated on
# the request instance.
headers.pop("Host", None)
# Update the Host header.
headers["Host"] = url.netloc.decode("ascii")

if method != request.method and method == "GET":
# If we've switch to a 'GET' request, then strip any headers which
Expand Down
39 changes: 19 additions & 20 deletions httpx/_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -1089,29 +1089,28 @@ def __init__(
if cookies:
Cookies(cookies).set_cookie_header(self)

if stream is not None:
if stream is None:
headers, stream = encode_request(content, data, files, json)
self._prepare(headers)
self.stream = stream
# Load the request body, except for streaming content.
if isinstance(stream, ByteStream):
self.read()
else:
# There's an important distinction between `Request(content=...)`,
# and `Request(stream=...)`.
#
# Using `content=...` implies automatically populated content headers,
# of either `Content-Length: ...` or `Transfer-Encoding: chunked`.
# Using `content=...` implies automatically populated `Host` and content
# headers, of either `Content-Length: ...` or `Transfer-Encoding: chunked`.
#
# Using `stream=...` will not automatically include any content headers.
# Using `stream=...` will not automatically include *any* auto-populated headers.
#
# As an end-user you don't really need `stream=...`. It's only
# useful when:
#
# * Preserving the request stream when copying requests, eg for redirects.
# * Creating request instances on the *server-side* of the transport API.
self.stream = stream
self._prepare({})
else:
headers, stream = encode_request(content, data, files, json)
self._prepare(headers)
self.stream = stream
# Load the request body, except for streaming content.
if isinstance(stream, ByteStream):
self.read()

def _prepare(self, default_headers: typing.Dict[str, str]) -> None:
for key, value in default_headers.items():
Expand Down Expand Up @@ -1216,7 +1215,14 @@ def __init__(
self.is_closed = False
self.is_stream_consumed = False

if stream is not None:
if stream is None:
headers, stream = encode_response(content, text, html, json)
self._prepare(headers)
self.stream = stream
if isinstance(stream, ByteStream):
# Load the response body, except for streaming content.
self.read()
else:
# There's an important distinction between `Response(content=...)`,
# and `Response(stream=...)`.
#
Expand All @@ -1229,13 +1235,6 @@ def __init__(
# useful when creating response instances having received a stream
# from the transport API.
self.stream = stream
else:
headers, stream = encode_response(content, text, html, json)
self._prepare(headers)
self.stream = stream
if isinstance(stream, ByteStream):
# Load the response body, except for streaming content.
self.read()

self._num_bytes_downloaded = 0

Expand Down