diff -r 3fc8dfeb6ebe -r b99e7fd55fd3 src/eric7/EricNetwork/EricNetworkProxyFactory.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/eric7/EricNetwork/EricNetworkProxyFactory.py Thu Jul 07 11:23:56 2022 +0200 @@ -0,0 +1,261 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2010 - 2022 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing a network proxy factory. +""" + +import os +import re + +from PyQt6.QtCore import QUrl, QCoreApplication +from PyQt6.QtWidgets import QDialog +from PyQt6.QtNetwork import ( + QNetworkProxyFactory, QNetworkProxy, QNetworkProxyQuery +) + +from EricWidgets import EricMessageBox + +import Preferences +import Globals +import Utilities + + +def schemeFromProxyType(proxyType): + """ + Module function to determine the scheme name from the proxy type. + + @param proxyType type of the proxy (QNetworkProxy.ProxyType) + @return scheme (string, one of Http, Https, Ftp) + """ + scheme = "" + if proxyType == QNetworkProxy.ProxyType.HttpProxy: + scheme = "Http" + elif proxyType == QNetworkProxy.ProxyType.HttpCachingProxy: + scheme = "Https" + elif proxyType == QNetworkProxy.ProxyType.FtpCachingProxy: + scheme = "Ftp" + elif proxyType == QNetworkProxy.ProxyType.NoProxy: + scheme = "NoProxy" + return scheme + + +def proxyAuthenticationRequired(proxy, auth): + """ + Module slot to handle a proxy authentication request. + + @param proxy reference to the proxy object (QNetworkProxy) + @param auth reference to the authenticator object (QAuthenticator) + """ + info = QCoreApplication.translate( + "EricNetworkProxyFactory", + "<b>Connect to proxy '{0}' using:</b>" + ).format(Utilities.html_encode(proxy.hostName())) + + from UI.AuthenticationDialog import AuthenticationDialog + dlg = AuthenticationDialog(info, proxy.user(), True) + dlg.setData(proxy.user(), proxy.password()) + if dlg.exec() == QDialog.DialogCode.Accepted: + username, password = dlg.getData() + auth.setUser(username) + auth.setPassword(password) + if dlg.shallSave(): + scheme = schemeFromProxyType(proxy.type()) + if scheme and scheme != "NoProxy": + Preferences.setUI("ProxyUser/{0}".format(scheme), username) + Preferences.setUI("ProxyPassword/{0}".format(scheme), password) + proxy.setUser(username) + proxy.setPassword(password) + + +class HostnameMatcher: + """ + Class implementing a matcher for host names. + """ + def __init__(self, pattern): + """ + Constructor + + @param pattern pattern to be matched against + @type str + """ + self.__regExp = None + self.setPattern(pattern) + + def setPattern(self, pattern): + """ + Public method to set the match pattern. + + @param pattern pattern to be matched against + """ + self.__pattern = pattern + + if "?" in pattern or "*" in pattern: + regexp = "^.*{0}.*$".format( + pattern + .replace(".", "\\.") + .replace("*", ".*") + .replace("?", ".") + ) + self.__regExp = re.compile(regexp, re.IGNORECASE) + + def pattern(self): + """ + Public method to get the match pattern. + + @return match pattern + @rtype str + """ + return self.__pattern + + def match(self, host): + """ + Public method to test the given string. + + @param host host name to be matched + @type str + @return flag indicating a successful match + @rtype bool + """ + if self.__regExp is None: + return self.__pattern in host + + return self.__regExp.search(host) is not None + + +class EricNetworkProxyFactory(QNetworkProxyFactory): + """ + Class implementing a network proxy factory. + """ + def __init__(self): + """ + Constructor + """ + super().__init__() + + self.__hostnameMatchers = [] + self.__exceptions = "" + + def __setExceptions(self, exceptions): + """ + Private method to set the host name exceptions. + + @param exceptions list of exceptions separated by ',' + @type str + """ + self.__hostnameMatchers = [] + self.__exceptions = exceptions + for exception in self.__exceptions.split(","): + self.__hostnameMatchers.append(HostnameMatcher(exception.strip())) + + def queryProxy(self, query): + """ + Public method to determine a proxy for a given query. + + @param query reference to the query object (QNetworkProxyQuery) + @return list of proxies in order of preference (list of QNetworkProxy) + """ + if ( + query.queryType() == QNetworkProxyQuery.QueryType.UrlRequest and + query.protocolTag() in ["http", "https", "ftp"] + ): + # use proxy at all ? + if not Preferences.getUI("UseProxy"): + return [QNetworkProxy(QNetworkProxy.ProxyType.NoProxy)] + + # test for exceptions + exceptions = Preferences.getUI("ProxyExceptions") + if exceptions != self.__exceptions: + self.__setExceptions(exceptions) + urlHost = query.url().host() + for matcher in self.__hostnameMatchers: + if matcher.match(urlHost): + return [QNetworkProxy(QNetworkProxy.ProxyType.NoProxy)] + + # determine proxy + if Preferences.getUI("UseSystemProxy"): + proxyList = QNetworkProxyFactory.systemProxyForQuery(query) + if ( + not Globals.isWindowsPlatform() and + len(proxyList) == 1 and + proxyList[0].type() == QNetworkProxy.ProxyType.NoProxy + ): + # try it the Python way + # scan the environment for variables named <scheme>_proxy + # scan over whole environment to make this case insensitive + for name, value in os.environ.items(): + name = name.lower() + if ( + value and + name[-6:] == '_proxy' and + name[:-6] == query.protocolTag().lower() + ): + url = QUrl(value) + if url.scheme() in ["http", "https"]: + proxyType = QNetworkProxy.ProxyType.HttpProxy + elif url.scheme() == "ftp": + proxyType = ( + QNetworkProxy.ProxyType.FtpCachingProxy + ) + else: + proxyType = QNetworkProxy.ProxyType.HttpProxy + proxy = QNetworkProxy( + proxyType, url.host(), url.port(), + url.userName(), url.password()) + proxyList = [proxy] + break + if proxyList: + scheme = schemeFromProxyType(proxyList[0].type()) + if scheme == "": + scheme = "Http" + if scheme != "NoProxy": + proxyList[0].setUser( + Preferences.getUI("ProxyUser/{0}".format(scheme))) + proxyList[0].setPassword( + Preferences.getUI( + "ProxyPassword/{0}".format(scheme))) + return proxyList + else: + return [QNetworkProxy(QNetworkProxy.ProxyType.NoProxy)] + else: + if Preferences.getUI("UseHttpProxyForAll"): + protocolKey = "Http" + else: + protocolKey = query.protocolTag().capitalize() + host = Preferences.getUI("ProxyHost/{0}".format(protocolKey)) + if not host: + EricMessageBox.critical( + None, + QCoreApplication.translate( + "EricNetworkProxyFactory", + "Proxy Configuration Error"), + QCoreApplication.translate( + "EricNetworkProxyFactory", + """Proxy usage was activated""" + """ but no proxy host for protocol""" + """ '{0}' configured.""").format(protocolKey)) + return [ + QNetworkProxy(QNetworkProxy.ProxyType.DefaultProxy) + ] + else: + if protocolKey in ["Http", "Https", "Ftp"]: + if query.protocolTag() == "ftp": + proxyType = QNetworkProxy.ProxyType.FtpCachingProxy + else: + proxyType = QNetworkProxy.ProxyType.HttpProxy + proxy = QNetworkProxy( + proxyType, host, + Preferences.getUI("ProxyPort/" + protocolKey), + Preferences.getUI("ProxyUser/" + protocolKey), + Preferences.getUI("ProxyPassword/" + protocolKey)) + else: + proxy = QNetworkProxy( + QNetworkProxy.ProxyType.DefaultProxy) + return [ + proxy, + QNetworkProxy(QNetworkProxy.ProxyType.DefaultProxy) + ] + else: + return [QNetworkProxy(QNetworkProxy.ProxyType.NoProxy)]