11import ssl
2+ from base64 import b64encode
23from typing import List , Mapping , Optional , Sequence , Tuple , Union
34
45from .._exceptions import ProxyError
5- from .._models import URL , Origin , Request , Response , enforce_headers , enforce_url
6+ from .._models import (
7+ URL ,
8+ Origin ,
9+ Request ,
10+ Response ,
11+ enforce_bytes ,
12+ enforce_headers ,
13+ enforce_url ,
14+ )
615from .._ssl import default_ssl_context
716from .._synchronization import AsyncLock
817from .._trace import Trace
@@ -35,6 +44,11 @@ def merge_headers(
3544 return default_headers + override_headers
3645
3746
47+ def build_auth_header (username : bytes , password : bytes ) -> bytes :
48+ userpass = username + b":" + password
49+ return b"Basic " + b64encode (userpass )
50+
51+
3852class AsyncHTTPProxy (AsyncConnectionPool ):
3953 """
4054 A connection pool that sends requests via an HTTP proxy.
@@ -43,6 +57,7 @@ class AsyncHTTPProxy(AsyncConnectionPool):
4357 def __init__ (
4458 self ,
4559 proxy_url : Union [URL , bytes , str ],
60+ proxy_auth : Tuple [Union [bytes , str ], Union [bytes , str ]] = None ,
4661 proxy_headers : Union [HeadersAsMapping , HeadersAsSequence ] = None ,
4762 ssl_context : ssl .SSLContext = None ,
4863 max_connections : Optional [int ] = 10 ,
@@ -61,6 +76,8 @@ def __init__(
6176 Parameters:
6277 proxy_url: The URL to use when connecting to the proxy server.
6378 For example `"http://127.0.0.1:8080/"`.
79+ proxy_auth: Any proxy authentication as a two-tuple of
80+ (username, password). May be either bytes or ascii-only str.
6481 proxy_headers: Any HTTP headers to use for the proxy requests.
6582 For example `{"Proxy-Authorization": "Basic <username>:<password>"}`.
6683 ssl_context: An SSL context to use for verifying connections.
@@ -102,6 +119,13 @@ def __init__(
102119 self ._ssl_context = ssl_context
103120 self ._proxy_url = enforce_url (proxy_url , name = "proxy_url" )
104121 self ._proxy_headers = enforce_headers (proxy_headers , name = "proxy_headers" )
122+ if proxy_auth is not None :
123+ username = enforce_bytes (proxy_auth [0 ], name = "proxy_auth" )
124+ password = enforce_bytes (proxy_auth [1 ], name = "proxy_auth" )
125+ authorization = build_auth_header (username , password )
126+ self ._proxy_headers = [
127+ (b"Proxy-Authorization" , authorization )
128+ ] + self ._proxy_headers
105129
106130 def create_connection (self , origin : Origin ) -> AsyncConnectionInterface :
107131 if origin .scheme == b"http" :
0 commit comments