]> git.ipfire.org Git - thirdparty/httpx.git/commitdiff
Cache netrc authentication per-client (#400)
authorCan Sarıgöl <cansarigol@derinbilgi.com.tr>
Wed, 16 Oct 2019 13:31:47 +0000 (16:31 +0300)
committerSeth Michael Larson <sethmichaellarson@gmail.com>
Wed, 16 Oct 2019 13:31:47 +0000 (08:31 -0500)
docs/advanced.md
httpx/client.py
httpx/utils.py
tests/test_utils.py

index 88195e67a8f4bbb7a75ced786458f147e2ef66df..368682fec73eb18b712c63a55e20e29451d75b8f 100644 (file)
@@ -91,6 +91,11 @@ h2_response = h2_client.get("https://myserver.com")
 HTTPX supports .netrc file. In `trust_env=True` cases, if auth parameter is
 not defined, HTTPX tries to add auth into request's header from .netrc file.
 
+!!! note
+    The NETRC file is cached across requests made by a client.
+    If you need to refresh the cache (e.g. because the NETRC file has changed),
+    you should create a new client or restart the interpreter.
+
 As default `trust_env` is true. To set false:
 ```python
 >>> httpx.get('https://example.org/', trust_env=False)
index bfee2de5b4df7047ef4455f1dd85d2b11c402c8b..bdf00d4a6ebee0935478aa81fe049523e3bbc0e6 100644 (file)
@@ -1,5 +1,6 @@
 import functools
 import inspect
+import netrc
 import typing
 from types import TracebackType
 
@@ -48,7 +49,7 @@ from .models import (
     ResponseContent,
     URLTypes,
 )
-from .utils import ElapsedTimer, get_environment_proxies, get_netrc_login
+from .utils import ElapsedTimer, get_environment_proxies, get_netrc
 
 
 class BaseClient:
@@ -277,13 +278,20 @@ class BaseClient:
             )
 
         if trust_env:
-            netrc_login = get_netrc_login(request.url.authority)
-            if netrc_login:
-                username, _, password = netrc_login
-                return BasicAuthMiddleware(username=username, password=password)
+            netrc_info = self._get_netrc()
+            if netrc_info:
+                netrc_login = netrc_info.authenticators(request.url.authority)
+                if netrc_login:
+                    username, _, password = netrc_login
+                    assert password is not None
+                    return BasicAuthMiddleware(username=username, password=password)
 
         return None
 
+    @functools.lru_cache(1)
+    def _get_netrc(self) -> typing.Optional[netrc.netrc]:
+        return get_netrc()
+
     def _dispatcher_for_request(
         self, request: AsyncRequest, proxies: typing.Dict[str, AsyncDispatcher]
     ) -> AsyncDispatcher:
index c16341c5f96e1ba9b834efe2612d09193ebdb920..a3aff3581c585154ee4e0f1d9ac25ce587fb09a9 100644 (file)
@@ -98,7 +98,7 @@ def guess_json_utf(data: bytes) -> typing.Optional[str]:
 NETRC_STATIC_FILES = (Path("~/.netrc"), Path("~/_netrc"))
 
 
-def get_netrc_login(host: str) -> typing.Optional[typing.Tuple[str, str, str]]:
+def get_netrc() -> typing.Optional[netrc.netrc]:
     NETRC_FILES = (Path(os.getenv("NETRC", "")),) + NETRC_STATIC_FILES
     netrc_path = None
 
@@ -110,9 +110,7 @@ def get_netrc_login(host: str) -> typing.Optional[typing.Tuple[str, str, str]]:
 
     if netrc_path is None:
         return None
-
-    netrc_info = netrc.netrc(str(netrc_path))
-    return netrc_info.authenticators(host)  # type: ignore
+    return netrc.netrc(str(netrc_path))
 
 
 def get_ca_bundle_from_env() -> typing.Optional[str]:
index 800928c993a7faa12ed62ffe30a3628eb67fdd96..f8295b2911f55aae0c694ac87bfd1443d644a36b 100644 (file)
@@ -10,7 +10,7 @@ from httpx.utils import (
     ElapsedTimer,
     get_ca_bundle_from_env,
     get_environment_proxies,
-    get_netrc_login,
+    get_netrc,
     guess_json_utf,
     obfuscate_sensitive_headers,
     parse_header_links,
@@ -54,24 +54,24 @@ def test_guess_by_bom(encoding, expected):
 
 
 def test_bad_get_netrc_login():
-    assert get_netrc_login("url") is None
-
     os.environ["NETRC"] = "tests/.netrc"
-    assert get_netrc_login("url") is None
-
-    os.environ["NETRC"] = "wrongpath"
-    assert get_netrc_login("url") is None
+    assert str(get_netrc()) is not None
 
     from httpx import utils
 
     utils.NETRC_STATIC_FILES = ()
+
+    os.environ["NETRC"] = "wrongpath"
+    assert utils.get_netrc() is None
+
     os.environ["NETRC"] = ""
-    assert utils.get_netrc_login("url") is None
+    assert utils.get_netrc() is None
 
 
 def test_get_netrc_login():
     os.environ["NETRC"] = "tests/.netrc"
-    assert get_netrc_login("netrcexample.org") == (
+    netrc = get_netrc()
+    assert netrc.authenticators("netrcexample.org") == (
         "example-username",
         None,
         "example-password",