WebBrowser/Network/NetworkUrlInterceptor.py

changeset 6281
9f7bbfd6545d
parent 6277
e22952cec018
child 6645
ad476851d7e0
equal deleted inserted replaced
6280:1d4d790414b2 6281:9f7bbfd6545d
8 by QtWebEngine. 8 by QtWebEngine.
9 """ 9 """
10 10
11 from __future__ import unicode_literals 11 from __future__ import unicode_literals
12 12
13 from PyQt5.QtCore import QMutex, QMutexLocker 13 from PyQt5.QtCore import QMutex, QMutexLocker, QUrl
14 from PyQt5.QtWebEngineCore import QWebEngineUrlRequestInterceptor 14 from PyQt5.QtWebEngineCore import QWebEngineUrlRequestInterceptor, \
15 QWebEngineUrlRequestInfo
15 16
16 from ..WebBrowserPage import WebBrowserPage 17 from ..WebBrowserPage import WebBrowserPage
17 18
18 import Preferences 19 import Preferences
19 20
60 info.setHttpHeader(b"User-Agent", userAgent.encode()) 61 info.setHttpHeader(b"User-Agent", userAgent.encode())
61 62
62 for interceptor in self.__interceptors: 63 for interceptor in self.__interceptors:
63 interceptor.interceptRequest(info) 64 interceptor.interceptRequest(info)
64 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
65 def __setRefererHeader(self, info): 109 def __setRefererHeader(self, info):
66 """ 110 """
67 Private method to set the 'Referer' header depending on the configured 111 Private method to set the 'Referer' header depending on the configured
68 rule set. 112 rule set.
69 113
70 @param info URL request information 114 @param info URL request information
71 @type QWebEngineUrlRequestInfo 115 @type QWebEngineUrlRequestInfo
72 """ 116 @see <a href="https://wiki.mozilla.org/Security/Referrer">
73 # TODO: extend referrer handling like that: 117 Mozilla Referrer</a>
118 @see <a href="https://www.w3.org/TR/referrer-policy/">
119 W3C Referrer Policy</a>
120 """
74 # 1. SendReferer: 121 # 1. SendReferer:
75 # 0 = never 122 # 0 = never
76 # 1 = only on click (NavigationTypeLink) 123 # 1 = only on click (NavigationTypeLink)
77 # 2 = always (default) 124 # 2 = always (default)
78 # 2. RefererTrimmingPolicy: 125 # 2. RefererTrimmingPolicy:
79 # 0 = send full URL (no trimming) (default) 126 # 0 = send full URL (no trimming) (default)
80 # 1 = send the URL without its query string 127 # 1 = send the URL without its query string
81 # 2 = only send the origin (ensure trailing /) 128 # 2 = only send the origin (ensure trailing /)
82 # 3. RefererDefaultPolicy: 129 # 3. RefererDefaultPolicy:
83 # set the default referrer policy (which can be overriden by 130 # set the default referrer policy (which can be overriden by
86 # 1 = same-origin 133 # 1 = same-origin
87 # 2 = strict-origin-when-cross-origin 134 # 2 = strict-origin-when-cross-origin
88 # 3 = no-referrer-when-downgrade (default) 135 # 3 = no-referrer-when-downgrade (default)
89 # see: https://wiki.mozilla.org/Security/Referrer 136 # see: https://wiki.mozilla.org/Security/Referrer
90 # see: https://www.w3.org/TR/referrer-policy/ 137 # see: https://www.w3.org/TR/referrer-policy/
91 if not self.__sendReferer: 138
139 if self.__sendReferer == 0:
140 # never send referer header
92 info.setHttpHeader(b"Referer", b"") 141 info.setHttpHeader(b"Referer", b"")
93 142 elif (self.__sendReferer == 1 and
94 def installUrlInterceptor(self, interceptor): 143 info.navigationType() !=
95 """ 144 QWebEngineUrlRequestInfo.NavigationTypeLink):
96 Public method to install an URL interceptor. 145 # send referer header only on click
97 146 info.setHttpHeader(b"Referer", b"")
98 @param interceptor URL interceptor to be installed 147 else:
99 @type UrlInterceptor 148 # send referer header always applying further policies
100 """ 149 url = info.firstPartyUrl()
101 locker = QMutexLocker(self.__mutex) # __IGNORE_WARNING__ 150 reqUrl = info.requestUrl()
102 151 if self.__refererDefaultPolicy == 0:
103 if interceptor not in self.__interceptors: 152 # no-referrer
104 self.__interceptors.append(interceptor) 153 refererUrl = b""
105 154 elif self.__refererDefaultPolicy == 1:
106 def removeUrlInterceptor(self, interceptor): 155 # same-origin
107 """ 156 if self.__sameOrigin(url, reqUrl):
108 Public method to remove an URL interceptor. 157 refererUrl = self.__trimmedReferer(url)
109 158 else:
110 @param interceptor URL interceptor to be removed 159 refererUrl = b""
111 @type UrlInterceptor 160 elif self.__refererDefaultPolicy == 2:
112 """ 161 # strict-origin-when-cross-origin
113 locker = QMutexLocker(self.__mutex) # __IGNORE_WARNING__ 162 if self.__sameOrigin(url, reqUrl):
114 163 refererUrl = self.__trimmedReferer(url)
115 if interceptor in self.__interceptors: 164 elif url.scheme() in ("https", "wss"):
116 self.__interceptors.remove(interceptor) 165 if self.__potentiallyTrustworthy(url):
117 166 refererUrl = self.__refererOrigin(url)
118 def __loadSettings(self): 167 else:
119 """ 168 refererUrl = b""
120 Private method to load the Network Manager settings. 169 else:
121 """ 170 refererUrl = self.__refererOrigin(url)
122 locker = QMutexLocker(self.__mutex) # __IGNORE_WARNING__ 171 else:
123 172 # no-referrer-when-downgrade
124 self.__doNotTrack = Preferences.getWebBrowser("DoNotTrack") 173 if url.scheme() in ("https", "wss") and \
125 self.__sendReferer = Preferences.getWebBrowser("SendReferer") 174 not self.__potentiallyTrustworthy(url):
126 175 refererUrl = b""
127 def preferencesChanged(self): 176 else:
128 """ 177 refererUrl = self.__trimmedReferer(url)
129 Public slot to handle a change of preferences. 178
130 """ 179 info.setHttpHeader(b"Referer", refererUrl)
131 self.__loadSettings() 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