From: Jim Jagielski Date: Fri, 5 Jun 2026 17:48:53 +0000 (+0000) Subject: test: port recent httpd-tests 2.4.68 changes to pytest_suite X-Git-Url: http://git.ipfire.org/gitweb/index.cgi?a=commitdiff_plain;h=ab53298da038512a19b9ddacc8febe8db416acc0;p=thirdparty%2Fapache%2Fhttpd.git test: port recent httpd-tests 2.4.68 changes to pytest_suite 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 --- diff --git a/test/pytest_suite/t/conf/proxy.conf.in b/test/pytest_suite/t/conf/proxy.conf.in index 37c76e651e..3025038a49 100644 --- a/test/pytest_suite/t/conf/proxy.conf.in +++ b/test/pytest_suite/t/conf/proxy.conf.in @@ -338,6 +338,28 @@ Alias /modules/proxy/fcgi-uds-sethandler @SERVERROOT@/htdocs/modules/proxy/fcgi ProxyPass http://@SERVERNAME@:@PORT@/modules/proxy_html + # Multi-substitution buffer reallocation test + + 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 + + + # Multi-substitution regex buffer test + + 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 + + # Multiple URL maps test 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 index 0000000000..0598dba59d --- /dev/null +++ b/test/pytest_suite/t/htdocs/modules/proxy_html/multi_subst.html @@ -0,0 +1,20 @@ + + +Multi-substitution buffer test + + +test + + + + +Multi-substitution buffer test + + +test + + 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 index 0000000000..1d838df17c --- /dev/null +++ b/test/pytest_suite/t/htdocs/modules/proxy_html/multi_subst_rx.html @@ -0,0 +1,20 @@ + + +Multi-substitution regex buffer test + + +test + + + + +Multi-substitution regex buffer test + + +test + + diff --git a/test/pytest_suite/tests/t/apache/test_expr.py b/test/pytest_suite/tests/t/apache/test_expr.py index 388a7d1f3d..6169440a07 100644 --- a/test/pytest_suite/tests/t/apache/test_expr.py +++ b/test/pytest_suite/tests/t/apache/test_expr.py @@ -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), diff --git a/test/pytest_suite/tests/t/modules/test_dav.py b/test/pytest_suite/tests/t/modules/test_dav.py index 82e36d9df7..aed5fd26f7 100644 --- a/test/pytest_suite/tests/t/modules/test_dav.py +++ b/test/pytest_suite/tests/t/modules/test_dav.py @@ -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): diff --git a/test/pytest_suite/tests/t/modules/test_headers.py b/test/pytest_suite/tests/t/modules/test_headers.py index 354394532a..d01cefd5cf 100644 --- a/test/pytest_suite/tests/t/modules/test_headers.py +++ b/test/pytest_suite/tests/t/modules/test_headers.py @@ -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] diff --git a/test/pytest_suite/tests/t/modules/test_proxy_html.py b/test/pytest_suite/tests/t/modules/test_proxy_html.py index cb3e4dbabe..fce3fea535 100644 --- a/test/pytest_suite/tests/t/modules/test_proxy_html.py +++ b/test/pytest_suite/tests/t/modules/test_proxy_html.py @@ -146,6 +146,39 @@ TESTS = [ # ProxyHTMLDocType test {"type": "url_rewrite", "path": "doctype/doctype.html", "pattern": r" 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"},