77from itertools import chain
88
99from pkgcore .fetch import fetchable
10+ from snakeoil .compatibility import IGNORED_EXCEPTIONS
1011
1112from .. import addons , base
1213from . import NetworkCheck
@@ -67,6 +68,19 @@ def desc(self):
6768 return f'SSL cert error, { self .message } : { self .url !r} '
6869
6970
71+ class HttpsUrlAvailable (base .FilteredVersionResult , base .Warning ):
72+ """URL uses http:// when https:// is available."""
73+
74+ def __init__ (self , http_url , https_url , ** kwargs ):
75+ super ().__init__ (** kwargs )
76+ self .http_url = http_url
77+ self .https_url = https_url
78+
79+ @property
80+ def desc (self ):
81+ return f'{ self .http_url } should use { self .https_url } '
82+
83+
7084class _HttpRedirected301 (Exception ):
7185 """Exception used for flagging HTTP 301 redirects."""
7286
@@ -118,6 +132,17 @@ def _url_to_result(self, url):
118132 result = partial (self .dead_result , url , str (e ))
119133 return result
120134
135+ def _https_check (self , url ):
136+ result = False
137+ try :
138+ response = self .url_opener .open (url , timeout = self .timeout )
139+ result = partial (HttpsUrlAvailable , f'http://{ url [8 :]} ' , url )
140+ except IGNORED_EXCEPTIONS :
141+ raise
142+ except Exception :
143+ pass
144+ return result
145+
121146 def _done (self , pkg , future ):
122147 result = future .result ()
123148 if result :
@@ -127,25 +152,33 @@ def _done(self, pkg, future):
127152 def _get_urls (self , pkg ):
128153 raise NotImplementedError
129154
155+ def _http_to_https_urls (self , urls ):
156+ for url in urls :
157+ if url .startswith ('http://' ):
158+ yield f'https://{ url [7 :]} '
159+
130160 def feed (self , pkg ):
131- for url in self ._get_urls (pkg ):
132- future = self .checked .get (url )
133- if future is None :
134- future = self .executor .submit (self ._url_to_result , url )
135- future .add_done_callback (partial (self ._done , pkg ))
136- self .checked [url ] = future
137- elif future .done ():
138- result = future .result ()
139- if result :
140- yield result (pkg = pkg )
141- else :
142- future .add_done_callback (partial (self ._done , pkg ))
161+ target_urls = tuple (self ._get_urls (pkg ))
162+ for urls , func in ((target_urls , self ._url_to_result ),
163+ (self ._http_to_https_urls (target_urls ), self ._https_check )):
164+ for url in urls :
165+ future = self .checked .get (url )
166+ if future is None :
167+ future = self .executor .submit (func , url )
168+ future .add_done_callback (partial (self ._done , pkg ))
169+ self .checked [url ] = future
170+ elif future .done ():
171+ result = future .result ()
172+ if result :
173+ yield result (pkg = pkg )
174+ else :
175+ future .add_done_callback (partial (self ._done , pkg ))
143176
144177
145178class HomepageUrlCheck (_UrlCheck ):
146179 """Various HOMEPAGE related checks that require internet access."""
147180
148- known_results = (DeadHomepage , RedirectedHomepage , SSLCertificateError )
181+ known_results = (DeadHomepage , RedirectedHomepage , HttpsUrlAvailable , SSLCertificateError )
149182
150183 def __init__ (self , * args , ** kwargs ):
151184 super ().__init__ (* args , ** kwargs )
@@ -159,7 +192,7 @@ def _get_urls(self, pkg):
159192class FetchablesUrlCheck (_UrlCheck ):
160193 """Various SRC_URI related checks that require internet access."""
161194
162- known_results = (DeadSrcUrl , RedirectedSrcUrl , SSLCertificateError )
195+ known_results = (DeadSrcUrl , RedirectedSrcUrl , HttpsUrlAvailable , SSLCertificateError )
163196 required_addons = (addons .UseAddon ,)
164197
165198 def __init__ (self , options , iuse_handler ):
0 commit comments