]> git.ipfire.org Git - thirdparty/apache/httpd.git/commitdiff
test: port recent httpd-tests 2.4.68 changes to pytest_suite
authorJim Jagielski <jim@apache.org>
Fri, 5 Jun 2026 17:48:53 +0000 (17:48 +0000)
committerJim Jagielski <jim@apache.org>
Fri, 5 Jun 2026 17:48:53 +0000 (17:48 +0000)
Reflect the following t/ changes into test/pytest_suite:

* expr: file()/filesize() are restricted in 2.4.68+; gate the
  expected results (None => parse error 500) and move file()
  into the 2.3.13 block.
* mod_headers: support an optional expected-status field; add
  malformed-regex -> 500 and 2.4.68 file()-in-htaccess -> 500.
* mod_dav: PUT to a .DAV state subdir is blocked (403) in
  2.4.68+, else 201.
* mod_proxy_html: add multi-substitution buffer-realloc tests
  (literal and regex) with ProxyHTMLBufSize 256.

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1935044 13f79535-47bb-0310-9956-ffa450edef68

test/pytest_suite/t/conf/proxy.conf.in
test/pytest_suite/t/htdocs/modules/proxy_html/multi_subst.html [new file with mode: 0644]
test/pytest_suite/t/htdocs/modules/proxy_html/multi_subst_rx.html [new file with mode: 0644]
test/pytest_suite/tests/t/apache/test_expr.py
test/pytest_suite/tests/t/modules/test_dav.py
test/pytest_suite/tests/t/modules/test_headers.py
test/pytest_suite/tests/t/modules/test_proxy_html.py

index 37c76e651e173433174c2debeb7c95564df669e8..3025038a4945befbd797ff5f7824140ac45e10de 100644 (file)
@@ -338,6 +338,28 @@ Alias /modules/proxy/fcgi-uds-sethandler @SERVERROOT@/htdocs/modules/proxy/fcgi
             ProxyPass http://@SERVERNAME@:@PORT@/modules/proxy_html
         </Location>
 
+        # Multi-substitution buffer reallocation test
+        <Location /modules/html_proxy/multi_subst>
+            ProxyHTMLEnable on
+            ProxyHTMLExtended on
+            ProxyHTMLLinks a href
+            ProxyHTMLEvents onclick
+            ProxyHTMLBufSize 256
+            ProxyHTMLURLMap http://x/ http://long-rewritten-path.example.com/
+            ProxyPass http://@SERVERNAME@:@PORT@/modules/proxy_html
+        </Location>
+
+        # Multi-substitution regex buffer test
+        <Location /modules/html_proxy/multi_subst_rx>
+            ProxyHTMLEnable on
+            ProxyHTMLExtended on
+            ProxyHTMLLinks a href
+            ProxyHTMLEvents onclick
+            ProxyHTMLBufSize 256
+            ProxyHTMLURLMap "http://rx/" "http://regex-rewritten-path.example.com/" R
+            ProxyPass http://@SERVERNAME@:@PORT@/modules/proxy_html
+        </Location>
+
         # Multiple URL maps test
         <Location /modules/html_proxy/multiple_maps>
             ProxyHTMLEnable on
