diff --git a/component/apache/apache-backend.conf.in b/component/apache/apache-backend.conf.in index 32886fc860b3e7faca4575252d6707dc836384e7..ba3c291cadb1976382bb175909840ff8cb79f36b 100644 --- a/component/apache/apache-backend.conf.in +++ b/component/apache/apache-backend.conf.in @@ -102,6 +102,7 @@ LoadModule rewrite_module modules/mod_rewrite.so LoadModule headers_module modules/mod_headers.so LoadModule deflate_module modules/mod_deflate.so LoadModule filter_module modules/mod_filter.so +LoadModule reqtimeout_module modules/mod_reqtimeout.so AddOutputFilterByType DEFLATE text/cache-manifest text/html text/plain text/css application/hal+json application/json application/x-javascript text/xml application/xml application/rss+xml text/javascript image/svg+xml application/x-font-ttf application/font-woff application/font-woff2 application/x-font-opentype @@ -184,6 +185,7 @@ Listen {{ ip }}:{{ port }} Listen {{ ip }}:{{ port }} SSLEngine on + Timeout 3600 {% if enable_authentication and parameter_dict['ca-cert'] and parameter_dict['crl'] -%} SSLVerifyClient require SSLCACertificateFile {{ parameter_dict['ca-cert'] }} @@ -199,7 +201,7 @@ Listen {{ ip }}:{{ port }} {% endif -%} {% for path, backend in path_mapping.items() %} - RewriteRule ^/{{path}}(.*) {{ backend }}/VirtualHostBase/https/{{ ip }}:{{ port }}/VirtualHostRoot/_vh_{{ path }}$1 [L,P] + RewriteRule ^/{{path}}(.*) {{ backend }}/VirtualHostBase/https/{{ ip }}:{{ port }}/VirtualHostRoot/_vh_{{ path.replace('/', '/_vh_') }}$1 [L,P] {% endfor -%} {% endfor -%} \ No newline at end of file diff --git a/component/apache/buildout.hash.cfg b/component/apache/buildout.hash.cfg index 089abcf6ab4329e31d2b4385caaa20bb937198e3..7f0bc34c573e9c870a24a64543a120c059d9a7e6 100644 --- a/component/apache/buildout.hash.cfg +++ b/component/apache/buildout.hash.cfg @@ -14,5 +14,5 @@ # not need these here). [template-apache-backend-conf] filename = apache-backend.conf.in -md5sum = 3b430ca726a2707e1b6a2ae41a6c8e21 +md5sum = 8bbba80016d8a0bebef93282ded87cda diff --git a/component/egg-patch/Zope2/0001-SiteAccess-Make-VirtualHostMonster-support-IPv6.patch b/component/egg-patch/Zope2/0001-SiteAccess-Make-VirtualHostMonster-support-IPv6.patch new file mode 100644 index 0000000000000000000000000000000000000000..24162f9cdf894e38c56cb2ffbed9bf153cf14a3f --- /dev/null +++ b/component/egg-patch/Zope2/0001-SiteAccess-Make-VirtualHostMonster-support-IPv6.patch @@ -0,0 +1,110 @@ +From 4e4ffe940a8927abb0c0c8a2b704eb0a0218bf26 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?=C5=81ukasz=20Nowak?= +Date: Wed, 22 Aug 2018 03:23:47 +0200 +Subject: [PATCH] SiteAccess: Make VirtualHostMonster support IPv6 + +from https://bugs.launchpad.net/zope2/+bug/699865 : + +VirtualHostMonster does not work with IPv6 named hosts. + +In case of such rewrite configuration: + +RewriteRule (.*) http://10.0.243.129:9280/VirtualHostBase/https/[%{SERVER_ADDR}]:4080$1 [L,P] + +When SERVER_ADDR is fd00::74ba VirtualHostMonster dies with: + +Traceback (most recent call last): + File "/eggs/Zope2-2.12.14-py2.6-linux-x86_64.egg/ZPublisher/BeforeTraverse.py", line 145, in __call__ + meth(*(container, request, None)[:args]) + File "/eggs/Zope2-2.12.14-py2.6-linux-x86_64.egg/Products/SiteAccess/VirtualHostMonster.py", line 154, in __call__ + host, port = host.split(':') +ValueError: too many values to unpack + +This is because IPv6 addresses contain ":" in them. +--- + src/Products/SiteAccess/VirtualHostMonster.py | 7 +++- + .../SiteAccess/tests/testVirtualHostMonster.py | 43 ++++++++++++++++++++++ + 2 files changed, 49 insertions(+), 1 deletion(-) + +diff --git a/src/Products/SiteAccess/VirtualHostMonster.py b/src/Products/SiteAccess/VirtualHostMonster.py +index a455766be..c284df153 100644 +--- a/src/Products/SiteAccess/VirtualHostMonster.py ++++ b/src/Products/SiteAccess/VirtualHostMonster.py +@@ -151,7 +151,12 @@ class VirtualHostMonster(Persistent, Item, Implicit): + protocol = stack.pop() + host = stack.pop() + if ':' in host: +- host, port = host.split(':') ++ if host.startswith('['): ++ # IPv6 address passed ++ host, port = host.rsplit(':', 1) ++ else: ++ # Name or IPv4 address passed ++ host, port = host.split(':') + request.setServerURL(protocol, host, port) + else: + request.setServerURL(protocol, host) +diff --git a/src/Products/SiteAccess/tests/testVirtualHostMonster.py b/src/Products/SiteAccess/tests/testVirtualHostMonster.py +index 6a9e41815..32d7313ce 100644 +--- a/src/Products/SiteAccess/tests/testVirtualHostMonster.py ++++ b/src/Products/SiteAccess/tests/testVirtualHostMonster.py +@@ -139,6 +139,48 @@ for i, (vaddr, vr, _vh, p, ubase) in enumerate(gen_cases()): + + setattr(VHMRegressions, 'testTraverse%s' % i, test) + ++class VHMPort(unittest.TestCase): ++ ++ def setUp(self): ++ import transaction ++ from Testing.makerequest import makerequest ++ from Testing.ZopeTestCase.ZopeLite import app ++ transaction.begin() ++ self.app = makerequest(app()) ++ if 'virtual_hosting' not in self.app.objectIds(): ++ # If ZopeLite was imported, we have no default virtual ++ # host monster ++ from Products.SiteAccess.VirtualHostMonster \ ++ import manage_addVirtualHostMonster ++ manage_addVirtualHostMonster(self.app, 'virtual_hosting') ++ self.app.manage_addFolder('folder') ++ self.app.folder.manage_addDTMLMethod('doc', '') ++ self.app.REQUEST.set('PARENTS', [self.app]) ++ self.traverse = self.app.REQUEST.traverse ++ ++ def tearDown(self): ++ import transaction ++ transaction.abort() ++ self.app._p_jar.close() ++ ++ def testPassedPort(self): ++ ob = self.traverse('/VirtualHostBase/http/www.mysite.com:81' ++ '/folder/') ++ self.assertEqual(self.app.REQUEST['ACTUAL_URL'], ++ 'http://www.mysite.com:81/folder/') ++ ++ def testIPv6(self): ++ ob = self.traverse('/VirtualHostBase/http/[::1]:80' ++ '/folder/') ++ self.assertEqual(self.app.REQUEST['ACTUAL_URL'], ++ 'http://[::1]/folder/') ++ ++ def testIPv6PassedPort(self): ++ ob = self.traverse('/VirtualHostBase/http/[::1]:81' ++ '/folder/') ++ self.assertEqual(self.app.REQUEST['ACTUAL_URL'], ++ 'http://[::1]:81/folder/') ++ + + class VHMAddingTests(unittest.TestCase): + +@@ -200,6 +242,7 @@ class VHMAddingTests(unittest.TestCase): + + def test_suite(): + suite = unittest.TestSuite() ++ suite.addTest(unittest.makeSuite(VHMPort)) + suite.addTest(unittest.makeSuite(VHMRegressions)) + suite.addTest(unittest.makeSuite(VHMAddingTests)) + return suite +-- +2.11.0 + diff --git a/stack/erp5/buildout.cfg b/stack/erp5/buildout.cfg index 392700b180e9465249884513258089f735bd3c1b..79462d4e61e5083d22a6c3877ae8c54bfe52f6f4 100644 --- a/stack/erp5/buildout.cfg +++ b/stack/erp5/buildout.cfg @@ -591,6 +591,8 @@ extra-paths = patch-binary = ${patch:location}/bin/patch Acquisition-patches = ${:_profile_base_location_}/../../component/egg-patch/Acquisition/aq_dynamic.patch#1d9a56e9af4371f5b6951ebf217a15d7 Acquisition-patch-options = -p1 +Zope2-patches = ${:_profile_base_location_}/../../component/egg-patch/Zope2/0001-SiteAccess-Make-VirtualHostMonster-support-IPv6.patch#5b8a5f7e4e4d418ae3eab43390506972 +Zope2-patch-options = -p1 Products.DCWorkflow-patches = ${:_profile_base_location_}/../../component/egg-patch/Products.DCWorkflow/workflow_method.patch#975b49e96bae33ac8563454fe5fa9899 Products.DCWorkflow-patch-options = -p1 python-magic-patches = ${:_profile_base_location_}/../../component/egg-patch/python_magic/magic.patch#de0839bffac17801e39b60873a6c2068 @@ -634,6 +636,7 @@ scripts += # patched eggs Acquisition = 2.13.12+SlapOSPatched001 Products.DCWorkflow = 2.2.4+SlapOSPatched001 +Zope2 = 2.13.28+SlapOSPatched001 ocropy = 1.0+SlapOSPatched001 pysvn = 1.7.10+SlapOSPatched002 python-ldap = 2.4.32+SlapOSPatched001 diff --git a/stack/erp5/buildout.hash.cfg b/stack/erp5/buildout.hash.cfg index 1192f40948e69a393d4b881409446516f86af75d..0d133fd86a6bd957f8de6d7ba41fffe199b89555 100644 --- a/stack/erp5/buildout.hash.cfg +++ b/stack/erp5/buildout.hash.cfg @@ -86,7 +86,7 @@ md5sum = d1257e7e942307be0a79e34aa4320e9f [template-balancer] filename = instance-balancer.cfg.in -md5sum = f0fd49c7d6d9f7c6936afba0d18b7691 +md5sum = 384d6f167836e98944860fb62158c4c7 [template-haproxy-cfg] filename = haproxy.cfg.in diff --git a/stack/erp5/instance-balancer.cfg.in b/stack/erp5/instance-balancer.cfg.in index bd869a016fe92ff160a57a055f2be462240fa799..05abf6eacd2728891d48c6edf158819e3bc0bd05 100644 --- a/stack/erp5/instance-balancer.cfg.in +++ b/stack/erp5/instance-balancer.cfg.in @@ -99,6 +99,7 @@ ipv4 = {{ ipv4 }} {% set apache_dict = {} -%} {% set zope_virtualhost_monster_backend_dict = {} %} {% set test_runner_url_dict = {} %} {# family_name => list of apache URLs #} +{% set direct_zope_url_dict = {} %} {# family_name => list of apache URLs #} {% set next_port = itertools.count(slapparameter_dict['tcpv4-port']).next -%} {% for family_name, parameter_id_list in sorted( slapparameter_dict['zope-family-dict'].iteritems()) -%} @@ -163,6 +164,18 @@ ipv6 = {{ zope_address.split(']:')[0][1:] }} {% set external_scheme = 'https' -%} {% endif -%} {% do apache_dict.__setitem__(family_name, (next_port(), external_scheme, internal_scheme ~ '://' ~ ipv4 ~ ':' ~ haproxy_port ~ backend_path, ssl_authentication)) -%} + +{# Direct access to backend zopes. #} +{% set external_port = next_port() %} +{% set direct_zope_url_list = [] %} +{% set direct_zope_backend_mapping = {} %} +{% for i, (zope_family_address, _, _) in enumerate(zope_family_address_list) %} +{% do direct_zope_url_list.append('https://[' ~ ipv6 ~ ']:' ~ external_port ~ '/' ~ family_name ~ '/zope-' ~ i ) %} +{% do direct_zope_backend_mapping.__setitem__(family_name ~ '/zope-' ~ i, 'http://' ~ zope_family_address ) %} +{% endfor -%} +{% do zope_virtualhost_monster_backend_dict.__setitem__(('[' ~ ipv6 ~ ']', external_port), (ssl_authentication, direct_zope_backend_mapping) ) -%} +{% do direct_zope_url_dict.__setitem__(family_name, direct_zope_url_list) %} + {% endfor -%} [haproxy-cfg-parameter-dict] @@ -250,6 +263,10 @@ recipe = slapos.cookbook:publish.serialised {% for family_name, test_runner_url_list in test_runner_url_dict.items() -%} {{ family_name ~ '-test-runner-url-list' }} = {{ dumps(test_runner_url_list) }} {% endfor -%} +{% for family_name, direct_zope_url_list in direct_zope_url_dict.items() -%} +{{ family_name ~ '-direct-zope-url-list' }} = {{ dumps(direct_zope_url_list) }} +{% endfor -%} + monitor-base-url = ${monitor-publish-parameters:monitor-base-url}