Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pip 20.3+ break proxy connection #9216

Closed
lex-pec opened this issue Dec 3, 2020 · 24 comments
Closed

Pip 20.3+ break proxy connection #9216

lex-pec opened this issue Dec 3, 2020 · 24 comments
Labels
C: error messages Improving error messages C: network connectivity C: proxy Dealing with proxies and networking project: vendored dependency Related to a vendored dependency

Comments

@lex-pec
Copy link

lex-pec commented Dec 3, 2020

Environment

  • pip version: 20.2.3
  • Python version: 3.9
  • OS: Win10 64-bit

Description
When I'm trying to update pip using py -m pip install --upgrade pip a 'ProxySchemeUnknown' error occurs with a plenty of other 'File' errors.

When I was looking for the solution to this problem, I found very similar issues, but they're not the same:
#6555; psf/requests#5297

I think the problem is with my internet provider. I am sharing the internet with my laptop through a portable hotspot in my smartphone. Also, I changed TTL on the laptop.

Expected behavior
pip is updated.

How to Reproduce

  1. Open Windows' CommandPrompt.
  2. Run py -m pip install --upgrade pip.
  3. An error occurs.

Output

C:\Users\User>py -m pip install --upgrade pip
Defaulting to user installation because normal site-packages is not writeable
ERROR: Exception:
Traceback (most recent call last):
  File "C:\Program Files\Python39\lib\site-packages\pip\_internal\cli\base_command.py", line 228, in _main
    status = self.run(options, args)
  File "C:\Program Files\Python39\lib\site-packages\pip\_internal\cli\req_command.py", line 182, in wrapper
    return func(self, options, args)
  File "C:\Program Files\Python39\lib\site-packages\pip\_internal\commands\install.py", line 323, in run
    requirement_set = resolver.resolve(
  File "C:\Program Files\Python39\lib\site-packages\pip\_internal\resolution\legacy\resolver.py", line 183, in resolve
    discovered_reqs.extend(self._resolve_one(requirement_set, req))
  File "C:\Program Files\Python39\lib\site-packages\pip\_internal\resolution\legacy\resolver.py", line 388, in _resolve_one
    abstract_dist = self._get_abstract_dist_for(req_to_install)
  File "C:\Program Files\Python39\lib\site-packages\pip\_internal\resolution\legacy\resolver.py", line 331, in _get_abstract_dist_for
    skip_reason = self._check_skip_installed(req)
  File "C:\Program Files\Python39\lib\site-packages\pip\_internal\resolution\legacy\resolver.py", line 254, in _check_skip_installed
    self.finder.find_requirement(req_to_install, upgrade=True)
  File "C:\Program Files\Python39\lib\site-packages\pip\_internal\index\package_finder.py", line 898, in find_requirement
    best_candidate_result = self.find_best_candidate(
  File "C:\Program Files\Python39\lib\site-packages\pip\_internal\index\package_finder.py", line 881, in find_best_candidate
    candidates = self.find_all_candidates(project_name)
  File "C:\Program Files\Python39\lib\site-packages\pip\_internal\index\package_finder.py", line 825, in find_all_candidates
    package_links = self.process_project_url(
  File "C:\Program Files\Python39\lib\site-packages\pip\_internal\index\package_finder.py", line 790, in process_project_url
    html_page = self._link_collector.fetch_page(project_url)
  File "C:\Program Files\Python39\lib\site-packages\pip\_internal\index\collector.py", line 643, in fetch_page
    return _get_html_page(location, session=self.session)
  File "C:\Program Files\Python39\lib\site-packages\pip\_internal\index\collector.py", line 455, in _get_html_page
    resp = _get_html_response(url, session=session)
  File "C:\Program Files\Python39\lib\site-packages\pip\_internal\index\collector.py", line 152, in _get_html_response
    resp = session.get(
  File "C:\Program Files\Python39\lib\site-packages\pip\_vendor\requests\sessions.py", line 543, in get
    return self.request('GET', url, **kwargs)
  File "C:\Program Files\Python39\lib\site-packages\pip\_internal\network\session.py", line 421, in request
    return super(PipSession, self).request(method, url, *args, **kwargs)
  File "C:\Program Files\Python39\lib\site-packages\pip\_vendor\requests\sessions.py", line 530, in request
    resp = self.send(prep, **send_kwargs)
  File "C:\Program Files\Python39\lib\site-packages\pip\_vendor\requests\sessions.py", line 643, in send
    r = adapter.send(request, **kwargs)
  File "C:\Program Files\Python39\lib\site-packages\pip\_vendor\cachecontrol\adapter.py", line 53, in send
    resp = super(CacheControlAdapter, self).send(request, **kw)
  File "C:\Program Files\Python39\lib\site-packages\pip\_vendor\requests\adapters.py", line 412, in send
    conn = self.get_connection(request.url, proxies)
  File "C:\Program Files\Python39\lib\site-packages\pip\_vendor\requests\adapters.py", line 309, in get_connection
    proxy_manager = self.proxy_manager_for(proxy)
  File "C:\Program Files\Python39\lib\site-packages\pip\_vendor\requests\adapters.py", line 193, in proxy_manager_for
    manager = self.proxy_manager[proxy] = proxy_from_url(
  File "C:\Program Files\Python39\lib\site-packages\pip\_vendor\urllib3\poolmanager.py", line 492, in proxy_from_url
    return ProxyManager(proxy_url=url, **kw)
  File "C:\Program Files\Python39\lib\site-packages\pip\_vendor\urllib3\poolmanager.py", line 429, in __init__
    raise ProxySchemeUnknown(proxy.scheme)
pip._vendor.urllib3.exceptions.ProxySchemeUnknown: Not supported proxy scheme None
WARNING: You are using pip version 20.2.3; however, version 20.3.1 is available.
You should consider upgrading via the 'C:\Program Files\Python39\python.exe -m pip install --upgrade pip' command.
@brainwane brainwane added the state: needs eyes Needs a maintainer/triager to take a closer look label Dec 3, 2020
@brainwane
Copy link
Contributor

I'll defer to other people in responding to the substance of your issue, but: congratulations on filing your first GitHub issue! And thanks for the detailed report!

@jw120
Copy link

jw120 commented Dec 4, 2020

I resolved the same problem by changing my https_proxy environement variable from : to https://:

Perhaps urllib got stricter

@uranusjr
Copy link
Member

uranusjr commented Dec 4, 2020

Combined with #9190, it indeed seems like urllib3 made changes to the proxy code that broke some stuff in pip.

@lex-pec
Copy link
Author

lex-pec commented Dec 4, 2020

UPD: I don't know why, but now I have a different problem, but it's also related to the connection. When I am trying to update pip or to install a package, I have another error:

(base) C:\Users\User>pip install --upgrade pip
Collecting pip
  WARNING: Retrying (Retry(total=4, connect=None, read=None, redirect=None, status=None)) after connection broken by 'ProtocolError('Connection aborted.', ConnectionResetError(10054, 'An existing connection was forcibly closed by the remote host', None, 10054, None))': /packages/ab/11/2dc62c5263d9eb322f2f028f7b56cd9d096bb8988fcf82d65fa2e4057afe/pip-20.3.1-py2.py3-none-any.whl
  WARNING: Retrying (Retry(total=3, connect=None, read=None, redirect=None, status=None)) after connection broken by 'ProtocolError('Connection aborted.', ConnectionResetError(10054, 'An existing connection was forcibly closed by the remote host', None, 10054, None))': /packages/ab/11/2dc62c5263d9eb322f2f028f7b56cd9d096bb8988fcf82d65fa2e4057afe/pip-20.3.1-py2.py3-none-any.whl
  WARNING: Retrying (Retry(total=2, connect=None, read=None, redirect=None, status=None)) after connection broken by 'ProtocolError('Connection aborted.', ConnectionResetError(10054, 'An existing connection was forcibly closed by the remote host', None, 10054, None))': /packages/ab/11/2dc62c5263d9eb322f2f028f7b56cd9d096bb8988fcf82d65fa2e4057afe/pip-20.3.1-py2.py3-none-any.whl
  WARNING: Retrying (Retry(total=1, connect=None, read=None, redirect=None, status=None)) after connection broken by 'ProtocolError('Connection aborted.', ConnectionResetError(10054, 'An existing connection was forcibly closed by the remote host', None, 10054, None))': /packages/ab/11/2dc62c5263d9eb322f2f028f7b56cd9d096bb8988fcf82d65fa2e4057afe/pip-20.3.1-py2.py3-none-any.whl
  WARNING: Retrying (Retry(total=0, connect=None, read=None, redirect=None, status=None)) after connection broken by 'ProtocolError('Connection aborted.', ConnectionResetError(10054, 'An existing connection was forcibly closed by the remote host', None, 10054, None))': /packages/ab/11/2dc62c5263d9eb322f2f028f7b56cd9d096bb8988fcf82d65fa2e4057afe/pip-20.3.1-py2.py3-none-any.whl
ERROR: Could not install packages due to an EnvironmentError: HTTPSConnectionPool(host='files.pythonhosted.org', port=443): Max retries exceeded with url: /packages/ab/11/2dc62c5263d9eb322f2f028f7b56cd9d096bb8988fcf82d65fa2e4057afe/pip-20.3.1-py2.py3-none-any.whl (Caused by ProtocolError('Connection aborted.', ConnectionResetError(10054, 'An existing connection was forcibly closed by the remote host', None, 10054, None)))

I've started to look for the solution and found a treatment for this problem on a chinese blog:
https://www.cnblogs.com/temari/p/13452629.html
The point was to add a trusted host and use -i parameter.

So, instead of pip install --upgrade pip I typed pip install --upgrade pip -i http://pypi.douban.com/simple --trusted-host pypi.douban.com like in the post and it worked! But I don't want to use these parameters everytime I need to install a package or update pip..

I can't make any conclusions, because I don't know how pip works. I've tryed to reach pypi.python.org and pypi.org in a browser, everything was fine.

May be @jw120 is right and the problem is with http:// (or https://) before proxy.

@pradyunsg
Copy link
Member

pradyunsg commented Dec 4, 2020

@lex-pec: Could you share the output of pip config list, with the non-working vs working configurations?

@FDUZS
Copy link

FDUZS commented Dec 9, 2020

same here.

Zheng ~ ❯❯❯ pip --version
pip 20.3.1 from d:\scoop\apps\python\current\lib\site-packages\pip (python 3.7)
Zheng ~ ❯❯❯ pip config list
global.index-url='https://pypi.tuna.tsinghua.edu.cn/simple'

without http_proxy and https_proxy:

Zheng ~\..\pywonderland git: master ≣ ❯❯❯ pip install -r .\requirements.txt
Looking in indexes: https://pypi.tuna.tsinghua.edu.cn/simple
WARNING: Retrying (Retry(total=4, connect=None, read=None, redirect=None, status=None)) after connection broken by 'ProxyError('Cannot connect to proxy.', OSError(0, 'Error'))': /simple/colour/
WARNING: Retrying (Retry(total=3, connect=None, read=None, redirect=None, status=None)) after connection broken by 'ProxyError('Cannot connect to proxy.', OSError(0, 'Error'))': /simple/colour/
WARNING: Retrying (Retry(total=2, connect=None, read=None, redirect=None, status=None)) after connection broken by 'ProxyError('Cannot connect to proxy.', OSError(0, 'Error'))': /simple/colour/
WARNING: Retrying (Retry(total=1, connect=None, read=None, redirect=None, status=None)) after connection broken by 'ProxyError('Cannot connect to proxy.', OSError(0, 'Error'))': /simple/colour/
WARNING: Retrying (Retry(total=0, connect=None, read=None, redirect=None, status=None)) after connection broken by 'ProxyError('Cannot connect to proxy.', OSError(0, 'Error'))': /simple/colour/
ERROR: Could not find a version that satisfies the requirement colour
ERROR: No matching distribution found for colour

after setting up those two environment variables:

Zheng ~\..\pywonderland git: master ≣ ❯❯❯ proxy

Name                           Value
----                           -----
http_proxy                     127.0.0.1:1080
https_proxy                    127.0.0.1:1080
Zheng ~\..\pywonderland git: master ≣ ❯❯❯ pip install -r .\requirements.txt
Looking in indexes: https://pypi.tuna.tsinghua.edu.cn/simple
ERROR: Could not install packages due to an EnvironmentError: Not supported proxy scheme None

@sethmlarson
Copy link
Contributor

sethmlarson commented Dec 9, 2020

Hello, urllib3 dev here.

  • The ProxySchemeUnknown error has been in urllib3 in its current state for 6 years and wasn't changed between 1.25.9 and 1.26.2. Diff for these versions is here: urllib3/urllib3@1.25.9...1.26.2, ProxySchemeUnknown is raised here: e76b1dd#diff-42d9ff3a3dc18438ae9ad3552070169bc4140b54b61529e8a2ac7708352e1c5dL428 and is unchanged.

    My only thoughts on the ProxySchemeUnknown issue is that proxies that previously weren't being detected and passed to urllib3 now are?

  • As for connection issues with a proxy: Users that have their proxy configured as proxy_url=https://... and connecting to https://pypi.org before were actually using their proxy in an HTTP configuration (urllib3 didn't support HTTPS in HTTPS before v1.26 and would silently connect to the proxy via HTTP) so should update their proxy to be "http://..." or change their proxy to use HTTPS if that's desired.

    We added a InvalidProxyConfigurationWarning for this situation in 1.25.9 to warn users of the upcoming change to make HTTPS+HTTPS proxy requests work as expected in 1.26, we didn't receive many hits on the linked issue so assumed this issue wasn't widespread.

    Comments like these: Support for web proxies is broken in pip 20.3 #9190 (comment) Support for web proxies is broken in pip 20.3 #9190 (comment) seem to indicate this is the case for some reporting users.

    My recommendation to all users that know they have a proxy configured in 20.2 of HTTPS_PROXY=https://<host> should actually be HTTPS_PROXY=http://<host>. I'm interested in seeing people's issues that don't fit this criteria though, if any.

cc @jalopezsilva

@uranusjr uranusjr changed the title ProxySchemeUnknown: Not supported proxy scheme None Pip 20.3+ break proxy connection Dec 9, 2020
@uranusjr uranusjr added C: network connectivity C: proxy Dealing with proxies and networking project: vendored dependency Related to a vendored dependency and removed state: needs eyes Needs a maintainer/triager to take a closer look labels Dec 9, 2020
@uranusjr
Copy link
Member

uranusjr commented Dec 9, 2020

Hmm, the 20.2 series was on 1.25.9, but I don’t recall anyone reporting issues on this either. Maybe our warning settings did not bubble them correct? I have to admit I’ve never understood how warnings in Python work. Either way, thanks for the recommendation! I’m changing the title and pinning this issue for better discovery. (Edit: oops, looks like we have too many important issues, and GitHub only allows 3. So we’ll have to do without pinning.)

@tomerv
Copy link

tomerv commented Dec 9, 2020

Thanks for the explanation! This is indeed the source of the issue for us, and after reading the explanation I'm convinced that simply changing "https://" to "http://" is the correct solution (and not just a workaround - as I thought before). For better usability, my recommendation would be to catch this specific mistake and give a better error message, at least in the next few releases.

@pradyunsg pradyunsg added the C: error messages Improving error messages label Dec 9, 2020
@pradyunsg
Copy link
Member

Agreed.

In pip, catching pip._vendor.urllib3.exceptions.ProxySchemeUnknown in _get_html_response, would likely be the way to go to provide a better error message to our users. I wonder if upstream urllib3 could be the one providing a better error message... oh hey, we have @sethmlarson's attention to ask what he thinks. ;)

@sethmlarson
Copy link
Contributor

@pradyunsg Created two usability issues: urllib3/urllib3#2104 and urllib3/urllib3#2105

@tdekelver
Copy link

I also had the issue ERROR: Could not install packages due to an EnvironmentError: Not supported proxy scheme None as my environment variables HTTPS_PROXY and HTTP_PROXY were configured as xxx.xxx.xxx.xxx:xxxx. I changed this to http://xxx.xxx.xxx.xxx:xxxx and everything works as normal now.

@sanjay1839
Copy link

sanjay1839 commented Jan 23, 2021

HI I Still have problem with the proxy setting or SSL @uranusjr
image

@weijenloi
Copy link

weijenloi commented Jan 30, 2021

HI I Still have problem with the proxy setting or SSL @uranusjr
image

@sanjay1839
try SET HTTPS_PROXY=http://[username:pass]@server:port
it's working on my side

pip version: 21.0

@kotori2
Copy link

kotori2 commented Feb 5, 2021

I think I have a different issue here. I don't have any proxy defined as environment variable, but they are defined as system proxy.

PS C:\Users\Kotori0> Write-Output $env:https_proxy
PS C:\Users\Kotori0> Write-Output $env:http_proxy
PS C:\Users\Kotori0> Get-ItemProperty -Path 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings' | findstr ProxyServer
ProxyServer              : 127.0.0.1:7890

It seems Windows system proxy supports only HTTP proxy but not HTTPS, but smh pip still parsed it as HTTPS proxy.

@uranusjr
Copy link
Member

uranusjr commented Feb 6, 2021

@kotori2 You will need to report this to urllib3. pip is not able to support what it does not offer.

@junqfisica
Copy link
Contributor

The problem seems to be related to how pip is getting the proxy. Passing a proxy parameter to pip installation has no effect, i.e pip install package --proxy http://my_proxy:80 instead, pip gets it from the system (Windows in my case) which then gets the wrong scheme https causing the SSL error.

Doing SET HTTPS_PROXY=http:my_proxy then pip install package solves the problem. However, I'm using Pycharm which means that the installer from it doesn't work and I need to run the command in the terminal myself.

To deploy the application to the server (Centos) also doesn't work. I use Ansible for that and I pass the proxy to it. But somehow pip fails to get the proxy from the --proxy parameter. So, I would say the error lies there. As a user, I would expect pip to use whatever address I pass to the proxy parameter, and not get the proxy from the system var.

@kotori2
Copy link

kotori2 commented Mar 1, 2021

The problem seems to be related to how pip is getting the proxy. Passing a proxy parameter to pip installation has no effect, i.e pip install package --proxy http://my_proxy:80 instead, pip gets it from the system (Windows in my case) which then gets the wrong scheme https causing the SSL error.

Doing SET HTTPS_PROXY=http:my_proxy then pip install package solves the problem. However, I'm using Pycharm which means that the installer from it doesn't work and I need to run the command in the terminal myself.

To deploy the application to the server (Centos) also doesn't work. I use Ansible for that and I pass the proxy to it. But somehow pip fails to get the proxy from the --proxy parameter. So, I would say the error lies there. As a user, I would expect pip to use whatever address I pass to the proxy parameter, and not get the proxy from the system var.

You should blame urllib instead of pip. This is an issue which exists since Python 2.x and it breaks since urllib3 support https in https proxy.
https://bugs.python.org/issue42627

@junqfisica
Copy link
Contributor

@kotori2 Thanks for your comment. I was wondering where the problem really was and I have found it. It's actually within pip at pi\_internal\network\session.py in the method PipSession().request() line 419

I'm using pip 21.0.1 to debug.

The problem is caused because the proxy set by --proxy in the pip method is not being passed corrected to the request of urllib package.

This is the original request method of PipSession:

def request(self, method, url, *args, **kwargs):
        # Allow setting a default timeout on a session
        kwargs.setdefault("timeout", self.timeout)
        
        # Dispatch the actual request
        return super().request(method, url, *args, **kwargs)

If you make a breakpoint there you gonna see that self.proxies is corrected setted from --proxies, however, when the call to the parent class is made the proxies get lost and urllib set it from the system, which then gets the wrong scheme (https instead of http).

An easy fix I suggest is to add the following line at the request method in the file pi\_internal\network\session.py, line 419:

def request(self, method, url, *args, **kwargs):
     # Allow setting a default timeout on a session
     kwargs.setdefault("timeout", self.timeout)
     kwargs.setdefault("proxies", self.proxies)  # fix problem with proxies.

    # Dispatch the actual request
    return super().request(method, url, *args, **kwargs)

This way the proxies are carried out correctly to the request, if no proxy is set an empty dict is passed.

So now if you run pip install package --proxy http://proxy_ip everything works as expected.

I hope this will help to remove this bug in next versions of pip asap.

@pradyunsg
Copy link
Member

Closing since #9216 (comment) has all the information relevant here.

I don't think there's anything that pip can do here, but our users should switch to the more-correct proxy declarations. If someone has concrete suggestions for improvements on pip's end that aren't "just make my old thing work", please do file a new issue for discussion on the same.

@junqfisica
Copy link
Contributor

@pradyunsg I didn't quite understand your reply. What do you mean by a more-correct proxy declaration? Are you saying that invokeing pip install package --proxy proxy_ip is not right? If so, could tell me why? I gave a concrete suggestion for a fix on pip's end. You are not passing the proxy set by the user correctly to the urllib library, and that is the problem. IDEs like Pycharm uses --proxy parameter to pass the proxy to pip.

@uranusjr
Copy link
Member

uranusjr commented Mar 4, 2021

If you make a breakpoint there you gonna see that self.proxies is corrected setted from --proxies, however, when the call to the parent class is made the proxies get lost and urllib set it from the system, which then gets the wrong scheme (https instead of http).

This makes me suspect this may be caused by an implementation change in requests.Session, and not actually intended. I’m not sure the proposed change is correct, but “proxies specified by --proxy are not applied to the underlying requests connection” should be considered a bug on its own. It should be described in its own issue report and not here though.

@junqfisica
Copy link
Contributor

@uranusjr I have posted it here also. I agree with you that this is an issue by itself. Currently, I have no time to open a new issue providing all the specifics.
I would say this a major bug, which misleads users and creates a lot of confusion about how the proxy has been set. About the solution, I don't think pip devs can fix anything at requests.Session, since it's inside a vendor. Instead, they could fix it at session.PipSession passing the proxies correctly to requests.Session,request(...) since it accepts proxies as kwargs.
I have tested it here and everything works fine. Saying that I'm not a pip contributor so I don't have an in-deep knowledge of what is going on there. If you have a better way to fix it I would be happy to hear it..:).

@uranusjr
Copy link
Member

uranusjr commented Mar 4, 2021

I dug into this a bit deeper and it seems like even requests itself is a bit inconsistent: psf/requests#5677 (comment)

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
C: error messages Improving error messages C: network connectivity C: proxy Dealing with proxies and networking project: vendored dependency Related to a vendored dependency
Projects
None yet
Development

No branches or pull requests