Author: jpeck
Date: Wed Jul  8 20:42:08 2026
New Revision: 1936013

Log:
Fix HTTP requests against <Location> paths with escapable characters.

This isn't really part of the mod_dav_svn proxy fixes, but this fix is
required to test the fix in 1936011. HTTPv2 commits failed with a 400
Bad Request against any mod_dav_svn repository whose <Location> path
contains a URI-escapable character.

get_resource() expects its ROOT_PATH argument in the decoded domain: it
strips it from the decoded r->uri (ap_stripprefix) and re-encodes it
for href output itself.  mod_dav's own method dispatch passes its
per-dir config, which is decoded, which is why plain DAV methods
(GET, PROPFIND, OPTIONS) always worked.  But three mod_dav_svn-internal
callers passed dav_svn__get_root_dir(), which is stored canonical and
URI-encoded.  Under "/svn repo", stripping "/svn%20repo" from
"/svn repo/!svn/me" fails, the URI parses as an ordinary repository
path, and dav_svn__method_post() bogusly rejects the transaction-
creation POST.  The same mismatch garbled the %f log path in
translate_name and made the SVNListParentPath root comparison never
match.

The domain contract, now honored by all in-tree callers: anything
comparing the stored root dir against r->uri must decode it first,
anything building client-visible URIs from it uses it as-is.

Regression-tested, updated tests coming in follow up commit 

* subversion/mod_dav_svn/repos.c
  (dav_svn__method_post): Decode the stored root dir before handing it
   to get_resource().
* subversion/mod_dav_svn/mod_dav_svn.c
  (dav_svn__translate_name): Likewise for dav_svn_split_uri().
* subversion/mod_dav_svn/util.c
  (dav_svn__is_parentpath_list): Decode before comparing against r->uri.

Modified:
   subversion/branches/proxy-move-copy-fix/subversion/mod_dav_svn/mod_dav_svn.c
   subversion/branches/proxy-move-copy-fix/subversion/mod_dav_svn/repos.c
   subversion/branches/proxy-move-copy-fix/subversion/mod_dav_svn/util.c

Modified: 
subversion/branches/proxy-move-copy-fix/subversion/mod_dav_svn/mod_dav_svn.c
==============================================================================
--- 
subversion/branches/proxy-move-copy-fix/subversion/mod_dav_svn/mod_dav_svn.c    
    Wed Jul  8 20:32:27 2026        (r1936012)
+++ 
subversion/branches/proxy-move-copy-fix/subversion/mod_dav_svn/mod_dav_svn.c    
    Wed Jul  8 20:42:08 2026        (r1936013)
@@ -1236,8 +1236,12 @@ static int dav_svn__translate_name(reque
     }
   else
     {
-      /* Retrieve path to repo and within repo for the request */
-      dav_error *err = dav_svn_split_uri(r, r->uri, dav_svn__get_root_dir(r),
+      /* Retrieve path to repo and within repo for the request.
+         dav_svn_split_uri() strips the root from the decoded r->uri, so
+         hand it the decoded form of the (encoded, canonical) root dir. */
+      const char *root_dir_decoded =
+        svn_path_uri_decode(dav_svn__get_root_dir(r), r->pool);
+      dav_error *err = dav_svn_split_uri(r, r->uri, root_dir_decoded,
                                          &ignore_cleaned_uri,
                                          &ignore_had_slash, &repos_basename,
                                          &ignore_relative_path, &repos_path);

Modified: subversion/branches/proxy-move-copy-fix/subversion/mod_dav_svn/repos.c
==============================================================================
--- subversion/branches/proxy-move-copy-fix/subversion/mod_dav_svn/repos.c      
Wed Jul  8 20:32:27 2026        (r1936012)
+++ subversion/branches/proxy-move-copy-fix/subversion/mod_dav_svn/repos.c      
Wed Jul  8 20:42:08 2026        (r1936013)
@@ -4955,9 +4955,16 @@ int dav_svn__method_post(request_rec *r)
   dav_resource *resource;
   dav_error *derr;
   const char *content_type;
+  const char *root_dir_decoded;
 
-  /* We only allow POSTs against the "me resource" right now. */
-  derr = get_resource(r, dav_svn__get_root_dir(r),
+  /* We only allow POSTs against the "me resource" right now.
+     get_resource() expects ROOT_PATH in the decoded domain, it strips
+     it from the (decoded) r->uri and re-encodes it for href output
+     itself, but dav_svn__get_root_dir() is stored canonical and
+     URI-encoded.  Decode it or the strip fails for any <Location>
+     containing a URI-escapable character. */
+  root_dir_decoded = svn_path_uri_decode(dav_svn__get_root_dir(r), r->pool);
+  derr = get_resource(r, root_dir_decoded,
                       "ignored", 0, &resource);
   if (derr != NULL)
     return derr->status;

Modified: subversion/branches/proxy-move-copy-fix/subversion/mod_dav_svn/util.c
==============================================================================
--- subversion/branches/proxy-move-copy-fix/subversion/mod_dav_svn/util.c       
Wed Jul  8 20:32:27 2026        (r1936012)
+++ subversion/branches/proxy-move-copy-fix/subversion/mod_dav_svn/util.c       
Wed Jul  8 20:42:08 2026        (r1936013)
@@ -434,7 +434,10 @@ dav_svn__is_parentpath_list(request_rec
 
   if (fs_parent_path && dav_svn__get_list_parentpath_flag(r))
     {
-      const char *root_path = dav_svn__get_root_dir(r);
+      /* r->uri is decoded, but the stored root dir is canonical and
+         URI-encoded, decode it so the comparison is like-with-like. */
+      const char *root_path =
+        svn_path_uri_decode(dav_svn__get_root_dir(r), r->pool);
       char *uri = apr_pstrdup(r->pool, r->uri);
       char *parentpath = apr_pstrdup(r->pool, root_path);
       apr_size_t uri_len = strlen(uri);

Reply via email to