Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions changes-entries/dav-options-trace.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
*) mod_dav: Do not list TRACE in the Allow field of an OPTIONS response when
TraceEnable is off. PR 70264
6 changes: 5 additions & 1 deletion modules/dav/main/mod_dav.c
Original file line number Diff line number Diff line change
Expand Up @@ -1844,6 +1844,8 @@ static int dav_method_search(request_rec *r)
/* handle the OPTIONS method */
static int dav_method_options(request_rec *r)
{
core_server_config *conf =
ap_get_core_module_config(r->server->module_config);
const dav_hooks_locks *locks_hooks = DAV_GET_HOOKS_LOCKS(r);
const dav_hooks_vsn *vsn_hooks = DAV_GET_HOOKS_VSN(r);
const dav_hooks_binding *binding_hooks = DAV_GET_HOOKS_BINDING(r);
Expand Down Expand Up @@ -1975,7 +1977,9 @@ static int dav_method_options(request_rec *r)
apr_table_addn(methods, "HEAD", "");
apr_table_addn(methods, "POST", "");
apr_table_addn(methods, "DELETE", "");
apr_table_addn(methods, "TRACE", "");
if (conf->trace_enable != AP_TRACE_DISABLE) {
apr_table_addn(methods, "TRACE", "");
}
apr_table_addn(methods, "PROPFIND", "");
apr_table_addn(methods, "PROPPATCH", "");
apr_table_addn(methods, "COPY", "");
Expand Down
75 changes: 75 additions & 0 deletions test/modules/dav/test_002_options_trace.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import os

import pytest

from pyhttpd.conf import HttpdConf

DAV_METHODS = {"OPTIONS", "GET", "HEAD", "POST", "DELETE", "PROPFIND",
"PROPPATCH", "COPY", "MOVE", "LOCK", "UNLOCK"}


def _setup(env, trace):
dav_dir = os.path.join(env.gen_dir, 'dav')
os.makedirs(os.path.join(dav_dir, 'col'), 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"
TraceEnable {trace}
""",
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


def _request(env, method, path):
r = env.curl_raw(env.mkurl("https", "test1", path),
options=['-X', method])
assert r.response, f"no response: {r.stderr}"
allow = r.response["header"].get("allow", "")
return r.response["status"], {m.strip() for m in allow.split(',') if m.strip()}


class TestOptionsTraceDisabled:

@pytest.fixture(autouse=True, scope='class')
def _class_scope(self, env):
_setup(env, "off")

# TRACE is not offered while the server refuses it
@pytest.mark.parametrize("path", ["/dav/file.txt", "/dav/col/"])
def test_dav_002_001(self, env, path):
status, allow = _request(env, "OPTIONS", path)
assert status == 200
assert "TRACE" not in allow, f"Allow: {allow}"
assert DAV_METHODS <= allow, f"Allow: {allow}"

def test_dav_002_002(self, env):
assert _request(env, "TRACE", "/dav/file.txt")[0] == 405


class TestOptionsTraceEnabled:

@pytest.fixture(autouse=True, scope='class',
params=["on", "extended"])
def _class_scope(self, env, request):
_setup(env, request.param)

# unchanged: TRACE is offered and works
@pytest.mark.parametrize("path", ["/dav/file.txt", "/dav/col/"])
def test_dav_002_101(self, env, path):
status, allow = _request(env, "OPTIONS", path)
assert status == 200
assert (DAV_METHODS | {"TRACE"}) <= allow, f"Allow: {allow}"

def test_dav_002_102(self, env):
assert _request(env, "TRACE", "/dav/file.txt")[0] == 200
Loading