diff --git a/test/pytest_suite/t/htdocs/modules/proxy_html/multi_subst.html b/test/pytest_suite/t/htdocs/modules/proxy_html/multi_subst.html
new file mode 100644 (file)
index 0000000..0598dba
--- /dev/null
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head><title>Multi-substitution buffer test</title></head>
+<body>
+<script>
+var u01='http://x/u01';var u02='http://x/u02';var u03='http://x/u03';var u04='http://x/u04';var u05='http://x/u05';var u06='http://x/u06';var u07='http://x/u07';var u08='http://x/u08';var u09='http://x/u09';var u10='http://x/u10';var u11='http://x/u11';var u12='http://x/u12';var u13='http://x/u13';var u14='http://x/u14';var u15='http://x/u15';var u16='http://x/u16';var u17='http://x/u17';var u18='http://x/u18';var u19='http://x/u19';var u20='http://x/u20';var u21='http://x/u21';var u22='http://x/u22';var u23='http://x/u23';var u24='http://x/u24';var u25='http://x/u25';var u26='http://x/u26';var u27='http://x/u27';var u28='http://x/u28';var u29='http://x/u29';var u30='http://x/u30';var u31='http://x/u31';var u32='http://x/u32';var u33='http://x/u33';var u34='http://x/u34';var u35='http://x/u35';var u36='http://x/u36';var u37='http://x/u37';var u38='http://x/u38';var u39='http://x/u39';var u40='http://x/u40';var sentinel='CDATA_END_OK';
+</script>
+<a href="#" onclick="f('http://x/v01','http://x/v02','http://x/v03','http://x/v04','http://x/v05','http://x/v06','http://x/v07','http://x/v08','http://x/v09','http://x/v10','http://x/v11','http://x/v12','http://x/v13','http://x/v14','http://x/v15','http://x/v16','http://x/v17','http://x/v18','http://x/v19','http://x/v20','http://x/v21','http://x/v22','http://x/v23','http://x/v24','http://x/v25','http://x/v26','http://x/v27','http://x/v28','http://x/v29','http://x/v30','http://x/v31','http://x/v32','http://x/v33','http://x/v34','http://x/v35','http://x/v36','http://x/v37','http://x/v38','http://x/v39','http://x/v40','EVENT_END_OK')">test</a>
+</body>
+</html>
+<!DOCTYPE html>
+<html>
+<head><title>Multi-substitution buffer test</title></head>
+<body>
+<script>
+var u01='http://x/u01';var u02='http://x/u02';var u03='http://x/u03';var u04='http://x/u04';var u05='http://x/u05';var u06='http://x/u06';var u07='http://x/u07';var u08='http://x/u08';var u09='http://x/u09';var u10='http://x/u10';var u11='http://x/u11';var u12='http://x/u12';var u13='http://x/u13';var u14='http://x/u14';var u15='http://x/u15';var u16='http://x/u16';var u17='http://x/u17';var u18='http://x/u18';var u19='http://x/u19';var u20='http://x/u20';var u21='http://x/u21';var u22='http://x/u22';var u23='http://x/u23';var u24='http://x/u24';var u25='http://x/u25';var u26='http://x/u26';var u27='http://x/u27';var u28='http://x/u28';var u29='http://x/u29';var u30='http://x/u30';var u31='http://x/u31';var u32='http://x/u32';var u33='http://x/u33';var u34='http://x/u34';var u35='http://x/u35';var u36='http://x/u36';var u37='http://x/u37';var u38='http://x/u38';var u39='http://x/u39';var u40='http://x/u40';var sentinel='CDATA_END_OK';
+</script>
+<a href="#" onclick="f('http://x/v01','http://x/v02','http://x/v03','http://x/v04','http://x/v05','http://x/v06','http://x/v07','http://x/v08','http://x/v09','http://x/v10','http://x/v11','http://x/v12','http://x/v13','http://x/v14','http://x/v15','http://x/v16','http://x/v17','http://x/v18','http://x/v19','http://x/v20','http://x/v21','http://x/v22','http://x/v23','http://x/v24','http://x/v25','http://x/v26','http://x/v27','http://x/v28','http://x/v29','http://x/v30','http://x/v31','http://x/v32','http://x/v33','http://x/v34','http://x/v35','http://x/v36','http://x/v37','http://x/v38','http://x/v39','http://x/v40','EVENT_END_OK')">test</a>
+</body>
+</html>
diff --git a/test/pytest_suite/t/htdocs/modules/proxy_html/multi_subst_rx.html b/test/pytest_suite/t/htdocs/modules/proxy_html/multi_subst_rx.html
new file mode 100644 (file)
index 0000000..1d838df
--- /dev/null
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head><title>Multi-substitution regex buffer test</title></head>
+<body>
+<script>
+var u01='http://rx/u01';var u02='http://rx/u02';var u03='http://rx/u03';var u04='http://rx/u04';var u05='http://rx/u05';var u06='http://rx/u06';var u07='http://rx/u07';var u08='http://rx/u08';var u09='http://rx/u09';var u10='http://rx/u10';var u11='http://rx/u11';var u12='http://rx/u12';var u13='http://rx/u13';var u14='http://rx/u14';var u15='http://rx/u15';var u16='http://rx/u16';var u17='http://rx/u17';var u18='http://rx/u18';var u19='http://rx/u19';var u20='http://rx/u20';var u21='http://rx/u21';var u22='http://rx/u22';var u23='http://rx/u23';var u24='http://rx/u24';var u25='http://rx/u25';var u26='http://rx/u26';var u27='http://rx/u27';var u28='http://rx/u28';var u29='http://rx/u29';var u30='http://rx/u30';var u31='http://rx/u31';var u32='http://rx/u32';var u33='http://rx/u33';var u34='http://rx/u34';var u35='http://rx/u35';var u36='http://rx/u36';var u37='http://rx/u37';var u38='http://rx/u38';var u39='http://rx/u39';var u40='http://rx/u40';var sentinel='RX_CDATA_END_OK';
+</script>
+<a href="#" onclick="f('http://rx/v01','http://rx/v02','http://rx/v03','http://rx/v04','http://rx/v05','http://rx/v06','http://rx/v07','http://rx/v08','http://rx/v09','http://rx/v10','http://rx/v11','http://rx/v12','http://rx/v13','http://rx/v14','http://rx/v15','http://rx/v16','http://rx/v17','http://rx/v18','http://rx/v19','http://rx/v20','http://rx/v21','http://rx/v22','http://rx/v23','http://rx/v24','http://rx/v25','http://rx/v26','http://rx/v27','http://rx/v28','http://rx/v29','http://rx/v30','http://rx/v31','http://rx/v32','http://rx/v33','http://rx/v34','http://rx/v35','http://rx/v36','http://rx/v37','http://rx/v38','http://rx/v39','http://rx/v40','RX_EVENT_END_OK')">test</a>
+</body>
+</html>
+<!DOCTYPE html>
+<html>
+<head><title>Multi-substitution regex buffer test</title></head>
+<body>
+<script>
+var u01='http://rx/u01';var u02='http://rx/u02';var u03='http://rx/u03';var u04='http://rx/u04';var u05='http://rx/u05';var u06='http://rx/u06';var u07='http://rx/u07';var u08='http://rx/u08';var u09='http://rx/u09';var u10='http://rx/u10';var u11='http://rx/u11';var u12='http://rx/u12';var u13='http://rx/u13';var u14='http://rx/u14';var u15='http://rx/u15';var u16='http://rx/u16';var u17='http://rx/u17';var u18='http://rx/u18';var u19='http://rx/u19';var u20='http://rx/u20';var u21='http://rx/u21';var u22='http://rx/u22';var u23='http://rx/u23';var u24='http://rx/u24';var u25='http://rx/u25';var u26='http://rx/u26';var u27='http://rx/u27';var u28='http://rx/u28';var u29='http://rx/u29';var u30='http://rx/u30';var u31='http://rx/u31';var u32='http://rx/u32';var u33='http://rx/u33';var u34='http://rx/u34';var u35='http://rx/u35';var u36='http://rx/u36';var u37='http://rx/u37';var u38='http://rx/u38';var u39='http://rx/u39';var u40='http://rx/u40';var sentinel='RX_CDATA_END_OK';
+</script>
+<a href="#" onclick="f('http://rx/v01','http://rx/v02','http://rx/v03','http://rx/v04','http://rx/v05','http://rx/v06','http://rx/v07','http://rx/v08','http://rx/v09','http://rx/v10','http://rx/v11','http://rx/v12','http://rx/v13','http://rx/v14','http://rx/v15','http://rx/v16','http://rx/v17','http://rx/v18','http://rx/v19','http://rx/v20','http://rx/v21','http://rx/v22','http://rx/v23','http://rx/v24','http://rx/v25','http://rx/v26','http://rx/v27','http://rx/v28','http://rx/v29','http://rx/v30','http://rx/v31','http://rx/v32','http://rx/v33','http://rx/v34','http://rx/v35','http://rx/v36','http://rx/v37','http://rx/v38','http://rx/v39','http://rx/v40','RX_EVENT_END_OK')">test</a>
+</body>
+</html>
index 388a7d1f3dcb557b7f323984f4ef1fb2afa6591c..6169440a07058a6ccf5cd32d805ff31877228692 100644 (file)
@@ -202,13 +202,15 @@ def _build_cases(http):
     url_foo = "/apache/"
     url_notexist = "/apache/expr/none"
 
