Commit 31d98e59 authored by Giorgos Korfiatis's avatar Giorgos Korfiatis

common: Strip trailing slash from endpoints

Remove trailing slash from the endpoints' publicURL field in service
definitions. These values end up in the response of POST /tokens, and,
according to the keystone API, should not end in slash. A trailing slash
breaks some clients, which do no proper checking before appending a
suffix.

Note that these URLs are not meant to act as a base path in the strict
semantics of http://tools.ietf.org/html/rfc3986#section-5.2.3 . Suffixes
should be merged into by a simple append (modulo catering for the joining
slash).

URLs are still configured as groups per prefix ending in a slash, eg:
'^account/' and '^ui/'. Permanent redirects are added for all non-API
endpoints (ui, helpdesk, admin, etc), so that `BASE_PATH/path' leads to
`BASE_PATH/path/'.
parent 1ed354f2
......@@ -6,6 +6,8 @@ The upgrade from v0.14.2 to v0.14.6 consists of the following step:
1. Set default container quota policy to unlimited for the containers
created prior to 0.14
2. Re-register services in astakos
1. Set default container quota policy to unlimited in old containers
====================================================================
......@@ -25,3 +27,16 @@ The upgrade from v0.14.2 to v0.14.6 consists of the following step:
In order to massively change the quota of ``images`` container
(in all the accounts)::
$ pithos-manage-accounts set-container-quota images 0
2. Re-register services in astakos
==================================
Service definitions have changed; you will thus need to register their new
version. In astakos node, run::
astakos-host$ snf-component-register
This will detect that the Synnefo components are already registered and ask
to update the registered services. Answer positively. You need to enter the
base URL for each component; give the same value as in the initial
registration.
......@@ -36,8 +36,15 @@ from synnefo.lib import join_urls
from astakos.im.settings import (
BASE_PATH, ACCOUNTS_PREFIX, VIEWS_PREFIX, KEYSTONE_PREFIX, WEBLOGIN_PREFIX)
from snf_django.lib.api.utils import prefix_pattern
from snf_django.utils.urls import extend_with_root_redirects
from astakos.im import settings
from snf_django.utils.urls import \
extend_with_root_redirects, extend_endpoint_with_slash
from astakos.im.settings import astakos_services
urlpatterns = []
# Redirects should be first, otherwise they may get overridden by wildcards
extend_endpoint_with_slash(urlpatterns, astakos_services, 'astakos_ui')
extend_endpoint_with_slash(urlpatterns, astakos_services, 'astakos_weblogin')
astakos_patterns = patterns(
'',
......@@ -48,11 +55,11 @@ astakos_patterns = patterns(
)
urlpatterns = patterns(
urlpatterns += patterns(
'',
(prefix_pattern(BASE_PATH), include(astakos_patterns)),
)
# set utility redirects
extend_with_root_redirects(urlpatterns, settings.astakos_services,
extend_with_root_redirects(urlpatterns, astakos_services,
'astakos_ui', BASE_PATH)
......@@ -47,7 +47,7 @@ def fill_endpoints(services, base_url):
if publicURL is not None:
continue
publicURL = join_urls(base_url, prefix, version).rstrip('/') + '/'
publicURL = join_urls(base_url, prefix, version).rstrip('/')
set_path(endpoint, 'publicURL', publicURL)
......@@ -84,4 +84,4 @@ def get_public_endpoint(services, service_type, version=None):
def get_service_path(services, service_type, version=None):
service_url = get_public_endpoint(services, service_type, version=version)
return urlparse(service_url).path.rstrip('/') + '/'
return urlparse(service_url).path.rstrip('/')
......@@ -45,7 +45,7 @@ class APITest(TestCase):
path = get_service_path(cyclades_services,
'compute', version='v2.0')
with astakos_user('user'):
response = self.client.get(path)
response = self.client.get(path.rstrip('/') + '/')
self.assertEqual(response.status_code, 200)
api_version = json.loads(response.content)['version']
self.assertEqual(api_version['id'], 'v2.0')
......
......@@ -35,7 +35,8 @@ from django.conf.urls.defaults import *
from django.conf import settings
from snf_django.lib.api.proxy import proxy
from snf_django.lib.api.utils import prefix_pattern
from snf_django.utils.urls import extend_with_root_redirects
from snf_django.utils.urls import \
extend_with_root_redirects, extend_endpoint_with_slash
from snf_django.lib.api.urls import api_patterns
from synnefo.cyclades_settings import (
BASE_URL, BASE_HOST, BASE_PATH, COMPUTE_PREFIX, VMAPI_PREFIX,
......@@ -47,6 +48,14 @@ from synnefo.cyclades_settings import (
from functools import partial
urlpatterns = []
# Redirects should be first, otherwise they may get overridden by wildcards
extend_endpoint_with_slash(urlpatterns, cyclades_services, 'cyclades_ui')
extend_endpoint_with_slash(urlpatterns, cyclades_services, 'cyclades_helpdesk')
extend_endpoint_with_slash(urlpatterns, cyclades_services, 'admin')
extend_endpoint_with_slash(urlpatterns, cyclades_services, 'cyclades_userdata')
astakos_proxy = partial(proxy, proxy_base=BASE_ASTAKOS_PROXY_PATH,
target_base=ASTAKOS_BASE_URL)
......@@ -63,7 +72,7 @@ cyclades_patterns += patterns('',
(prefix_pattern(HELPDESK_PREFIX), include('synnefo.helpdesk.urls')),
)
urlpatterns = patterns(
urlpatterns += patterns(
'',
(prefix_pattern(BASE_PATH), include(cyclades_patterns)),
)
......
......@@ -107,10 +107,10 @@ def get_request_dict(request):
raise faults.BadRequest("Unsupported Content-type: '%s'" % content_type)
def prefix_pattern(prefix):
def prefix_pattern(prefix, append_slash=True):
"""Return a reliable urls.py pattern from a prefix"""
prefix = prefix.strip('/')
if prefix:
if prefix and append_slash:
prefix += '/'
pattern = '^' + prefix
return pattern
......@@ -34,12 +34,25 @@
from django.conf.urls.defaults import url, patterns
from snf_django.lib.api.utils import prefix_pattern
from synnefo.lib.services import get_public_endpoint
from synnefo.lib.services import get_service_path
from synnefo.lib import join_urls
def extend_path_with_slash(patterns_obj, path):
if not path.endswith('/'):
pattern = prefix_pattern(path, append_slash=False) + '$'
entry = url(pattern, 'redirect_to', {'url': path + '/'})
patterns_obj += patterns('django.views.generic.simple', entry)
def extend_endpoint_with_slash(patterns_obj, filled_services, service_type,
version=None):
path = get_service_path(filled_services, service_type, version)
extend_path_with_slash(patterns_obj, path)
def extend_with_root_redirects(patterns_obj, filled_services, service_type,
base_path):
base_path, with_slash=True):
"""
Append additional redirect url entries for `/` and `/<base_path>` paths.
......@@ -50,7 +63,10 @@ def extend_with_root_redirects(patterns_obj, filled_services, service_type,
redirects to the chosen service url.
"""
service_url = get_public_endpoint(filled_services, service_type)
service_path = get_service_path(filled_services, service_type)
if with_slash:
service_path = service_path.rstrip('/') + '/'
root_url_entry = None
if base_path and base_path != '/':
# redirect slash to /<base_path>/
......@@ -61,11 +77,11 @@ def extend_with_root_redirects(patterns_obj, filled_services, service_type,
base_path_pattern = prefix_pattern(base_path) + '$'
base_path_pattern_no_slash = prefix_pattern(base_path).rstrip('/') + '$'
# redirect /<base_path> and /<base_path>/ to service_url public endpoint
# redirect /<base_path> and /<base_path>/ to service_path public endpoint
base_url_entry = url(base_path_pattern, 'redirect_to', {'url':
service_url})
service_path})
base_url_entry_no_slash = url(base_path_pattern_no_slash,
'redirect_to', {'url': service_url})
'redirect_to', {'url': service_path})
# urls order matter. Setting base_url_entry first allows us to avoid
# redirect loops when base_path is empty or `/`
patterns_obj += patterns('django.views.generic.simple',
......
......@@ -37,12 +37,20 @@ from snf_django.lib.api.proxy import proxy
from snf_django.lib.api.utils import prefix_pattern
from snf_django.lib.api.urls import api_patterns
from snf_django.lib.api import api_endpoint_not_found
from snf_django.utils.urls import extend_endpoint_with_slash
from pithos.api.settings import (
pithos_services,
BASE_PATH, ASTAKOS_BASE_URL, BASE_ASTAKOS_PROXY_PATH,
ASTAKOS_ACCOUNTS_PREFIX, PROXY_USER_SERVICES,
PITHOS_PREFIX, PUBLIC_PREFIX, UI_PREFIX)
urlpatterns = []
# Redirects should be first, otherwise they may get overridden by wildcards
extend_endpoint_with_slash(urlpatterns, pithos_services, "pithos_ui")
extend_endpoint_with_slash(urlpatterns, pithos_services, "pithos_public")
# TODO: This only works when in this order.
pithos_api_patterns = api_patterns(
'pithos.api.functions',
......@@ -69,7 +77,7 @@ pithos_patterns = patterns(
(r'{0}'.format(prefix_pattern(UI_PREFIX)),
include(pithos_view_patterns)))
urlpatterns = patterns(
urlpatterns += patterns(
'',
(prefix_pattern(BASE_PATH), include(pithos_patterns)),
)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment