You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by co...@apache.org on 2026/09/29 09:08:43 UTC
svn commit: r1938684 - httpd/httpd/trunk/test/modules/dav
Author: covener
Date: Tue Sep 29 09:08:43 2026
New Revision: 1938684
Log:
add dav tests for r1938681
Added:
httpd/httpd/trunk/test/modules/dav/
httpd/httpd/trunk/test/modules/dav/__init__.py
httpd/httpd/trunk/test/modules/dav/conftest.py
httpd/httpd/trunk/test/modules/dav/env.py
httpd/httpd/trunk/test/modules/dav/test_001_propdb_ns_limit.py
Added: httpd/httpd/trunk/test/modules/dav/__init__.py
==============================================================================
Added: httpd/httpd/trunk/test/modules/dav/conftest.py
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ httpd/httpd/trunk/test/modules/dav/conftest.py Tue Sep 29 09:08:43 2026 (r1938684)
@@ -0,0 +1,36 @@
+import logging
+import os
+
+import pytest
+import sys
+
+from .env import DavTestEnv
+from pyhttpd.env import HttpdTestEnv
+
+sys.path.append(os.path.join(os.path.dirname(__file__), '../..'))
+
+
+def pytest_report_header(config, start_path):
+ env = DavTestEnv()
+ return f"dav [apache: {env.get_httpd_version()}, mpm: {env.mpm_module}, {env.prefix}]"
+
+
+@pytest.fixture(scope="package")
+def env(pytestconfig) -> DavTestEnv:
+ level = logging.INFO
+ console = logging.StreamHandler()
+ console.setLevel(level)
+ console.setFormatter(logging.Formatter('%(levelname)s: %(message)s'))
+ logging.getLogger('').addHandler(console)
+ logging.getLogger('').setLevel(level=level)
+ env = DavTestEnv(pytestconfig=pytestconfig)
+ env.setup_httpd()
+ env.apache_access_log_clear()
+ env.httpd_error_log.clear_log()
+ return env
+
+
+@pytest.fixture(autouse=True, scope="package")
+def _stop_package_scope(env):
+ yield
+ assert env.apache_stop() == 0
Added: httpd/httpd/trunk/test/modules/dav/env.py
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ httpd/httpd/trunk/test/modules/dav/env.py Tue Sep 29 09:08:43 2026 (r1938684)
@@ -0,0 +1,25 @@
+import inspect
+import logging
+import os
+
+from pyhttpd.env import HttpdTestEnv, HttpdTestSetup
+
+log = logging.getLogger(__name__)
+
+
+class DavTestSetup(HttpdTestSetup):
+
+ def __init__(self, env: 'HttpdTestEnv'):
+ super().__init__(env=env)
+ self.add_source_dir(os.path.dirname(inspect.getfile(DavTestSetup)))
+ self.add_modules(["dav", "dav_fs", "alias"])
+
+
+class DavTestEnv(HttpdTestEnv):
+
+ def __init__(self, pytestconfig=None):
+ super().__init__(pytestconfig=pytestconfig)
+ self.add_httpd_log_modules(["dav", "dav_fs"])
+
+ def setup_httpd(self, setup: HttpdTestSetup = None):
+ super().setup_httpd(setup=DavTestSetup(env=self))
Added: httpd/httpd/trunk/test/modules/dav/test_001_propdb_ns_limit.py
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ httpd/httpd/trunk/test/modules/dav/test_001_propdb_ns_limit.py Tue Sep 29 09:08:43 2026 (r1938684)
@@ -0,0 +1,72 @@
+import os
+import pytest
+
+from pyhttpd.conf import HttpdConf
+
+
+class TestPropdbNsLimit:
+
+ @pytest.fixture(autouse=True, scope='class')
+ def _class_scope(self, env):
+ dav_dir = os.path.join(env.gen_dir, 'dav')
+ os.makedirs(dav_dir, exist_ok=True)
+ with open(os.path.join(dav_dir, 'file.txt'), 'w') as fd:
+ fd.write('hello\n')
+ conf = HttpdConf(env, extras={
+ 'base': f"""
+ DavLockDB "{env.gen_dir}/davlock"
+ """,
+ f"test1.{env.http_tld}": f"""
+ Alias /dav "{dav_dir}"
+ <Directory "{dav_dir}">
+ Dav On
+ Require all granted
+ </Directory>
+ """,
+ })
+ conf.add_vhost_test1()
+ conf.install()
+ assert env.apache_restart() == 0
+
+ @staticmethod
+ def _propertyupdate(nspaces: int, prefix: str) -> str:
+ # every xmlns declaration in a PROPPATCH body is recorded in the
+ # resource's property database, whether or not it is used
+ decls = ''.join(f' xmlns:{prefix}{i}="urn:{prefix}{i}"'
+ for i in range(nspaces))
+ return ('<?xml version="1.0"?>'
+ f'<D:propertyupdate xmlns:D="DAV:"{decls}>'
+ f'<D:set><D:prop><{prefix}0:p>v</{prefix}0:p></D:prop></D:set>'
+ '</D:propertyupdate>')
+
+ def _proppatch(self, env, body: str):
+ fpath = os.path.join(env.gen_dir, 'proppatch.xml')
+ with open(fpath, 'w') as fd:
+ fd.write(body)
+ url = env.mkurl("https", "test1", "/dav/file.txt")
+ return env.curl_raw(url, options=[
+ '-X', 'PROPPATCH', '-H', 'Content-Type: text/xml',
+ '--data-binary', f'@{fpath}'])
+
+ # a modest number of distinct namespaces is accepted and stored
+ def test_dav_001_01(self, env):
+ r = self._proppatch(env, self._propertyupdate(100, 'a'))
+ assert r.response["status"] == 207
+ assert 'HTTP/1.1 200' in r.stdout
+ assert 'HTTP/1.1 413' not in r.stdout
+
+ # declaring more distinct namespaces than one property database will
+ # record must be refused with 413 rather than accepted, and the resource
+ # must remain usable afterwards
+ def test_dav_001_02(self, env):
+ r = self._proppatch(env, self._propertyupdate(2049, 'b'))
+ # the refusal is logged at error level, and writing back the
+ # oversized namespace table on close fails with a warning
+ env.httpd_error_log.ignore_recent(
+ lognos=['AH00577'],
+ matches=[r'.*Too many distinct namespaces'])
+ assert r.response["status"] == 207
+ assert 'HTTP/1.1 413' in r.stdout
+ url = env.mkurl("https", "test1", "/dav/file.txt")
+ r = env.curl_raw(url, options=['-X', 'PROPFIND', '-H', 'Depth: 0'])
+ assert r.response["status"] == 207