1
0
mirror of https://github.com/openSUSE/osc.git synced 2025-02-04 18:46:17 +01:00

Merge pull request #145 from OlegGirko/api-fix-root-path

Add support for non-root paths in API URLs.
This commit is contained in:
Adrian Schröter 2015-08-13 07:52:35 +02:00
commit f9e54d0488
2 changed files with 41 additions and 24 deletions

View File

@ -382,17 +382,17 @@ cookiejar = None
def parse_apisrv_url(scheme, apisrv): def parse_apisrv_url(scheme, apisrv):
if apisrv.startswith('http://') or apisrv.startswith('https://'): if apisrv.startswith('http://') or apisrv.startswith('https://'):
return urlsplit(apisrv)[0:2] return urlsplit(apisrv)[0:3]
elif scheme != None: elif scheme != None:
# the split/join is needed to get a proper url (e.g. without a trailing slash) # the split/join is needed to get a proper url (e.g. without a trailing slash)
return urlsplit(urljoin(scheme, apisrv))[0:2] return urlsplit(urljoin(scheme, apisrv))[0:3]
else: else:
msg = 'invalid apiurl \'%s\' (specify the protocol (http:// or https://))' % apisrv msg = 'invalid apiurl \'%s\' (specify the protocol (http:// or https://))' % apisrv
raise URLError(msg) raise URLError(msg)
def urljoin(scheme, apisrv): def urljoin(scheme, apisrv, path=''):
return '://'.join([scheme, apisrv]) return '://'.join([scheme, apisrv]) + path
def is_known_apiurl(url): def is_known_apiurl(url):
@ -401,6 +401,21 @@ def is_known_apiurl(url):
return apiurl in config['api_host_options'] return apiurl in config['api_host_options']
def extract_known_apiurl(url):
"""
Return longest prefix of given url that is known apiurl,
None if there is no known apiurl that is prefix of given url.
"""
scheme, host, path = parse_apisrv_url(None, url)
p = path.split('/')
while p:
apiurl = urljoin(scheme, host, '/'.join(p))
if apiurl in config['api_host_options']:
return apiurl
p.pop()
return None
def get_apiurl_api_host_options(apiurl): def get_apiurl_api_host_options(apiurl):
""" """
Returns all apihost specific options for the given apiurl, None if Returns all apihost specific options for the given apiurl, None if
@ -441,10 +456,9 @@ def get_apiurl_usr(apiurl):
# So we need to build a new opener everytime we switch the # So we need to build a new opener everytime we switch the
# apiurl (because different apiurls may have different # apiurl (because different apiurls may have different
# cafile/capath locations) # cafile/capath locations)
def _build_opener(url): def _build_opener(apiurl):
from osc.core import __version__ from osc.core import __version__
global config global config
apiurl = urljoin(*parse_apisrv_url(None, url))
if 'last_opener' not in _build_opener.__dict__: if 'last_opener' not in _build_opener.__dict__:
_build_opener.last_opener = (None, None) _build_opener.last_opener = (None, None)
if apiurl == _build_opener.last_opener[0]: if apiurl == _build_opener.last_opener[0]:
@ -644,18 +658,18 @@ def config_set_option(section, opt, val=None, delete=False, update=True, **kwarg
general_opts = [i for i in DEFAULTS.keys() if not i in ['user', 'pass', 'passx']] general_opts = [i for i in DEFAULTS.keys() if not i in ['user', 'pass', 'passx']]
if section != 'general': if section != 'general':
section = config['apiurl_aliases'].get(section, section) section = config['apiurl_aliases'].get(section, section)
scheme, host = \ scheme, host, path = \
parse_apisrv_url(config.get('scheme', 'https'), section) parse_apisrv_url(config.get('scheme', 'https'), section)
section = urljoin(scheme, host) section = urljoin(scheme, host, path)
sections = {} sections = {}
for url in cp.sections(): for url in cp.sections():
if url == 'general': if url == 'general':
sections[url] = url sections[url] = url
else: else:
scheme, host = \ scheme, host, path = \
parse_apisrv_url(config.get('scheme', 'https'), url) parse_apisrv_url(config.get('scheme', 'https'), url)
apiurl = urljoin(scheme, host) apiurl = urljoin(scheme, host, path)
sections[apiurl] = url sections[apiurl] = url
section = sections.get(section.rstrip('/'), section) section = sections.get(section.rstrip('/'), section)
@ -702,19 +716,20 @@ def write_initial_config(conffile, entries, custom_template=''):
config.update(entries) config.update(entries)
# at this point use_keyring and gnome_keyring are str objects # at this point use_keyring and gnome_keyring are str objects
if config['use_keyring'] == '1' and GENERIC_KEYRING: if config['use_keyring'] == '1' and GENERIC_KEYRING:
protocol, host = \ protocol, host, path = \
parse_apisrv_url(None, config['apiurl']) parse_apisrv_url(None, config['apiurl'])
keyring.set_password(host, config['user'], config['pass']) keyring.set_password(host, config['user'], config['pass'])
config['pass'] = '' config['pass'] = ''
config['passx'] = '' config['passx'] = ''
elif config['gnome_keyring'] == '1' and GNOME_KEYRING: elif config['gnome_keyring'] == '1' and GNOME_KEYRING:
protocol, host = \ protocol, host, path = \
parse_apisrv_url(None, config['apiurl']) parse_apisrv_url(None, config['apiurl'])
gnomekeyring.set_network_password_sync( gnomekeyring.set_network_password_sync(
user=config['user'], user=config['user'],
password=config['pass'], password=config['pass'],
protocol=protocol, protocol=protocol,
server=host) server=host,
object=path)
config['user'] = '' config['user'] = ''
config['pass'] = '' config['pass'] = ''
config['passx'] = '' config['passx'] = ''
@ -741,19 +756,20 @@ def add_section(filename, url, user, passwd):
# Section might have existed, but was empty # Section might have existed, but was empty
pass pass
if config['use_keyring'] and GENERIC_KEYRING: if config['use_keyring'] and GENERIC_KEYRING:
protocol, host = parse_apisrv_url(None, url) protocol, host, path = parse_apisrv_url(None, url)
keyring.set_password(host, user, passwd) keyring.set_password(host, user, passwd)
cp.set(url, 'keyring', '1') cp.set(url, 'keyring', '1')
cp.set(url, 'user', user) cp.set(url, 'user', user)
cp.remove_option(url, 'pass') cp.remove_option(url, 'pass')
cp.remove_option(url, 'passx') cp.remove_option(url, 'passx')
elif config['gnome_keyring'] and GNOME_KEYRING: elif config['gnome_keyring'] and GNOME_KEYRING:
protocol, host = parse_apisrv_url(None, url) protocol, host, path = parse_apisrv_url(None, url)
gnomekeyring.set_network_password_sync( gnomekeyring.set_network_password_sync(
user=user, user=user,
password=passwd, password=passwd,
protocol=protocol, protocol=protocol,
server=host) server=host,
object=path)
cp.set(url, 'keyring', '1') cp.set(url, 'keyring', '1')
cp.remove_option(url, 'pass') cp.remove_option(url, 'pass')
cp.remove_option(url, 'passx') cp.remove_option(url, 'passx')
@ -836,8 +852,8 @@ def get_config(override_conffile=None,
aliases = {} aliases = {}
for url in [x for x in cp.sections() if x != 'general']: for url in [x for x in cp.sections() if x != 'general']:
# backward compatiblity # backward compatiblity
scheme, host = parse_apisrv_url(config.get('scheme', 'https'), url) scheme, host, path = parse_apisrv_url(config.get('scheme', 'https'), url)
apiurl = urljoin(scheme, host) apiurl = urljoin(scheme, host, path)
user = None user = None
password = None password = None
if config['use_keyring'] and GENERIC_KEYRING: if config['use_keyring'] and GENERIC_KEYRING:
@ -851,7 +867,7 @@ def get_config(override_conffile=None,
elif config['gnome_keyring'] and GNOME_KEYRING: elif config['gnome_keyring'] and GNOME_KEYRING:
# Read from gnome keyring if available # Read from gnome keyring if available
try: try:
gk_data = gnomekeyring.find_network_password_sync(protocol=scheme, server=host) gk_data = gnomekeyring.find_network_password_sync(protocol=scheme, server=host, object=path)
if not 'user' in gk_data[0]: if not 'user' in gk_data[0]:
raise oscerr.ConfigError('no user found in keyring', conffile) raise oscerr.ConfigError('no user found in keyring', conffile)
user = gk_data[0]['user'] user = gk_data[0]['user']

View File

@ -3148,8 +3148,8 @@ def makeurl(baseurl, l, query=[]):
elif isinstance(query, type(dict())): elif isinstance(query, type(dict())):
query = urlencode(query) query = urlencode(query)
scheme, netloc = urlsplit(baseurl)[0:2] scheme, netloc, path = urlsplit(baseurl)[0:3]
return urlunsplit((scheme, netloc, '/'.join(l), query, '')) return urlunsplit((scheme, netloc, '/'.join([path] + l), query, ''))
def http_request(method, url, headers={}, data=None, file=None): def http_request(method, url, headers={}, data=None, file=None):
@ -3174,10 +3174,11 @@ def http_request(method, url, headers={}, data=None, file=None):
req = URLRequest(url) req = URLRequest(url)
api_host_options = {} api_host_options = {}
if conf.is_known_apiurl(url): apiurl = conf.extract_known_apiurl(url)
if apiurl is not None:
# ok no external request # ok no external request
install_opener(conf._build_opener(url)) install_opener(conf._build_opener(apiurl))
api_host_options = conf.get_apiurl_api_host_options(url) api_host_options = conf.get_apiurl_api_host_options(apiurl)
for header, value in api_host_options['http_headers']: for header, value in api_host_options['http_headers']:
req.add_header(header, value) req.add_header(header, value)