eric6/WebBrowser/Network/NetworkUrlInterceptor.py

changeset 6942
2602857055c5
parent 6645
ad476851d7e0
child 7229
53054eb5b15a
equal deleted inserted replaced
6941:f99d60d6b59b 6942:2602857055c5
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2016 - 2019 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing a class to handle URL requests before they get processed
8 by QtWebEngine.
9 """
10
11 from __future__ import unicode_literals
12
13 from PyQt5.QtCore import QMutex, QMutexLocker, QUrl
14 from PyQt5.QtWebEngineCore import QWebEngineUrlRequestInterceptor, \
15 QWebEngineUrlRequestInfo
16
17 from ..WebBrowserPage import WebBrowserPage
18
19 import Preferences
20
21
22 class NetworkUrlInterceptor(QWebEngineUrlRequestInterceptor):
23 """
24 Class implementing an URL request handler.
25 """
26 def __init__(self, parent=None):
27 """
28 Constructor
29
30 @param parent reference to the parent object
31 @type QObject
32 """
33 super(NetworkUrlInterceptor, self).__init__(parent)
34
35 self.__interceptors = []
36 self.__mutex = QMutex()
37
38 self.__loadSettings()
39
40 def interceptRequest(self, info):
41 """
42 Public method handling an URL request.
43
44 @param info URL request information
45 @type QWebEngineUrlRequestInfo
46 """
47 locker = QMutexLocker(self.__mutex) # __IGNORE_WARNING__
48
49 # Do Not Track feature
50 if self.__doNotTrack:
51 info.setHttpHeader(b"DNT", b"1")
52 info.setHttpHeader(b"X-Do-Not-Track", b"1")
53
54 # Send referrer header?
55 if info.requestUrl().host() not in \
56 Preferences.getWebBrowser("SendRefererWhitelist"):
57 self.__setRefererHeader(info)
58
59 # User Agents header
60 userAgent = WebBrowserPage.userAgentForUrl(info.requestUrl())
61 info.setHttpHeader(b"User-Agent", userAgent.encode())
62
63 for interceptor in self.__interceptors:
64 interceptor.interceptRequest(info)
65
66 def installUrlInterceptor(self, interceptor):
67 """
68 Public method to install an URL interceptor.
69
70 @param interceptor URL interceptor to be installed
71 @type UrlInterceptor
72 """
73 locker = QMutexLocker(self.__mutex) # __IGNORE_WARNING__
74
75 if interceptor not in self.__interceptors:
76 self.__interceptors.append(interceptor)
77
78 def removeUrlInterceptor(self, interceptor):
79 """
80 Public method to remove an URL interceptor.
81
82 @param interceptor URL interceptor to be removed
83 @type UrlInterceptor
84 """
85 locker = QMutexLocker(self.__mutex) # __IGNORE_WARNING__
86
87 if interceptor in self.__interceptors:
88 self.__interceptors.remove(interceptor)
89
90 def __loadSettings(self):
91 """
92 Private method to load the Network Manager settings.
93 """
94 locker = QMutexLocker(self.__mutex) # __IGNORE_WARNING__
95
96 self.__doNotTrack = Preferences.getWebBrowser("DoNotTrack")
97 self.__sendReferer = Preferences.getWebBrowser("RefererSendReferer")
98 self.__refererDefaultPolicy = \
99 Preferences.getWebBrowser("RefererDefaultPolicy")
100 self.__refererTrimmingPolicy = \
101 Preferences.getWebBrowser("RefererTrimmingPolicy")
102
103 def preferencesChanged(self):
104 """
105 Public slot to handle a change of preferences.
106 """
107 self.__loadSettings()
108
109 def __setRefererHeader(self, info):
110 """
111 Private method to set the 'Referer' header depending on the configured
112 rule set.
113
114 @param info URL request information
115 @type QWebEngineUrlRequestInfo
116 @see <a href="https://wiki.mozilla.org/Security/Referrer">
117 Mozilla Referrer</a>
118 @see <a href="https://www.w3.org/TR/referrer-policy/">
119 W3C Referrer Policy</a>
120 """
121 # 1. SendReferer:
122 # 0 = never
123 # 1 = only on click (NavigationTypeLink)
124 # 2 = always (default)
125 # 2. RefererTrimmingPolicy:
126 # 0 = send full URL (no trimming) (default)
127 # 1 = send the URL without its query string
128 # 2 = only send the origin (ensure trailing /)
129 # 3. RefererDefaultPolicy:
130 # set the default referrer policy (which can be overriden by
131 # the site)
132 # 0 = no-referrer
133 # 1 = same-origin
134 # 2 = strict-origin-when-cross-origin
135 # 3 = no-referrer-when-downgrade (default)
136 # see: https://wiki.mozilla.org/Security/Referrer
137 # see: https://www.w3.org/TR/referrer-policy/
138
139 if self.__sendReferer == 0:
140 # never send referer header
141 info.setHttpHeader(b"Referer", b"")
142 elif (self.__sendReferer == 1 and
143 info.navigationType() !=
144 QWebEngineUrlRequestInfo.NavigationTypeLink):
145 # send referer header only on click
146 info.setHttpHeader(b"Referer", b"")
147 else:
148 # send referer header always applying further policies
149 url = info.firstPartyUrl()
150 reqUrl = info.requestUrl()
151 if self.__refererDefaultPolicy == 0:
152 # no-referrer
153 refererUrl = b""
154 elif self.__refererDefaultPolicy == 1:
155 # same-origin
156 if self.__sameOrigin(url, reqUrl):
157 refererUrl = self.__trimmedReferer(url)
158 else:
159 refererUrl = b""
160 elif self.__refererDefaultPolicy == 2:
161 # strict-origin-when-cross-origin
162 if self.__sameOrigin(url, reqUrl):
163 refererUrl = self.__trimmedReferer(url)
164 elif url.scheme() in ("https", "wss"):
165 if self.__potentiallyTrustworthy(url):
166 refererUrl = self.__refererOrigin(url)
167 else:
168 refererUrl = b""
169 else:
170 refererUrl = self.__refererOrigin(url)
171 else:
172 # no-referrer-when-downgrade
173 if url.scheme() in ("https", "wss") and \
174 not self.__potentiallyTrustworthy(url):
175 refererUrl = b""
176 else:
177 refererUrl = self.__trimmedReferer(url)
178
179 info.setHttpHeader(b"Referer", refererUrl)
180
181 def __sameOrigin(self, url1, url2):
182 """
183 Private method to test the "same origin" policy.
184
185 @param url1 first URL for the test
186 @type QUrl
187 @param url2 second URL for the test
188 @type QUrl
189 @return flag indicating that both URLs have the same origin
190 @rtype bool
191 """
192 origin1 = url1.url(QUrl.RemoveUserInfo | QUrl.RemovePath)
193 origin2 = url2.url(QUrl.RemoveUserInfo | QUrl.RemovePath)
194
195 return origin1 == origin2
196
197 def __potentiallyTrustworthy(self, url):
198 """
199 Private method to check, if the given URL is potentially trustworthy.
200
201 @param url URL to be checked
202 @type QUrl
203 @return flag indicating a potentially trustworthy URL
204 @rtype bool
205 """
206 if url.scheme() == "data":
207 return False
208
209 if url.toString() in ("about:blank", "about:srcdoc"):
210 return True
211
212 origin = url.adjusted(QUrl.RemoveUserInfo | QUrl.RemovePath)
213
214 if origin.isEmpty() or origin.scheme() == "":
215 return False
216 if origin.scheme() in ("https", "wss"):
217 return True
218 if origin.host().startswith("127.") or origin.host().endswith(":1"):
219 return True
220 if origin.host() == "localhost" or \
221 origin.host().endswith(".localhost"):
222 return True
223 if origin.scheme() == "file":
224 return True
225 if origin.scheme() in ("qrc", "qthelp", "eric"):
226 return True
227
228 return False
229
230 def __trimmedReferer(self, url):
231 """
232 Private method to generate the trimmed referer header URL.
233
234 @param url URL to be trimmed as a referer header
235 @type QUrl
236 @return trimmed referer header URL
237 @rtype QByteArray or bytes
238 """
239 if self.__refererTrimmingPolicy == 0:
240 # send full URL (no trimming) (default)
241 refererUrl = url.toEncoded(
242 QUrl.RemoveUserInfo | QUrl.RemoveFragment)
243 elif self.__refererTrimmingPolicy == 1:
244 # send the URL without its query string
245 refererUrl = url.toEncoded(
246 QUrl.RemoveUserInfo | QUrl.RemoveFragment |
247 QUrl.RemoveQuery)
248 else:
249 # only send the origin (ensure trailing /)
250 refererUrl = self.__refererOrigin(url)
251
252 return refererUrl
253
254 def __refererOrigin(self, url):
255 """
256 Private method to generate an origin referer header URL.
257
258 @param url URL to generate the header from
259 @type QUrl
260 @return origin referer header URL
261 @rtype QByteArray or bytes
262 """
263 referer = url.toEncoded(QUrl.RemoveUserInfo | QUrl.RemovePath)
264 if not referer.endsWith(b"/"):
265 referer += b"/"
266
267 return referer

eric ide

mercurial