launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #22579
[Merge] lp:~cjwatson/launchpad/cveimport-requests into lp:launchpad
Colin Watson has proposed merging lp:~cjwatson/launchpad/cveimport-requests into lp:launchpad with lp:~cjwatson/launchpad/bugs-remote-finders-requests as a prerequisite.
Commit message:
Convert update-cve to urlfetch with explicit proxy configuration.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~cjwatson/launchpad/cveimport-requests/+merge/347201
--
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~cjwatson/launchpad/cveimport-requests into lp:launchpad.
=== modified file 'constraints.txt'
--- constraints.txt 2018-05-31 13:40:28 +0000
+++ constraints.txt 2018-05-31 13:40:28 +0000
@@ -336,6 +336,7 @@
PyYAML==3.10
rabbitfixture==0.3.6
requests==2.7.0
+requests-file==1.4.3
requests-toolbelt==0.6.2
responses==0.9.0
scandir==1.7
=== modified file 'lib/lp/bugs/scripts/cveimport.py'
--- lib/lp/bugs/scripts/cveimport.py 2016-08-16 15:33:02 +0000
+++ lib/lp/bugs/scripts/cveimport.py 2018-05-31 13:40:28 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2018 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""A set of functions related to the ability to parse the XML CVE database,
@@ -10,9 +10,9 @@
import gzip
import StringIO
import time
-import urllib2
import xml.etree.cElementTree as cElementTree
+import requests
from zope.component import getUtility
from zope.event import notify
from zope.interface import implementer
@@ -31,6 +31,10 @@
LaunchpadCronScript,
LaunchpadScriptFailure,
)
+from lp.services.timeout import (
+ override_timeout,
+ urlfetch,
+ )
CVEDB_NS = '{http://cve.mitre.org/cve/downloads/1.0}'
@@ -209,14 +213,22 @@
elif self.options.cveurl is not None:
self.logger.info("Downloading CVE database from %s..." %
self.options.cveurl)
+ proxies = {}
+ if config.launchpad.http_proxy:
+ proxies['http'] = config.launchpad.http_proxy
+ proxies['https'] = config.launchpad.http_proxy
try:
- url = urllib2.urlopen(self.options.cveurl)
- except (urllib2.HTTPError, urllib2.URLError):
+ with override_timeout(config.cveupdater.timeout):
+ # Command-line options are trusted, so allow file://
+ # URLs to ease testing.
+ response = urlfetch(
+ self.options.cveurl, proxies=proxies, allow_file=True)
+ except requests.RequestException:
raise LaunchpadScriptFailure(
'Unable to connect for CVE database %s'
% self.options.cveurl)
- cve_db_gz = url.read()
+ cve_db_gz = response.content
self.logger.info("%d bytes downloaded." % len(cve_db_gz))
cve_db = gzip.GzipFile(
fileobj=StringIO.StringIO(cve_db_gz)).read()
=== modified file 'lib/lp/services/config/schema-lazr.conf'
--- lib/lp/services/config/schema-lazr.conf 2018-05-31 13:40:28 +0000
+++ lib/lp/services/config/schema-lazr.conf 2018-05-31 13:40:28 +0000
@@ -490,6 +490,9 @@
# datatype: string
cve_db_url: https://cve.mitre.org/data/downloads/allitems.xml.gz
+# datatype: integer
+timeout: 30
+
[database]
# Connection strings, format as per the PQconnectdb connection string as
=== modified file 'lib/lp/services/tests/test_timeout.py'
--- lib/lp/services/tests/test_timeout.py 2018-05-31 13:40:28 +0000
+++ lib/lp/services/tests/test_timeout.py 2018-05-31 13:40:28 +0000
@@ -15,12 +15,18 @@
import threading
import xmlrpclib
+from fixtures import TempDir
from requests.exceptions import (
ConnectionError,
InvalidSchema,
)
-from testtools.matchers import MatchesStructure
+from testtools.matchers import (
+ ContainsDict,
+ Equals,
+ MatchesStructure,
+ )
+from lp.services.osutils import write_file
from lp.services.timeout import (
default_timeout,
get_default_timeout_function,
@@ -365,6 +371,29 @@
self.assertEqual(
"No connection adapters were found for '%s'" % url, str(e))
+ def test_urlfetch_does_not_support_file_urls_by_default(self):
+ """urlfetch() does not support file urls by default."""
+ set_default_timeout_function(lambda: 1)
+ self.addCleanup(set_default_timeout_function, None)
+ test_path = self.useFixture(TempDir()).join('file')
+ write_file(test_path, '')
+ url = 'file://' + test_path
+ e = self.assertRaises(InvalidSchema, urlfetch, url)
+ self.assertEqual(
+ "No connection adapters were found for '%s'" % url, str(e))
+
+ def test_urlfetch_supports_file_urls_if_allow_file(self):
+ """urlfetch() supports file urls if explicitly asked to do so."""
+ set_default_timeout_function(lambda: 1)
+ self.addCleanup(set_default_timeout_function, None)
+ test_path = self.useFixture(TempDir()).join('file')
+ write_file(test_path, 'Success.')
+ url = 'file://' + test_path
+ self.assertThat(urlfetch(url, allow_file=True), MatchesStructure(
+ status_code=Equals(200),
+ headers=ContainsDict({'Content-Length': Equals(8)}),
+ content=Equals('Success.')))
+
def test_xmlrpc_transport(self):
""" Another use case for timeouts is communicating with external
systems using XMLRPC. In order to allow timeouts using XMLRPC we
=== modified file 'lib/lp/services/timeout.py'
--- lib/lp/services/timeout.py 2018-05-31 13:40:28 +0000
+++ lib/lp/services/timeout.py 2018-05-31 13:40:28 +0000
@@ -40,6 +40,7 @@
)
from requests.packages.urllib3.exceptions import ClosedPoolError
from requests.packages.urllib3.poolmanager import PoolManager
+from requests_file import FileAdapter
from six import reraise
@@ -316,21 +317,29 @@
class URLFetcher:
"""Object fetching remote URLs with a time out."""
- @staticmethod
- def _makeSession(trust_env=None):
- session = Session()
+ @with_timeout(cleanup='cleanup')
+ def fetch(self, url, trust_env=None, allow_file=False, **request_kwargs):
+ """Fetch the URL using a custom HTTP handler supporting timeout.
+
+ :param url: The URL to fetch.
+ :param trust_env: If not None, set the session's trust_env to this
+ to determine whether it fetches proxy configuration from the
+ environment.
+ :param allow_file: If True, allow file:// URLs. (Be careful to only
+ pass this if the URL is trusted.)
+ :param request_kwargs: Additional keyword arguments passed on to
+ `Session.request`.
+ """
+ self.session = Session()
if trust_env is not None:
- session.trust_env = trust_env
+ self.session.trust_env = trust_env
# Mount our custom adapters.
- session.mount("https://", CleanableHTTPAdapter())
- session.mount("http://", CleanableHTTPAdapter())
- return session
+ self.session.mount("https://", CleanableHTTPAdapter())
+ self.session.mount("http://", CleanableHTTPAdapter())
+ if allow_file:
+ self.session.mount("file://", FileAdapter())
- @with_timeout(cleanup='cleanup')
- def fetch(self, url, trust_env=None, **request_kwargs):
- """Fetch the URL using a custom HTTP handler supporting timeout."""
request_kwargs.setdefault("method", "GET")
- self.session = self._makeSession(trust_env=trust_env)
response = self.session.request(url=url, **request_kwargs)
response.raise_for_status()
# Make sure the content has been consumed before returning.
=== modified file 'setup.py'
--- setup.py 2018-05-31 13:40:28 +0000
+++ setup.py 2018-05-31 13:40:28 +0000
@@ -207,6 +207,7 @@
'PyYAML',
'rabbitfixture',
'requests',
+ 'requests-file',
'requests-toolbelt',
'responses',
'scandir',
Follow ups