Skip to content

Commit

Permalink
Merge branch 'master' into content-parameters-on-response
Browse files Browse the repository at this point in the history
  • Loading branch information
j178 authored Sep 3, 2020
2 parents 8e7b8d1 + 19b863a commit 0744e4d
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 35 deletions.
27 changes: 20 additions & 7 deletions httpx/_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import httpcore

from .__version__ import __version__
from ._auth import Auth, BasicAuth, FunctionAuth
from ._config import (
DEFAULT_LIMITS,
Expand All @@ -18,6 +19,7 @@
create_ssl_context,
)
from ._content_streams import ContentStream
from ._decoders import SUPPORTED_DECODERS
from ._exceptions import (
HTTPCORE_EXC_MAP,
InvalidURL,
Expand Down Expand Up @@ -55,6 +57,10 @@
logger = get_logger(__name__)

KEEPALIVE_EXPIRY = 5.0
USER_AGENT = f"python-httpx/{__version__}"
ACCEPT_ENCODING = ", ".join(
[key for key in SUPPORTED_DECODERS.keys() if key != "identity"]
)


class BaseClient:
Expand All @@ -74,7 +80,7 @@ def __init__(

self._auth = self._build_auth(auth)
self._params = QueryParams(params)
self._headers = Headers(headers)
self.headers = Headers(headers)
self._cookies = Cookies(cookies)
self._timeout = Timeout(timeout)
self.max_redirects = max_redirects
Expand Down Expand Up @@ -161,7 +167,16 @@ def headers(self) -> Headers:

@headers.setter
def headers(self, headers: HeaderTypes) -> None:
self._headers = Headers(headers)
client_headers = Headers(
{
b"Accept": b"*/*",
b"Accept-Encoding": ACCEPT_ENCODING.encode("ascii"),
b"Connection": b"keep-alive",
b"User-Agent": USER_AGENT.encode("ascii"),
}
)
client_headers.update(headers)
self._headers = client_headers

@property
def cookies(self) -> Cookies:
Expand Down Expand Up @@ -299,11 +314,9 @@ def _merge_headers(
Merge a headers argument together with any headers on the client,
to create the headers used for the outgoing request.
"""
if headers or self.headers:
merged_headers = Headers(self.headers)
merged_headers.update(headers)
return merged_headers
return headers
merged_headers = Headers(self.headers)
merged_headers.update(headers)
return merged_headers

def _merge_queryparams(
self, params: QueryParamTypes = None
Expand Down
34 changes: 6 additions & 28 deletions httpx/_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,13 +109,11 @@ def userinfo(self) -> str:

@property
def username(self) -> str:
userinfo = self._uri_reference.userinfo or ""
return unquote(userinfo.partition(":")[0])
return unquote(self.userinfo.partition(":")[0])

@property
def password(self) -> str:
userinfo = self._uri_reference.userinfo or ""
return unquote(userinfo.partition(":")[2])
return unquote(self.userinfo.partition(":")[2])

@property
def host(self) -> str:
Expand Down Expand Up @@ -586,12 +584,6 @@ def getlist(self, key: str, split_commas: bool = False) -> typing.List[str]:
return self.get_list(key, split_commas=split_commas)


USER_AGENT = f"python-httpx/{__version__}"
ACCEPT_ENCODING = ", ".join(
[key for key in SUPPORTED_DECODERS.keys() if key != "identity"]
)


class Request:
def __init__(
self,
Expand Down Expand Up @@ -633,26 +625,12 @@ def prepare(self) -> None:
has_content_length = (
"content-length" in self.headers or "transfer-encoding" in self.headers
)
has_user_agent = "user-agent" in self.headers
has_accept = "accept" in self.headers
has_accept_encoding = "accept-encoding" in self.headers
has_connection = "connection" in self.headers

if not has_host:
url = self.url
if url.userinfo:
url = url.copy_with(username=None, password=None)
auto_headers.append((b"host", url.authority.encode("ascii")))

if not has_host and self.url.authority:
host = self.url.copy_with(username=None, password=None).authority
auto_headers.append((b"host", host.encode("ascii")))
if not has_content_length and self.method in ("POST", "PUT", "PATCH"):
auto_headers.append((b"content-length", b"0"))
if not has_user_agent:
auto_headers.append((b"user-agent", USER_AGENT.encode("ascii")))
if not has_accept:
auto_headers.append((b"accept", b"*/*"))
if not has_accept_encoding:
auto_headers.append((b"accept-encoding", ACCEPT_ENCODING.encode()))
if not has_connection:
auto_headers.append((b"connection", b"keep-alive"))

self.headers = Headers(auto_headers + self.headers.raw)

Expand Down
22 changes: 22 additions & 0 deletions tests/client/test_headers.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,28 @@ def test_header_update():
}


def test_remove_default_header():
"""
Remove a default header from the Client.
"""
url = "http://example.org/echo_headers"

client = httpx.Client(transport=MockTransport())
del client.headers["User-Agent"]

response = client.get(url)

assert response.status_code == 200
assert response.json() == {
"headers": {
"accept": "*/*",
"accept-encoding": "gzip, deflate, br",
"connection": "keep-alive",
"host": "example.org",
}
}


def test_header_does_not_exist():
headers = httpx.Headers({"foo": "bar"})
with pytest.raises(KeyError):
Expand Down
12 changes: 12 additions & 0 deletions tests/models/test_requests.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,18 @@ def test_json_encoded_data():
assert request.content == b'{"test": 123}'


def test_headers():
request = httpx.Request("POST", "http://example.org", json={"test": 123})

assert request.headers == httpx.Headers(
{
"Host": "example.org",
"Content-Type": "application/json",
"Content-Length": "13",
}
)


def test_read_and_stream_data():
# Ensure a request may still be streamed if it has been read.
# Needed for cases such as authentication classes that read the request body.
Expand Down

0 comments on commit 0744e4d

Please sign in to comment.