diff --git a/docs/usage.rst b/docs/usage.rst index 56c88e2..4054805 100644 --- a/docs/usage.rst +++ b/docs/usage.rst @@ -235,6 +235,34 @@ regex This source supports :ref:`list options`. +Search in an HTTP header +~~~~~~~~~~~~~~~~~~~~~~~~ +:: + + source = "httpheader" + +Send an HTTP request and search through a specific header. + +url + The URL of the HTTP request. + +header + (*Optional*) The header to look at. Default is ``Location``. Another useful header is ``Content-Disposition``. + +regex + A regular expression used to find the version string. + + It can have zero or one capture group. The capture group or the whole match is the version string. + + When multiple version strings are found, the maximum of those is chosen. + +method + (*Optional*) The HTTP method to use. Default is ``HEAD``. + +follow_redirects + (*Optional*) Whether to follow 3xx HTTP redirects. Default is ``false``. If you are looking at a ``Location`` header, you shouldn't change this. + + Find with a Command ~~~~~~~~~~~~~~~~~~~ :: diff --git a/nvchecker_source/httpheader.py b/nvchecker_source/httpheader.py new file mode 100644 index 0000000..57feb46 --- /dev/null +++ b/nvchecker_source/httpheader.py @@ -0,0 +1,39 @@ +# MIT licensed +# Copyright (c) 2021 lilydjwg , et al. + +import re +import sre_constants + +from nvchecker.api import session, GetVersionError + +async def get_version(name, conf, *, cache, **kwargs): + key = tuple(sorted(conf.items())) + return await cache.get(key, get_version_impl) + +async def get_version_impl(info): + conf = dict(info) + url = conf['url'] + header = conf.get('header', 'Location') + follow_redirects = conf.get('follow_redirects', False) + method = conf.get('method', 'HEAD') + + try: + regex = re.compile(conf['regex']) + except sre_constants.error as e: + raise GetVersionError('bad regex', exc_info=e) + + res = await session.request( + url, + method = method, + follow_redirects = follow_redirects, + ) + + header_value = res.headers.get(header) + if not header_value: + raise GetVersionError('header %s not found or is empty' % header) + + try: + version = regex.findall(header_value) + except ValueError: + raise GetVersionError('version string not found.') + return version diff --git a/nvchecker_source/regex.py b/nvchecker_source/regex.py index b71dce6..0828d4d 100644 --- a/nvchecker_source/regex.py +++ b/nvchecker_source/regex.py @@ -25,7 +25,6 @@ async def get_version_impl(info): try: version = regex.findall(body) except ValueError: - version = None if not conf.get('missing_ok', False): raise GetVersionError('version string not found.') return version diff --git a/tests/test_httpheader.py b/tests/test_httpheader.py new file mode 100644 index 0000000..d8e7a14 --- /dev/null +++ b/tests/test_httpheader.py @@ -0,0 +1,14 @@ +# MIT licensed +# Copyright (c) 2021 lilydjwg , et al. + +import pytest + +pytestmark = pytest.mark.asyncio + +async def test_redirection(get_version): + assert await get_version("jmeter-plugins-manager", { + "source": "httpheader", + "url": "https://jmeter-plugins.org/get/", + "regex": r'/([\d.]+)/', + }) == "1.6" +