-    cases.append((rf"file('{file_foo}') = 'foo\n' ", 1))
-
     if http.have_min_apache_version("2.3.13"):
+        # file() and filesize() are restricted in 2.4.68+ (e.g. in .htaccess
+        # context), turning these into parse errors (None => expect 500).
+        restrict2 = None if http.have_min_apache_version("2.4.68") else 1
         cases += [
-            (f"filesize('{file_foo}') = 4 ", 1),
-            (f"filesize('{file_notexist}') = 0 ", 1),
-            (f"filesize('{file_zero}') = 0 ", 1),
+            (f"filesize('{file_foo}') = 4 ", restrict2),
+            (f"filesize('{file_notexist}') = 0 ", restrict2),
+            (f"filesize('{file_zero}') = 0 ", restrict2),
+            (rf"file('{file_foo}') = 'foo\n' ", restrict2),
             (f"-d '{file_foo}' ", 0),
             (f"-e '{file_foo}' ", 1),
             (f"-f '{file_foo}' ", 1),
index 82e36d9df7533b2d5319df5296eabc8c75d3772c..aed5fd26f790fb313b08dd51456064e259508df4 100644 (file)
@@ -186,7 +186,20 @@ def test_dav(http):
         assert resp.status_code == 400, \
             f"PR 49825: expect 400 bad request, got {resp.status_code}"
 
+    # PUT to a .DAV state subdirectory should be blocked (403) in 2.4.68+,
+    # else allowed (201).
+    dav_uri = f"/{DIR}/.DAV/test.html"
+    expected = 403 if http.have_min_apache_version("2.4.68") else 201
+    with httpx.Client(timeout=30.0) as c:
+        resp = c.put(base + dav_uri, content=BODY)
+        assert t_cmp(resp.status_code, expected), \
+            f"PUT to .DAV subdir: expect {expected}, got {resp.status_code}"
+
     # clean up
+    try:
+        os.unlink(os.path.join(htdocs, DIR, ".DAV", "test.html"))
+    except OSError:
+        pass
     for sub in (".DAV",):
         p = os.path.join(htdocs, DIR, sub)
         if os.path.isdir(p):
index 354394532ac51d3268d253abff637a38ea234f90..d01cefd5cf3e7f6749e8228bb90945336424eb58 100644 (file)
@@ -115,7 +115,8 @@ def test_header_combinations(http):
                         f"[{h1},{h2},{h3},{h4}]"
 
 
-# (htaccess content, [request header pairs], [expected response header pairs])
+# (htaccess content, [request header pairs], [expected response header pairs],
+#  [optional expected status; defaults to 200])
 TESTCASES = [
     # echo
     ("Header echo Test-Header\nHeader echo ^Aaa$\nHeader echo ^Aa$",
@@ -163,6 +164,9 @@ TESTCASES = [
     # expr=
     ('Header set Test-Header foo "expr=%{REQUEST_URI} =~ m#htaccess#"',
      [], ["Test-Header", "foo"]),
+    # 500 error test - malformed regex (unmatched parenthesis)
+    ("Header edit Test-Header (unclosed bar",
+     [], [], 500),
 ]
 
 TESTCASES_251 = [
@@ -197,15 +201,29 @@ def _pairs_to_dict(pairs):
 @need_module("headers")
 def test_header_directives(http):
     cases = list(TESTCASES)
+    if http.have_min_apache_version("2.4.68"):
+        # file() is not permitted in an .htaccess expr context -> 500.
+        htaccess = _htaccess_path(http)
+        cases.append((
+            f'Header set Test-Header "expr=%{{base64:%{{file:{htaccess}}}}}"',
+            [], [], 500))
     if http.have_min_apache_version("2.5.1"):
         cases += TESTCASES_251
 
-    for htaccess, req_pairs, exp_pairs in cases:
+    for case in cases:
+        htaccess, req_pairs, exp_pairs = case[0], case[1], case[2]
+        # Optional 4th element is the expected status; defaults to 200.
+        expected_status = case[3] if len(case) > 3 else 200
         with open(_htaccess_path(http), "w") as f:
             f.write(htaccess)
         req_headers = _pairs_to_dict(req_pairs)
         r = http.GET("/modules/headers/htaccess/", headers=req_headers)
-        assert t_cmp(r.status_code, 200), "Checking return code is '200'"
+        assert t_cmp(r.status_code, expected_status), \
+            f"Checking return code is '{expected_status}' [htaccess: {htaccess!r}]"
+
+        # Only validate response headers for successful responses.
+        if expected_status != 200:
+            continue
 
         for i in range(0, len(exp_pairs), 2):
             name, expected = exp_pairs[i], exp_pairs[i + 1]
index cb3e4dbabec8939aee5da3966e6b7247685d35f6..fce3fea53523c6d5028a22501603266dbab30ba0 100644 (file)
@@ -146,6 +146,39 @@ TESTS = [
     # ProxyHTMLDocType test
     {"type": "url_rewrite", "path": "doctype/doctype.html",
      "pattern": r"<!DOCTYPE html", "desc": "DOCTYPE declaration added"},
+
+    # Multi-substitution buffer reallocation tests
+    # Tests that many literal substitutions (where replacement > match) in a
+    # single buffer don't truncate content when ap_varbuf_grow reallocates.
+    {"type": "url_rewrite", "path": "multi_subst/multi_subst.html",
+     "pattern": r"http://long-rewritten-path\.example\.com/u01",
+     "desc": "CDATA multi-subst first URL rewritten"},
+    {"type": "url_rewrite", "path": "multi_subst/multi_subst.html",
+     "pattern": r"http://long-rewritten-path\.example\.com/u40",
+     "desc": "CDATA multi-subst last URL rewritten"},
+    {"type": "url_rewrite", "path": "multi_subst/multi_subst.html",
+     "pattern": r"CDATA_END_OK",
+     "desc": "CDATA content preserved after multi-substitution"},
+    {"type": "url_rewrite", "path": "multi_subst/multi_subst.html",
+     "pattern": r"EVENT_END_OK",
+     "desc": "event attr preserved after multi-substitution"},
+
+    # Multi-substitution regex buffer tests
+    # Tests that many regex substitutions in a single CDATA/event buffer
+    # don't cause heap overflow or content truncation.
+    {"type": "url_rewrite", "path": "multi_subst_rx/multi_subst_rx.html",
+     "pattern": r"http://regex-rewritten-path\.example\.com/u01",
+     "desc": "CDATA regex multi-subst first URL rewritten"},
+    {"type": "url_rewrite", "path": "multi_subst_rx/multi_subst_rx.html",
+     "pattern": r"http://regex-rewritten-path\.example\.com/u40",
+     "desc": "CDATA regex multi-subst last URL rewritten"},
+    {"type": "url_rewrite", "path": "multi_subst_rx/multi_subst_rx.html",
+     "pattern": r"RX_CDATA_END_OK",
+     "desc": "CDATA content preserved after regex multi-substitution"},
+    {"type": "url_rewrite", "path": "multi_subst_rx/multi_subst_rx.html",
+     "pattern": r"RX_EVENT_END_OK",
+     "desc": "event attr preserved after regex multi-substitution"},
+
     # Multiple URL maps tests
     {"type": "url_rewrite", "path": "multiple_maps/multiple_maps.html",
      "pattern": r"http://new-a\.example\.com/page1\.html", "desc": "first URL map"},