eric6/Helpviewer/Network/NetworkAccessManager.py

changeset 6942
2602857055c5
parent 6645
ad476851d7e0
diff -r f99d60d6b59b -r 2602857055c5 eric6/Helpviewer/Network/NetworkAccessManager.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eric6/Helpviewer/Network/NetworkAccessManager.py	Sun Apr 14 15:09:21 2019 +0200
@@ -0,0 +1,277 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2009 - 2019 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing a QNetworkAccessManager subclass.
+"""
+
+from __future__ import unicode_literals
+
+import os
+
+from PyQt5.QtCore import pyqtSignal, QByteArray
+from PyQt5.QtWidgets import QDialog
+from PyQt5.QtNetwork import QNetworkAccessManager, QNetworkRequest, \
+    QNetworkReply
+
+from E5Network.E5NetworkProxyFactory import E5NetworkProxyFactory, \
+    proxyAuthenticationRequired
+try:
+    from PyQt5.QtNetwork import QSslSocket
+    from E5Network.E5SslErrorHandler import E5SslErrorHandler
+    SSL_AVAILABLE = True
+except ImportError:
+    SSL_AVAILABLE = False
+
+import Preferences
+import Utilities
+from Globals import qVersionTuple
+
+
+class NetworkAccessManager(QNetworkAccessManager):
+    """
+    Class implementing a QNetworkAccessManager subclass.
+    
+    @signal requestCreated emitted after the request has been created passing
+        the operation, a reference to the network request and a reference to
+        the network reply (QNetworkAccessManager.Operation, QNetworkRequest,
+        QNetworkReply)
+    """
+    requestCreated = pyqtSignal(
+        QNetworkAccessManager.Operation, QNetworkRequest, QNetworkReply)
+    
+    def __init__(self, engine, parent=None):
+        """
+        Constructor
+        
+        @param engine reference to the help engine (QHelpEngine)
+        @param parent reference to the parent object (QObject)
+        """
+        super(NetworkAccessManager, self).__init__(parent)
+        
+        self.__adblockNetwork = None
+        
+        self.__schemeHandlers = {}  # dictionary of scheme handlers
+        
+        self.__proxyFactory = E5NetworkProxyFactory()
+        self.setProxyFactory(self.__proxyFactory)
+        
+        self.__setDiskCache()
+        self.languagesChanged()
+        
+        if SSL_AVAILABLE:
+            self.__sslErrorHandler = E5SslErrorHandler(self)
+            self.sslErrors.connect(self.__sslErrorHandler.sslErrorsReplySlot)
+        
+        self.proxyAuthenticationRequired.connect(proxyAuthenticationRequired)
+        self.authenticationRequired.connect(self.__authenticationRequired)
+        
+        self.__doNotTrack = Preferences.getHelp("DoNotTrack")
+        self.__sendReferer = Preferences.getHelp("SendReferer")
+        
+        # register scheme handlers
+        if engine:
+            from .QtHelpAccessHandler import QtHelpAccessHandler
+            self.setSchemeHandler("qthelp", QtHelpAccessHandler(engine, self))
+        
+        from .EricAccessHandler import EricAccessHandler
+        self.setSchemeHandler("eric", EricAccessHandler(self))
+        
+        from .AboutAccessHandler import AboutAccessHandler
+        self.setSchemeHandler("about", AboutAccessHandler(self))
+        
+        from Helpviewer.AdBlock.AdBlockAccessHandler import \
+            AdBlockAccessHandler
+        self.setSchemeHandler("abp", AdBlockAccessHandler(self))
+        
+        from .FtpAccessHandler import FtpAccessHandler
+        self.setSchemeHandler("ftp", FtpAccessHandler(self))
+        
+        from .FileAccessHandler import FileAccessHandler
+        self.setSchemeHandler("file", FileAccessHandler(self))
+    
+    def setSchemeHandler(self, scheme, handler):
+        """
+        Public method to register a scheme handler.
+        
+        @param scheme access scheme (string)
+        @param handler reference to the scheme handler object
+            (SchemeAccessHandler)
+        """
+        self.__schemeHandlers[scheme] = handler
+    
+    def createRequest(self, op, request, outgoingData=None):
+        """
+        Public method to create a request.
+        
+        @param op the operation to be performed
+            (QNetworkAccessManager.Operation)
+        @param request reference to the request object (QNetworkRequest)
+        @param outgoingData reference to an IODevice containing data to be sent
+            (QIODevice)
+        @return reference to the created reply object (QNetworkReply)
+        """
+        scheme = request.url().scheme()
+        if scheme == "https" and \
+                (not SSL_AVAILABLE or not QSslSocket.supportsSsl()):
+            from .NetworkProtocolUnknownErrorReply import \
+                NetworkProtocolUnknownErrorReply
+            return NetworkProtocolUnknownErrorReply(scheme, self)
+        
+        import Helpviewer.HelpWindow
+        
+        if op == QNetworkAccessManager.PostOperation and \
+                outgoingData is not None:
+            outgoingDataByteArray = outgoingData.peek(1024 * 1024)
+            Helpviewer.HelpWindow.HelpWindow.passwordManager().post(
+                request, outgoingDataByteArray)
+        
+        reply = None
+        if scheme in self.__schemeHandlers:
+            reply = self.__schemeHandlers[scheme]\
+                        .createRequest(op, request, outgoingData)
+        if reply is not None:
+            return reply
+        
+        # give GreaseMonkey the chance to create a request
+        reply = Helpviewer.HelpWindow.HelpWindow.greaseMonkeyManager()\
+            .createRequest(op, request, outgoingData)
+        if reply is not None:
+            return reply
+        
+        req = QNetworkRequest(request)
+        if req.rawHeader(b"X-Eric6-UserLoadAction") == QByteArray(b"1"):
+            req.setRawHeader(b"X-Eric6-UserLoadAction", QByteArray())
+            req.setAttribute(QNetworkRequest.User + 200, b"")
+        else:
+            req.setAttribute(
+                QNetworkRequest.User + 200, req.rawHeader(b"Referer"))
+        
+        if hasattr(QNetworkRequest, 'HttpPipeliningAllowedAttribute'):
+            req.setAttribute(
+                QNetworkRequest.HttpPipeliningAllowedAttribute, True)
+        if not self.__acceptLanguage.isEmpty():
+            req.setRawHeader(b"Accept-Language", self.__acceptLanguage)
+        
+        # AdBlock code
+        if op == QNetworkAccessManager.GetOperation:
+            if self.__adblockNetwork is None:
+                self.__adblockNetwork = \
+                    Helpviewer.HelpWindow.HelpWindow.adBlockManager().network()
+            reply = self.__adblockNetwork.block(req)
+            if reply is not None:
+                reply.setParent(self)
+                return reply
+        
+        # set cache policy
+        if op == QNetworkAccessManager.GetOperation:
+            urlHost = req.url().host()
+            for host in Preferences.getHelp("NoCacheHosts"):
+                if host in urlHost:
+                    req.setAttribute(
+                        QNetworkRequest.CacheLoadControlAttribute,
+                        QNetworkRequest.AlwaysNetwork)
+                    break
+            else:
+                req.setAttribute(
+                    QNetworkRequest.CacheLoadControlAttribute,
+                    Preferences.getHelp("CachePolicy"))
+        else:
+            req.setAttribute(
+                QNetworkRequest.CacheLoadControlAttribute,
+                QNetworkRequest.AlwaysNetwork)
+        
+        # Do Not Track feature
+        if self.__doNotTrack:
+            req.setRawHeader(b"DNT", b"1")
+            req.setRawHeader(b"X-Do-Not-Track", b"1")
+        
+        # Send referer header?
+        if not self.__sendReferer and \
+           req.url().host() not in Preferences.getHelp("SendRefererWhitelist"):
+            req.setRawHeader(b"Referer", b"")
+        
+        reply = QNetworkAccessManager.createRequest(
+            self, op, req, outgoingData)
+        self.requestCreated.emit(op, req, reply)
+        
+        return reply
+    
+    def __authenticationRequired(self, reply, auth):
+        """
+        Private slot to handle an authentication request.
+        
+        @param reply reference to the reply object (QNetworkReply)
+        @param auth reference to the authenticator object (QAuthenticator)
+        """
+        urlRoot = "{0}://{1}"\
+            .format(reply.url().scheme(), reply.url().authority())
+        realm = auth.realm()
+        if not realm and 'realm' in auth.options():
+            realm = auth.option("realm")
+        if realm:
+            info = self.tr("<b>Enter username and password for '{0}', "
+                           "realm '{1}'</b>").format(urlRoot, realm)
+        else:
+            info = self.tr("<b>Enter username and password for '{0}'</b>")\
+                .format(urlRoot)
+        
+        from UI.AuthenticationDialog import AuthenticationDialog
+        import Helpviewer.HelpWindow
+        
+        dlg = AuthenticationDialog(info, auth.user(),
+                                   Preferences.getUser("SavePasswords"),
+                                   Preferences.getUser("SavePasswords"))
+        if Preferences.getUser("SavePasswords"):
+            username, password = \
+                Helpviewer.HelpWindow.HelpWindow.passwordManager().getLogin(
+                    reply.url(), realm)
+            if username:
+                dlg.setData(username, password)
+        if dlg.exec_() == QDialog.Accepted:
+            username, password = dlg.getData()
+            auth.setUser(username)
+            auth.setPassword(password)
+            if Preferences.getUser("SavePasswords") and dlg.shallSave():
+                Helpviewer.HelpWindow.HelpWindow.passwordManager().setLogin(
+                    reply.url(), realm, username, password)
+    
+    def preferencesChanged(self):
+        """
+        Public slot to signal a change of preferences.
+        """
+        self.__setDiskCache()
+        
+        self.__doNotTrack = Preferences.getHelp("DoNotTrack")
+        self.__sendReferer = Preferences.getHelp("SendReferer")
+    
+    def languagesChanged(self):
+        """
+        Public slot to (re-)load the list of accepted languages.
+        """
+        from Helpviewer.HelpLanguagesDialog import HelpLanguagesDialog
+        languages = Preferences.toList(
+            Preferences.Prefs.settings.value(
+                "Help/AcceptLanguages",
+                HelpLanguagesDialog.defaultAcceptLanguages()))
+        self.__acceptLanguage = HelpLanguagesDialog.httpString(languages)
+    
+    def __setDiskCache(self):
+        """
+        Private method to set the disk cache.
+        """
+        if Preferences.getHelp("DiskCacheEnabled"):
+            from PyQt5.QtWebKit import qWebKitVersion
+            from .NetworkDiskCache import NetworkDiskCache
+            diskCache = NetworkDiskCache(self)
+            location = os.path.join(
+                Utilities.getConfigDir(), "browser", 'cache',
+                "{0}-Qt{1}.{2}".format(qWebKitVersion(), *qVersionTuple()))
+            size = Preferences.getHelp("DiskCacheSize") * 1024 * 1024
+            diskCache.setCacheDirectory(location)
+            diskCache.setMaximumCacheSize(size)
+        else:
+            diskCache = None
+        self.setCache(diskCache)

eric ide

mercurial