eric6/Helpviewer/Network/NetworkAccessManager.py

changeset 6942
2602857055c5
parent 6645
ad476851d7e0
equal deleted inserted replaced
6941:f99d60d6b59b 6942:2602857055c5
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2009 - 2019 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing a QNetworkAccessManager subclass.
8 """
9
10 from __future__ import unicode_literals
11
12 import os
13
14 from PyQt5.QtCore import pyqtSignal, QByteArray
15 from PyQt5.QtWidgets import QDialog
16 from PyQt5.QtNetwork import QNetworkAccessManager, QNetworkRequest, \
17 QNetworkReply
18
19 from E5Network.E5NetworkProxyFactory import E5NetworkProxyFactory, \
20 proxyAuthenticationRequired
21 try:
22 from PyQt5.QtNetwork import QSslSocket
23 from E5Network.E5SslErrorHandler import E5SslErrorHandler
24 SSL_AVAILABLE = True
25 except ImportError:
26 SSL_AVAILABLE = False
27
28 import Preferences
29 import Utilities
30 from Globals import qVersionTuple
31
32
33 class NetworkAccessManager(QNetworkAccessManager):
34 """
35 Class implementing a QNetworkAccessManager subclass.
36
37 @signal requestCreated emitted after the request has been created passing
38 the operation, a reference to the network request and a reference to
39 the network reply (QNetworkAccessManager.Operation, QNetworkRequest,
40 QNetworkReply)
41 """
42 requestCreated = pyqtSignal(
43 QNetworkAccessManager.Operation, QNetworkRequest, QNetworkReply)
44
45 def __init__(self, engine, parent=None):
46 """
47 Constructor
48
49 @param engine reference to the help engine (QHelpEngine)
50 @param parent reference to the parent object (QObject)
51 """
52 super(NetworkAccessManager, self).__init__(parent)
53
54 self.__adblockNetwork = None
55
56 self.__schemeHandlers = {} # dictionary of scheme handlers
57
58 self.__proxyFactory = E5NetworkProxyFactory()
59 self.setProxyFactory(self.__proxyFactory)
60
61 self.__setDiskCache()
62 self.languagesChanged()
63
64 if SSL_AVAILABLE:
65 self.__sslErrorHandler = E5SslErrorHandler(self)
66 self.sslErrors.connect(self.__sslErrorHandler.sslErrorsReplySlot)
67
68 self.proxyAuthenticationRequired.connect(proxyAuthenticationRequired)
69 self.authenticationRequired.connect(self.__authenticationRequired)
70
71 self.__doNotTrack = Preferences.getHelp("DoNotTrack")
72 self.__sendReferer = Preferences.getHelp("SendReferer")
73
74 # register scheme handlers
75 if engine:
76 from .QtHelpAccessHandler import QtHelpAccessHandler
77 self.setSchemeHandler("qthelp", QtHelpAccessHandler(engine, self))
78
79 from .EricAccessHandler import EricAccessHandler
80 self.setSchemeHandler("eric", EricAccessHandler(self))
81
82 from .AboutAccessHandler import AboutAccessHandler
83 self.setSchemeHandler("about", AboutAccessHandler(self))
84
85 from Helpviewer.AdBlock.AdBlockAccessHandler import \
86 AdBlockAccessHandler
87 self.setSchemeHandler("abp", AdBlockAccessHandler(self))
88
89 from .FtpAccessHandler import FtpAccessHandler
90 self.setSchemeHandler("ftp", FtpAccessHandler(self))
91
92 from .FileAccessHandler import FileAccessHandler
93 self.setSchemeHandler("file", FileAccessHandler(self))
94
95 def setSchemeHandler(self, scheme, handler):
96 """
97 Public method to register a scheme handler.
98
99 @param scheme access scheme (string)
100 @param handler reference to the scheme handler object
101 (SchemeAccessHandler)
102 """
103 self.__schemeHandlers[scheme] = handler
104
105 def createRequest(self, op, request, outgoingData=None):
106 """
107 Public method to create a request.
108
109 @param op the operation to be performed
110 (QNetworkAccessManager.Operation)
111 @param request reference to the request object (QNetworkRequest)
112 @param outgoingData reference to an IODevice containing data to be sent
113 (QIODevice)
114 @return reference to the created reply object (QNetworkReply)
115 """
116 scheme = request.url().scheme()
117 if scheme == "https" and \
118 (not SSL_AVAILABLE or not QSslSocket.supportsSsl()):
119 from .NetworkProtocolUnknownErrorReply import \
120 NetworkProtocolUnknownErrorReply
121 return NetworkProtocolUnknownErrorReply(scheme, self)
122
123 import Helpviewer.HelpWindow
124
125 if op == QNetworkAccessManager.PostOperation and \
126 outgoingData is not None:
127 outgoingDataByteArray = outgoingData.peek(1024 * 1024)
128 Helpviewer.HelpWindow.HelpWindow.passwordManager().post(
129 request, outgoingDataByteArray)
130
131 reply = None
132 if scheme in self.__schemeHandlers:
133 reply = self.__schemeHandlers[scheme]\
134 .createRequest(op, request, outgoingData)
135 if reply is not None:
136 return reply
137
138 # give GreaseMonkey the chance to create a request
139 reply = Helpviewer.HelpWindow.HelpWindow.greaseMonkeyManager()\
140 .createRequest(op, request, outgoingData)
141 if reply is not None:
142 return reply
143
144 req = QNetworkRequest(request)
145 if req.rawHeader(b"X-Eric6-UserLoadAction") == QByteArray(b"1"):
146 req.setRawHeader(b"X-Eric6-UserLoadAction", QByteArray())
147 req.setAttribute(QNetworkRequest.User + 200, b"")
148 else:
149 req.setAttribute(
150 QNetworkRequest.User + 200, req.rawHeader(b"Referer"))
151
152 if hasattr(QNetworkRequest, 'HttpPipeliningAllowedAttribute'):
153 req.setAttribute(
154 QNetworkRequest.HttpPipeliningAllowedAttribute, True)
155 if not self.__acceptLanguage.isEmpty():
156 req.setRawHeader(b"Accept-Language", self.__acceptLanguage)
157
158 # AdBlock code
159 if op == QNetworkAccessManager.GetOperation:
160 if self.__adblockNetwork is None:
161 self.__adblockNetwork = \
162 Helpviewer.HelpWindow.HelpWindow.adBlockManager().network()
163 reply = self.__adblockNetwork.block(req)
164 if reply is not None:
165 reply.setParent(self)
166 return reply
167
168 # set cache policy
169 if op == QNetworkAccessManager.GetOperation:
170 urlHost = req.url().host()
171 for host in Preferences.getHelp("NoCacheHosts"):
172 if host in urlHost:
173 req.setAttribute(
174 QNetworkRequest.CacheLoadControlAttribute,
175 QNetworkRequest.AlwaysNetwork)
176 break
177 else:
178 req.setAttribute(
179 QNetworkRequest.CacheLoadControlAttribute,
180 Preferences.getHelp("CachePolicy"))
181 else:
182 req.setAttribute(
183 QNetworkRequest.CacheLoadControlAttribute,
184 QNetworkRequest.AlwaysNetwork)
185
186 # Do Not Track feature
187 if self.__doNotTrack:
188 req.setRawHeader(b"DNT", b"1")
189 req.setRawHeader(b"X-Do-Not-Track", b"1")
190
191 # Send referer header?
192 if not self.__sendReferer and \
193 req.url().host() not in Preferences.getHelp("SendRefererWhitelist"):
194 req.setRawHeader(b"Referer", b"")
195
196 reply = QNetworkAccessManager.createRequest(
197 self, op, req, outgoingData)
198 self.requestCreated.emit(op, req, reply)
199
200 return reply
201
202 def __authenticationRequired(self, reply, auth):
203 """
204 Private slot to handle an authentication request.
205
206 @param reply reference to the reply object (QNetworkReply)
207 @param auth reference to the authenticator object (QAuthenticator)
208 """
209 urlRoot = "{0}://{1}"\
210 .format(reply.url().scheme(), reply.url().authority())
211 realm = auth.realm()
212 if not realm and 'realm' in auth.options():
213 realm = auth.option("realm")
214 if realm:
215 info = self.tr("<b>Enter username and password for '{0}', "
216 "realm '{1}'</b>").format(urlRoot, realm)
217 else:
218 info = self.tr("<b>Enter username and password for '{0}'</b>")\
219 .format(urlRoot)
220
221 from UI.AuthenticationDialog import AuthenticationDialog
222 import Helpviewer.HelpWindow
223
224 dlg = AuthenticationDialog(info, auth.user(),
225 Preferences.getUser("SavePasswords"),
226 Preferences.getUser("SavePasswords"))
227 if Preferences.getUser("SavePasswords"):
228 username, password = \
229 Helpviewer.HelpWindow.HelpWindow.passwordManager().getLogin(
230 reply.url(), realm)
231 if username:
232 dlg.setData(username, password)
233 if dlg.exec_() == QDialog.Accepted:
234 username, password = dlg.getData()
235 auth.setUser(username)
236 auth.setPassword(password)
237 if Preferences.getUser("SavePasswords") and dlg.shallSave():
238 Helpviewer.HelpWindow.HelpWindow.passwordManager().setLogin(
239 reply.url(), realm, username, password)
240
241 def preferencesChanged(self):
242 """
243 Public slot to signal a change of preferences.
244 """
245 self.__setDiskCache()
246
247 self.__doNotTrack = Preferences.getHelp("DoNotTrack")
248 self.__sendReferer = Preferences.getHelp("SendReferer")
249
250 def languagesChanged(self):
251 """
252 Public slot to (re-)load the list of accepted languages.
253 """
254 from Helpviewer.HelpLanguagesDialog import HelpLanguagesDialog
255 languages = Preferences.toList(
256 Preferences.Prefs.settings.value(
257 "Help/AcceptLanguages",
258 HelpLanguagesDialog.defaultAcceptLanguages()))
259 self.__acceptLanguage = HelpLanguagesDialog.httpString(languages)
260
261 def __setDiskCache(self):
262 """
263 Private method to set the disk cache.
264 """
265 if Preferences.getHelp("DiskCacheEnabled"):
266 from PyQt5.QtWebKit import qWebKitVersion
267 from .NetworkDiskCache import NetworkDiskCache
268 diskCache = NetworkDiskCache(self)
269 location = os.path.join(
270 Utilities.getConfigDir(), "browser", 'cache',
271 "{0}-Qt{1}.{2}".format(qWebKitVersion(), *qVersionTuple()))
272 size = Preferences.getHelp("DiskCacheSize") * 1024 * 1024
273 diskCache.setCacheDirectory(location)
274 diskCache.setMaximumCacheSize(size)
275 else:
276 diskCache = None
277 self.setCache(diskCache)

eric ide

mercurial