Issue 1:
While all other protocols are working, I can't access an URL using an HTTPS-proxy (StackOverflow)

Expected Result

Open an HTTPS-URL using HTTPS-proxy.

Actual Result

[Errno 111] Connection refused

---------------------------------------------------------------------------
ConnectionRefusedError Traceback (most recent call last)
[/usr/local/lib/python3.7/dist-packages/urllib3/connection.py](https://localhost:8080/#) in _new_conn(self)
158 conn = connection.create_connection(
--> 159 (self._dns_host, self.port), self.timeout, **extra_kw)
160

14 frames
[/usr/local/lib/python3.7/dist-packages/urllib3/util/connection.py](https://localhost:8080/#) in create_connection(address, timeout, source_address, socket_options)
79 if err is not None:
---> 80 raise err
81

[/usr/local/lib/python3.7/dist-packages/urllib3/util/connection.py](https://localhost:8080/#) in create_connection(address, timeout, source_address, socket_options)
69 sock.bind(source_address)
---> 70 sock.connect(sa)
71 return sock

ConnectionRefusedError: [Errno 111] Connection refused

During handling of the above exception, another exception occurred:

NewConnectionError Traceback (most recent call last)
[/usr/local/lib/python3.7/dist-packages/urllib3/connectionpool.py](https://localhost:8080/#) in urlopen(self, method, url, body, headers, retries, redirect, assert_same_host, timeout, pool_timeout, release_conn, chunked, body_pos, **response_kw)
593 if is_new_proxy_conn:
--> 594 self._prepare_proxy(conn)
595

[/usr/local/lib/python3.7/dist-packages/urllib3/connectionpool.py](https://localhost:8080/#) in _prepare_proxy(self, conn)
804 conn.set_tunnel(self._proxy_host, self.port, self.proxy_headers)
--> 805 conn.connect()
806

[/usr/local/lib/python3.7/dist-packages/urllib3/connection.py](https://localhost:8080/#) in connect(self)
300 # Add certificate verification
--> 301 conn = self._new_conn()
302 hostname = self.host

[/usr/local/lib/python3.7/dist-packages/urllib3/connection.py](https://localhost:8080/#) in _new_conn(self)
167 raise NewConnectionError(
--> 168 self, "Failed to establish a new connection: %s" % e)
169

NewConnectionError: <urllib3.connection.VerifiedHTTPSConnection object at 0x7fc4f55256d0>: Failed to establish a new connection: [Errno 111] Connection refused

During handling of the above exception, another exception occurred:

MaxRetryError Traceback (most recent call last)
[/usr/local/lib/python3.7/dist-packages/requests/adapters.py](https://localhost:8080/#) in send(self, request, stream, timeout, verify, cert, proxies)
449 retries=self.max_retries,
--> 450 timeout=timeout
451 )

[/usr/local/lib/python3.7/dist-packages/urllib3/connectionpool.py](https://localhost:8080/#) in urlopen(self, method, url, body, headers, retries, redirect, assert_same_host, timeout, pool_timeout, release_conn, chunked, body_pos, **response_kw)
637 retries = retries.increment(method, url, error=e, _pool=self,
--> 638 _stacktrace=sys.exc_info()[2])
639 retries.sleep()

[/usr/local/lib/python3.7/dist-packages/urllib3/util/retry.py](https://localhost:8080/#) in increment(self, method, url, response, error, _pool, _stacktrace)
398 if new_retry.is_exhausted():
--> 399 raise MaxRetryError(_pool, url, error or ResponseError(cause))
400

MaxRetryError: HTTPSConnectionPool(host='google.com', port=443): Max retries exceeded with url: / (Caused by ProxyError('Cannot connect to proxy.', NewConnectionError('<urllib3.connection.VerifiedHTTPSConnection object at 0x7fc4f55256d0>: Failed to establish a new connection: [Errno 111] Connection refused')))

During handling of the above exception, another exception occurred:

ProxyError Traceback (most recent call last)
[<ipython-input-5-0042a445fda6>](https://localhost:8080/#) in <module>()
5 print(proxy_url)
6
----> 7 r = requests.get('https://google.com/', proxies = {protocol: proxy_url})
8 r.status_code

[/usr/local/lib/python3.7/dist-packages/requests/api.py](https://localhost:8080/#) in get(url, params, **kwargs)
73 """
74
---> 75 return request('get', url, params=params, **kwargs)
76
77

[/usr/local/lib/python3.7/dist-packages/requests/api.py](https://localhost:8080/#) in request(method, url, **kwargs)
59 # cases, and look like a memory leak in others.
60 with sessions.Session() as session:
---> 61 return session.request(method=method, url=url, **kwargs)
62
63

[/usr/local/lib/python3.7/dist-packages/requests/sessions.py](https://localhost:8080/#) in request(self, method, url, params, data, headers, cookies, files, auth, timeout, allow_redirects, proxies, hooks, stream, verify, cert, json)
527 }
528 send_kwargs.update(settings)
--> 529 resp = self.send(prep, **send_kwargs)
530
531 return resp

[/usr/local/lib/python3.7/dist-packages/requests/sessions.py](https://localhost:8080/#) in send(self, request, **kwargs)
643
644 # Send the request
--> 645 r = adapter.send(request, **kwargs)
646
647 # Total elapsed time of the request (approximately)

[/usr/local/lib/python3.7/dist-packages/requests/adapters.py](https://localhost:8080/#) in send(self, request, stream, timeout, verify, cert, proxies)
511
512 if isinstance(e.reason, _ProxyError):
--> 513 raise ProxyError(e, request=request)
514
515 if isinstance(e.reason, _SSLError):

ProxyError: HTTPSConnectionPool(host='google.com', port=443): Max retries exceeded with url: / (Caused by ProxyError('Cannot connect to proxy.', NewConnectionError('<urllib3.connection.VerifiedHTTPSConnection object at 0x7fc4f55256d0>: Failed to establish a new connection: [Errno 111] Connection refused')))

Reproduction Steps

Here is also a google colab that reproduces this issue.

import requests
import random

PROXY_LIST_URL = 'https://proxylist.geonode.com/api/proxy-list?limit=50&page=1&sort_by=lastChecked&sort_type=desc&protocols=https'

proxies = requests.get(PROXY_LIST_URL).json()['data']

proxy = random.choice(proxies)

protocol = proxy['protocols'][0]
proxy_url = f"{protocol}://{proxy['ip']}:{proxy['port']}"
print(proxy_url)

r = requests.get('https://google.com', proxies = {protocol: proxy_url})
print(r.status_code)

System Information

$ python -m requests.help

{
"chardet": {
"version": "3.0.4"
},
"charset_normalizer": {
"version": "2.0.12"
},
"cryptography": {
"version": ""
},
"idna": {
"version": "2.10"
},
"implementation": {
"name": "CPython",
"version": "3.7.12"
},
"platform": {
"release": "5.4.144+",
"system": "Linux"
},
"pyOpenSSL": {
"openssl_version": "",
"version": null
},
"requests": {
"version": "2.27.1"
},
"system_ssl": {
"version": "1010100f"
},
"urllib3": {
"version": "1.24.3"
},
"using_charset_normalizer": false,
"using_pyopenssl": false
}

Issue 2:
foyoux/aligo#55

from dataclasses import dataclass

import requests

@dataclass
class ShareToken(str):
"""
>>> assert isinstance(ShareToken('xxx'), str)
"""
share_token: str = None
expire_time: str = None
expires_in: int = None

def __new__(cls, *args, **kwargs):
share_token = kwargs.get('share_token')
if share_token is None:
share_token = args[0]
return super().__new__(cls, share_token)

def __str__(self):
return self.share_token

def main():
share_token = ShareToken('xxx')
resp = requests.get('https://github.com/', headers={
# Why am I doing this?
# Because the share_token has a short validity period,
# but the program may need it for a long time,
# the object used is convenient for updating in place when it fails.
# Maybe I didn't express clearly,
# but as far as my own application scenario is concerned,
# this is the best way. Of course, these are not the point,
# the point is that I think headers should allow subclasses of str or bytes. thanks
'x-share-token': share_token
})
print(resp.status_code)

if __name__ == '__main__':
main()

Expected Result

The operation is successful, no error is reported, and 200 is printed out.

Actual Result

It is OK under requests==2.27.1, but the latest 2.28.0 & 2.28.1 reports an error "requests.exceptions.InvalidHeader: Header part (...."

Traceback (most recent call last):
File "/home/foyou/Desktop/projects/foyoux/aligo/main.py", line 42, in <module>
main()
File "/home/foyou/Desktop/projects/foyoux/aligo/main.py", line 27, in main
resp = requests.get('https://github.com/', headers={
File "/home/foyou/Desktop/projects/foyoux/aligo/venv/lib/python3.10/site-packages/requests/api.py", line 73, in get
return request("get", url, params=params, **kwargs)
File "/home/foyou/Desktop/projects/foyoux/aligo/venv/lib/python3.10/site-packages/requests/api.py", line 59, in request
return session.request(method=method, url=url, **kwargs)
File "/home/foyou/Desktop/projects/foyoux/aligo/venv/lib/python3.10/site-packages/requests/sessions.py", line 573, in request
prep = self.prepare_request(req)
File "/home/foyou/Desktop/projects/foyoux/aligo/venv/lib/python3.10/site-packages/requests/sessions.py", line 484, in prepare_request
p.prepare(
File "/home/foyou/Desktop/projects/foyoux/aligo/venv/lib/python3.10/site-packages/requests/models.py", line 369, in prepare
self.prepare_headers(headers)
File "/home/foyou/Desktop/projects/foyoux/aligo/venv/lib/python3.10/site-packages/requests/models.py", line 491, in prepare_headers
check_header_validity(header)
File "/home/foyou/Desktop/projects/foyoux/aligo/venv/lib/python3.10/site-packages/requests/utils.py", line 1037, in check_header_validity
raise InvalidHeader(
requests.exceptions.InvalidHeader: Header part (ShareToken(share_token='xxx', expire_time=None, expires_in=None)) from {'x-share-token': ShareToken(share_token='xxx', expire_time=None, expires_in=None)} must be of type str or bytes, not <class '__main__.ShareToken'>

Reproduction Steps

run this code

from dataclasses import dataclass

import requests

@dataclass
class ShareToken(str):
"""
>>> assert isinstance(ShareToken('xxx'), str)
"""
share_token: str = None
expire_time: str = None
expires_in: int = None

def __new__(cls, *args, **kwargs):
share_token = kwargs.get('share_token')
if share_token is None:
share_token = args[0]
return super().__new__(cls, share_token)

def __str__(self):
return self.share_token

def main():
share_token = ShareToken('xxx')
resp = requests.get('https://github.com/', headers={
# Why am I doing this?
# Because the share_token has a short validity period,
# but the program may need it for a long time,
# the object used is convenient for updating in place when it fails.
# Maybe I didn't express clearly,
# but as far as my own application scenario is concerned,
# this is the best way. Of course, these are not the point,
# the point is that I think headers should allow subclasses of str or bytes. thanks
'x-share-token': share_token
})
print(resp.status_code)

if __name__ == '__main__':
main()

System Information

$ python -m requests.help

{
"chardet": {
"version": null
},
"charset_normalizer": {
"version": "2.0.12"
},
"cryptography": {
"version": ""
},
"idna": {
"version": "3.3"
},
"implementation": {
"name": "CPython",
"version": "3.10.5"
},
"platform": {
"release": "5.14.0-1051-oem",
"system": "Linux"
},
"pyOpenSSL": {
"openssl_version": "",
"version": null
},
"requests": {
"version": "2.28.1"
},
"system_ssl": {
"version": "1010106f"
},
"urllib3": {
"version": "1.26.12"
},
"using_charset_normalizer": true,
"using_pyopenssl": false
}