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