Skip to content
Snippets Groups Projects
Commit 6d53c50e authored by slobinger's avatar slobinger
Browse files

Merge branch '20-enable-api-proxy-rootpath' into 'master'

Resolve "Basis-Pfad (/) bei API über Proxy nicht aufrufbar"

Closes #20

See merge request !15
parents eadcf56c 46dc81c6
No related branches found
No related tags found
1 merge request!15Resolve "Basis-Pfad (/) bei API über Proxy nicht aufrufbar"
Pipeline #
python3-sams-classes (1.0.1~1) UNRELEASED; urgency=medium
* fixed issue #20 "Basis-Pfad (/) bei API über Proxy nicht aufrufbar"
-- Lobinger <slobinger@justus.zib.de> Tue, 13 Jun 2017 15:28:43 +0200
python3-sams-classes (1.0.0) unstable; urgency=medium python3-sams-classes (1.0.0) unstable; urgency=medium
* Initial Release. * Initial Release.
-- Sebastian Lobinger <sebastian.lobinger@zib.de> Thu, 08 Jun 2017 10:42:38 +0200 -- Sebastian Lobinger <sebastian.lobinger@zib.de> Thu, 08 Jun 2017 10:42:38 +0200
\ No newline at end of file
...@@ -46,14 +46,18 @@ class SAMSApp: ...@@ -46,14 +46,18 @@ class SAMSApp:
endpoint = '_'.join(view['function'].split('.')) endpoint = '_'.join(view['function'].split('.'))
view_func = SAMSApp._get_attr(self.module, view['function']) view_func = SAMSApp._get_attr(self.module, view['function'])
self.__blueprint.add_url_rule( self.__blueprint.add_url_rule(
rule = self._generate_url(view.get('url')), endpoint = endpoint, rule = self._generate_url(urlPart = view.get('url')), endpoint = endpoint,
view_func = view_func) view_func = view_func)
def __add_proxy_urls(self): def __add_proxy_urls(self):
i = 0 i = 0
for proxy in self.proxies: for proxy in self.proxies:
self.__blueprint.add_url_rule( self.__blueprint.add_url_rule(
rule = self._generate_url(proxy.urlRule), rule = self._generate_url(urlPart = proxy.urlRule),
endpoint = self.__blueprint.name.replace('.', '_') + '_proxy_' + str(i),
view_func = proxy.proxy)
self.__blueprint.add_url_rule(
rule = self._generate_url(urlPart = proxy.rootUrlRule),
endpoint = self.__blueprint.name.replace('.', '_') + '_proxy_' + str(i), endpoint = self.__blueprint.name.replace('.', '_') + '_proxy_' + str(i),
view_func = proxy.proxy) view_func = proxy.proxy)
i += 1 i += 1
...@@ -107,15 +111,12 @@ class SAMSApp: ...@@ -107,15 +111,12 @@ class SAMSApp:
return entries return entries
def _generate_url( def _generate_url(
self, urlPrefix: str, urlPart: str = '', external = False ) -> str: self, urlPrefix: str = '', urlPart: str = '', external = False ) -> str:
if external: if external:
return urlPart return urlPart
urlPrefix = urlPrefix.strip('/') urlPrefix = urlPrefix.strip('/')
urlPart = urlPart.strip('/') urlPart = urlPart.lstrip('/')
urlElements = [] url = '/'.join([urlPrefix, urlPart])
if urlPrefix: if url[0] != '/':
urlElements.append(urlPrefix) url = '/' + url
if urlPart: return url
urlElements.append(urlPart) \ No newline at end of file
url = '/'.join(urlElements)
return '/' + url if (not url) or (url[0] is not '/') else url
\ No newline at end of file
...@@ -22,8 +22,16 @@ class SAMSProxy: ...@@ -22,8 +22,16 @@ class SAMSProxy:
if 0 == len(self._proxySpec['in']): if 0 == len(self._proxySpec['in']):
return '/<path:path>' return '/<path:path>'
return '/' + urlRule + '/<path:path>' return '/' + urlRule + '/<path:path>'
@property
def rootUrlRule(self):
urlRule = self._proxySpec['in'].strip()
urlRule = urlRule.strip('/')
if 0 == len(self._proxySpec['in']):
return '/'
return '/' + urlRule + '/'
def proxy(self, path): def proxy(self, path = ''):
url = '/'.join([self._proxySpec['out'].strip().rstrip('/'), path]) url = '/'.join([self._proxySpec['out'].strip().rstrip('/'), path])
headers = SAMSProxy.__cleaned_dict(request.headers) headers = SAMSProxy.__cleaned_dict(request.headers)
headers.pop('Content-Type', None) headers.pop('Content-Type', None)
......
...@@ -21,4 +21,9 @@ def passthrough(): ...@@ -21,4 +21,9 @@ def passthrough():
body = request.get_json() body = request.get_json()
output = json.dumps( output = json.dumps(
{'url': request.args, 'body': body, 'header': dict(request.headers)}) {'url': request.args, 'body': body, 'header': dict(request.headers)})
return output return output
\ No newline at end of file
@app.route('/', methods = [
'GET', 'POST', 'DELETE', 'UPDATE', 'PATCH', 'OPTIONS', 'PUT', 'HEAD'])
def rootpath():
return 'rootpath'
\ No newline at end of file
...@@ -153,7 +153,7 @@ class TestSAMSApp(unittest.TestCase): ...@@ -153,7 +153,7 @@ class TestSAMSApp(unittest.TestCase):
app = SAMSApp(name = 'test', manifest = manifest app = SAMSApp(name = 'test', manifest = manifest
, langDict = {'en': langDict}) , langDict = {'en': langDict})
menu = app.menu(langCode = 'en', urlPrefix = '/test') menu = app.menu(langCode = 'en', urlPrefix = '/test')
self.assertEqual(menu[0]['url'], '/test') self.assertEqual(menu[0]['url'], '/test/')
self.assertEqual(menu[1]['url'], '/test/1') self.assertEqual(menu[1]['url'], '/test/1')
def test_app_menu_external_urls(self): def test_app_menu_external_urls(self):
...@@ -168,7 +168,7 @@ class TestSAMSApp(unittest.TestCase): ...@@ -168,7 +168,7 @@ class TestSAMSApp(unittest.TestCase):
app = SAMSApp(name = 'test', manifest = manifest app = SAMSApp(name = 'test', manifest = manifest
, langDict = {'en': langDict}) , langDict = {'en': langDict})
menu = app.menu(langCode = 'en', urlPrefix = '/test') menu = app.menu(langCode = 'en', urlPrefix = '/test')
self.assertEqual(menu[0]['url'], '/test') self.assertEqual(menu[0]['url'], '/test/')
self.assertEqual(menu[1]['url'], 'http://zib.de') self.assertEqual(menu[1]['url'], 'http://zib.de')
def test_app_proxies_list(self): def test_app_proxies_list(self):
...@@ -218,10 +218,11 @@ class TestSAMSAppWithThreadedApi(unittest.TestCase): ...@@ -218,10 +218,11 @@ class TestSAMSAppWithThreadedApi(unittest.TestCase):
) )
self.flaskApp.register_blueprint(testApp.blueprint) self.flaskApp.register_blueprint(testApp.blueprint)
self.assertGreater(len(list(self.flaskApp.url_map.iter_rules())), 1) self.assertGreater(len(list(self.flaskApp.url_map.iter_rules())), 1)
eprint(self.flaskApp.url_map) for path in ('/api/hello', '/api/'):
with self.flaskApp.test_client(self) as client: with self.subTest(path):
response = client.get('/api/hello') with self.flaskApp.test_client(self) as client:
self.assertIs(response.status_code, 200) response = client.get(path)
self.assertIs(response.status_code, 200)
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()
\ No newline at end of file
...@@ -68,6 +68,9 @@ class TestSAMSHubWithThreadedAPI(unittest.TestCase): ...@@ -68,6 +68,9 @@ class TestSAMSHubWithThreadedAPI(unittest.TestCase):
time.sleep(0.01) time.sleep(0.01)
self.proxyApp = Flask('test') self.proxyApp = Flask('test')
self.proxyApp.config['TESTING'] = True self.proxyApp.config['TESTING'] = True
self.basic_url_rule_params = {'endpoint': 'proxy',
'methods': ['GET', 'POST', 'PUT', 'UPDATE', 'PATCH', 'DELETE', 'OPTIONS']}
self.url_rule_properties = ['rootUrlRule', 'urlRule']
def tearDown(self): def tearDown(self):
response = requests.get('http://localhost:4711/shutdown') response = requests.get('http://localhost:4711/shutdown')
...@@ -78,9 +81,9 @@ class TestSAMSHubWithThreadedAPI(unittest.TestCase): ...@@ -78,9 +81,9 @@ class TestSAMSHubWithThreadedAPI(unittest.TestCase):
"""The proxy passes json data """ """The proxy passes json data """
proxy = SAMSProxy( proxy = SAMSProxy(
proxySpec = {'in': '/proxy', 'out': 'http://localhost:4711'}) proxySpec = {'in': '/proxy', 'out': 'http://localhost:4711'})
self.proxyApp.add_url_rule(rule = proxy.urlRule, endpoint = 'proxy', for urlRuleProp in self.url_rule_properties:
view_func = proxy.proxy, methods=['GET', 'POST', 'PUT', 'UPDATE', self.proxyApp.add_url_rule(rule = getattr(proxy, urlRuleProp),
'PATCH', 'DELETE', 'OPTIONS']) view_func = proxy.proxy, **self.basic_url_rule_params)
thProxyApp = FlaskInThread(self.proxyApp, host="localhost", port=5000) thProxyApp = FlaskInThread(self.proxyApp, host="localhost", port=5000)
thProxyApp.start() thProxyApp.start()
time.sleep(0.01) time.sleep(0.01)
...@@ -99,9 +102,9 @@ class TestSAMSHubWithThreadedAPI(unittest.TestCase): ...@@ -99,9 +102,9 @@ class TestSAMSHubWithThreadedAPI(unittest.TestCase):
'user': {'name': 'u','param-type': 'url'}, 'user': {'name': 'u','param-type': 'url'},
'group': {'name': 'g', 'param-type': 'body'}, 'group': {'name': 'g', 'param-type': 'body'},
'language': {'name': 'Lang', 'param-type': 'header'}}}}) 'language': {'name': 'Lang', 'param-type': 'header'}}}})
self.proxyApp.add_url_rule(rule = proxy.urlRule, endpoint = 'proxy', for urlRuleProp in self.url_rule_properties:
view_func = proxy.proxy, methods=['GET', 'POST', 'PUT', 'UPDATE', self.proxyApp.add_url_rule(rule = getattr(proxy, urlRuleProp),
'PATCH', 'DELETE', 'OPTIONS']) view_func = proxy.proxy, **self.basic_url_rule_params)
self.proxyApp.secret_key = 'A0Zr98j/3yX R~XHH!jmN]LWX/,?RT' self.proxyApp.secret_key = 'A0Zr98j/3yX R~XHH!jmN]LWX/,?RT'
with self.proxyApp.test_client(self) as client: with self.proxyApp.test_client(self) as client:
with client.session_transaction() as sess: with client.session_transaction() as sess:
...@@ -125,9 +128,9 @@ class TestSAMSHubWithThreadedAPI(unittest.TestCase): ...@@ -125,9 +128,9 @@ class TestSAMSHubWithThreadedAPI(unittest.TestCase):
'user': {'name': 'u','param-type': 'url'}, 'user': {'name': 'u','param-type': 'url'},
'group': {'name': 'g', 'param-type': 'body'}, 'group': {'name': 'g', 'param-type': 'body'},
'language': {'name': 'lang', 'param-type': 'header'}}}}) 'language': {'name': 'lang', 'param-type': 'header'}}}})
self.proxyApp.add_url_rule(rule = proxy.urlRule, endpoint = 'proxy', for urlRuleProp in self.url_rule_properties:
view_func = proxy.proxy, methods=['GET', 'POST', 'PUT', 'UPDATE', self.proxyApp.add_url_rule(rule = getattr(proxy, urlRuleProp),
'PATCH', 'DELETE', 'OPTIONS']) view_func = proxy.proxy, **self.basic_url_rule_params)
self.proxyApp.secret_key = 'A0Zr98j/3yX R~XHH!jmN]LWX/,?RT' self.proxyApp.secret_key = 'A0Zr98j/3yX R~XHH!jmN]LWX/,?RT'
with self.proxyApp.test_client(self) as client: with self.proxyApp.test_client(self) as client:
with client.session_transaction() as sess: with client.session_transaction() as sess:
...@@ -152,9 +155,9 @@ class TestSAMSHubWithThreadedAPI(unittest.TestCase): ...@@ -152,9 +155,9 @@ class TestSAMSHubWithThreadedAPI(unittest.TestCase):
'user': {'name': 'u','param-type': 'url'}, 'user': {'name': 'u','param-type': 'url'},
'group': {'name': 'g', 'param-type': 'body'}, 'group': {'name': 'g', 'param-type': 'body'},
'language': {'name': 'lang', 'param-type': 'header'}}}}) 'language': {'name': 'lang', 'param-type': 'header'}}}})
self.proxyApp.add_url_rule(rule = proxy.urlRule, endpoint = 'proxy', for urlRuleProp in self.url_rule_properties:
view_func = proxy.proxy, methods=['GET', 'POST', 'PUT', 'UPDATE', self.proxyApp.add_url_rule(rule = getattr(proxy, urlRuleProp),
'PATCH', 'DELETE', 'OPTIONS']) view_func = proxy.proxy, **self.basic_url_rule_params)
self.proxyApp.secret_key = 'A0Zr98j/3yX R~XHH!jmN]LWX/,?RT' self.proxyApp.secret_key = 'A0Zr98j/3yX R~XHH!jmN]LWX/,?RT'
with self.proxyApp.test_client(self) as client: with self.proxyApp.test_client(self) as client:
with client.session_transaction() as sess: with client.session_transaction() as sess:
...@@ -171,23 +174,25 @@ class TestSAMSHubWithThreadedAPI(unittest.TestCase): ...@@ -171,23 +174,25 @@ class TestSAMSHubWithThreadedAPI(unittest.TestCase):
""" The proxy forwards a request to test flaskapp and returns 'hello' """ """ The proxy forwards a request to test flaskapp and returns 'hello' """
proxy = SAMSProxy( proxy = SAMSProxy(
proxySpec = {'in': '/proxy', 'out': 'http://localhost:4711'}) proxySpec = {'in': '/proxy', 'out': 'http://localhost:4711'})
self.proxyApp.add_url_rule(rule = proxy.urlRule, endpoint = 'proxy', for urlRuleProp in self.url_rule_properties:
view_func = proxy.proxy, methods=['GET', 'POST', 'PUT', 'UPDATE', self.proxyApp.add_url_rule(rule = getattr(proxy, urlRuleProp),
'PATCH', 'DELETE', 'OPTIONS']) view_func = proxy.proxy, **self.basic_url_rule_params)
with self.proxyApp.test_client(self) as client: with self.proxyApp.test_client(self) as client:
eprint(self.proxyApp.url_map)
for method in ['get', 'post', 'put', 'update', 'patch', 'delete', for method in ['get', 'post', 'put', 'update', 'patch', 'delete',
'options']: 'options']:
response = client.open(path='/proxy/hello', method=method.upper()) for path in ('/proxy/hello', '/proxy/'):
self.assertIs(response.status_code, 200, method) response = client.open(path = path, method = method.upper())
self.assertEqual(response.data.decode('utf-8'), method + ' hello') with self.subTest('method ' + method + ' path ' + path):
self.assertIs(response.status_code, 200, method)
def test_param_passthrough(self): def test_param_passthrough(self):
"""The proxy passes headers, form / data and url params """ """The proxy passes headers, form / data and url params """
proxy = SAMSProxy( proxy = SAMSProxy(
proxySpec = {'in': '/proxy', 'out': 'http://localhost:4711'}) proxySpec = {'in': '/proxy', 'out': 'http://localhost:4711'})
self.proxyApp.add_url_rule(rule = proxy.urlRule, endpoint = 'proxy', for urlRuleProp in self.url_rule_properties:
view_func = proxy.proxy, methods=['GET', 'POST', 'PUT', 'UPDATE', self.proxyApp.add_url_rule(rule = getattr(proxy, urlRuleProp),
'PATCH', 'DELETE', 'OPTIONS']) view_func = proxy.proxy, **self.basic_url_rule_params)
with self.proxyApp.test_client(self) as client: with self.proxyApp.test_client(self) as client:
res = client.get(path='/proxy/passthrough', res = client.get(path='/proxy/passthrough',
query_string={'u':'foo'}, data={'g':'bar'}, headers={'lang': 'klingon'}) query_string={'u':'foo'}, data={'g':'bar'}, headers={'lang': 'klingon'})
...@@ -214,6 +219,9 @@ class TestSAMSHubWithThreadedAPI(unittest.TestCase): ...@@ -214,6 +219,9 @@ class TestSAMSHubWithThreadedAPI(unittest.TestCase):
proxyApp.add_url_rule(rule = proxy.urlRule, endpoint = 'proxy', proxyApp.add_url_rule(rule = proxy.urlRule, endpoint = 'proxy',
view_func = proxy.proxy, methods=['GET', 'POST', 'PUT', 'UPDATE', view_func = proxy.proxy, methods=['GET', 'POST', 'PUT', 'UPDATE',
'PATCH', 'DELETE', 'OPTIONS']) 'PATCH', 'DELETE', 'OPTIONS'])
proxyApp.add_url_rule(rule = proxy.rootUrlRule, endpoint = 'proxy',
view_func = proxy.proxy, methods=['GET', 'POST', 'PUT', 'UPDATE',
'PATCH', 'DELETE', 'OPTIONS'])
with proxyApp.test_client(self) as client: with proxyApp.test_client(self) as client:
res = client.get(path='/proxy/passthrough', res = client.get(path='/proxy/passthrough',
query_string={'u':'foo'}, data={'g':'bar'}, query_string={'u':'foo'}, data={'g':'bar'},
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment