Author: jpeck
Date: Wed Jul  8 20:32:27 2026
New Revision: 1936012

Log:
Canonicalize SVNMasterURI at config-parse time, avoid re-encoding it

The SVNMasterURI directive value was stored verbatim, so a trailing slash
leaked "//" into every proxied filename and rewritten Destination header.
mirror.c URI-encoded the raw value before use, double-escaping any 
'%' in a master path that itself needs encoding.

Store the value canonicalized (no trailing slash, normalized escapes)
and establish the invariant that consumers use it as-is: the Destination
rewrite and the Location response-header match take it verbatim, and the
proxy filename now encodes only the (decoded) URI segment appended to
it.

This is a user-visible config improvement: SVNMasterURI values with a
trailing slash now work.  The mirror test harness deliberately
configures one to keep this canonicalized.

* subversion/mod_dav_svn/mod_dav_svn.c
  (SVNMasterURI_cmd): Canonicalize the value before storing it.
* subversion/mod_dav_svn/mirror.c
  (proxy_request_fixup): Build r->filename from the raw master URI plus
   the encoded segment.
  (proxy_request_fixup_destination): Don't re-encode the master URI in
   the rewritten Destination header.
  (dav_svn__location_header_filter): Match the stored master URI
   against the Location header without re-encoding it.

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

Modified: 
subversion/branches/proxy-move-copy-fix/subversion/mod_dav_svn/mirror.c
==============================================================================
--- subversion/branches/proxy-move-copy-fix/subversion/mod_dav_svn/mirror.c     
Wed Jul  8 20:23:32 2026        (r1936011)
+++ subversion/branches/proxy-move-copy-fix/subversion/mod_dav_svn/mirror.c     
Wed Jul  8 20:32:27 2026        (r1936012)
@@ -76,8 +76,7 @@ proxy_request_fixup_destination(request_
       }
 
     apr_table_set(r->headers_in, "Destination",
-                  apr_pstrcat(r->pool, svn_path_uri_encode(master_uri, 
r->pool),
-                              "/", rel, SVN_VA_NULL));
+                  apr_pstrcat(r->pool, master_uri, "/", rel, SVN_VA_NULL));
 }
 
 
@@ -86,7 +85,8 @@ proxy_request_fixup_destination(request_
    specified in the SVNMasterURI Apache configuration value.
    URI_SEGMENT is the URI bits relative to the repository root (but if
    non-empty, *does* have a leading slash delimiter).
-   MASTER_URI and URI_SEGMENT are not URI-encoded. */
+   MASTER_URI is canonical and URI-encoded (stored by SVNMasterURI_cmd);
+   URI_SEGMENT is not URI-encoded. */
 static int proxy_request_fixup(request_rec *r,
                                const char *master_uri,
                                const char *uri_segment)
@@ -101,11 +101,10 @@ static int proxy_request_fixup(request_r
 
     r->proxyreq = PROXYREQ_REVERSE;
     r->uri = r->unparsed_uri;
-    r->filename = (char *) svn_path_uri_encode(apr_pstrcat(r->pool, "proxy:",
-                                                           master_uri,
-                                                           uri_segment,
-                                                           SVN_VA_NULL),
-                                               r->pool);
+    r->filename = (char *) apr_pstrcat(r->pool, "proxy:", master_uri,
+                                       svn_path_uri_encode(uri_segment,
+                                                           r->pool),
+                                       SVN_VA_NULL);
     r->handler = "proxy-server";
 
     proxy_request_fixup_destination(r, master_uri);
@@ -300,7 +299,6 @@ apr_status_t dav_svn__location_header_fi
     /* Don't filter if we're in a subrequest or we aren't setup to
        proxy anything. */
     master_uri = dav_svn__get_master_uri(r);
-    master_uri = svn_path_uri_encode(master_uri, r->pool);
     if (r->main || !master_uri) {
         ap_remove_output_filter(f);
         return ap_pass_brigade(f->next, bb);

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:23:32 2026        (r1936011)
+++ 
subversion/branches/proxy-move-copy-fix/subversion/mod_dav_svn/mod_dav_svn.c    
    Wed Jul  8 20:32:27 2026        (r1936012)
@@ -339,7 +339,10 @@ SVNMasterURI_cmd(cmd_parms *cmd, void *c
   if (! *uri_base_name)
     return "SVNMasterURI value must not be a server root";
 
-  conf->master_uri = apr_pstrdup(cmd->pool, arg1);
+  /* Store the URI canonicalized: no trailing slash, normalized hex
+     encoding.  mirror.c concatenates "/<relpath>" onto this value and
+     must never see a trailing "/" or a non-normalized escape. */
+  conf->master_uri = svn_urlpath__canonicalize(arg1, cmd->pool);
 
   return NULL;
 }

Reply via email to