35 lines
1.3 KiB
Python
35 lines
1.3 KiB
Python
|
import re
|
||
|
|
||
|
from semantic_version import Version
|
||
|
|
||
|
_USER_AGENT_SEARCH_REGEX = re.compile(r'docker\/([0-9]+(?:\.[0-9]+){1,2})')
|
||
|
_EXACT_1_5_USER_AGENT = re.compile(r'^Go 1\.1 package http$')
|
||
|
_ONE_FIVE_ZERO = '1.5.0'
|
||
|
|
||
|
def docker_version(user_agent_string):
|
||
|
""" Extract the Docker version from the user agent, taking special care to
|
||
|
handle the case of a 1.5 client requesting an auth token, which sends
|
||
|
a broken user agent. If we can not positively identify a version, return
|
||
|
None.
|
||
|
"""
|
||
|
|
||
|
# First search for a well defined semver portion in the UA header.
|
||
|
found_semver = _USER_AGENT_SEARCH_REGEX.search(user_agent_string)
|
||
|
if found_semver:
|
||
|
# Docker changed their versioning scheme on Feb 17, 2017 to use date-based versioning:
|
||
|
# https://github.com/docker/docker/pull/31075
|
||
|
|
||
|
# This scheme allows for 0s to appear as prefixes in the major or minor portions of the version,
|
||
|
# which violates semver. Strip them out.
|
||
|
portions = found_semver.group(1).split('.')
|
||
|
updated_portions = [(p[:-1].lstrip('0') + p[-1]) for p in portions]
|
||
|
return Version('.'.join(updated_portions), partial=True)
|
||
|
|
||
|
# Check if we received the very specific header which represents a 1.5 request
|
||
|
# to the auth endpoints.
|
||
|
elif _EXACT_1_5_USER_AGENT.match(user_agent_string):
|
||
|
return Version(_ONE_FIVE_ZERO)
|
||
|
|
||
|
else:
|
||
|
return None
|