You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by st...@apache.org on 2018/11/12 10:23:08 UTC

svn commit: r1846391 - in /subversion/branches/dav-path-escape: ./ subversion/include/ subversion/include/private/ subversion/libsvn_ra_serf/ subversion/libsvn_subr/ subversion/mod_dav_svn/ subversion/mod_dav_svn/reports/

Author: stsp
Date: Mon Nov 12 10:23:07 2018
New Revision: 1846391

URL: http://svn.apache.org/viewvc?rev=1846391&view=rev
Log:
Create the dav-path-escape branch. See BRANCH-README for details.

Patch by: philip

Added:
    subversion/branches/dav-path-escape/   (props changed)
      - copied from r1846390, subversion/trunk/
    subversion/branches/dav-path-escape/BRANCH-README   (with props)
Modified:
    subversion/branches/dav-path-escape/subversion/include/private/svn_string_private.h
    subversion/branches/dav-path-escape/subversion/include/svn_dav.h
    subversion/branches/dav-path-escape/subversion/libsvn_ra_serf/getlocationsegments.c
    subversion/branches/dav-path-escape/subversion/libsvn_ra_serf/log.c
    subversion/branches/dav-path-escape/subversion/libsvn_ra_serf/options.c
    subversion/branches/dav-path-escape/subversion/libsvn_ra_serf/property.c
    subversion/branches/dav-path-escape/subversion/libsvn_ra_serf/ra_serf.h
    subversion/branches/dav-path-escape/subversion/libsvn_ra_serf/update.c
    subversion/branches/dav-path-escape/subversion/libsvn_ra_serf/util.c
    subversion/branches/dav-path-escape/subversion/libsvn_subr/path.c
    subversion/branches/dav-path-escape/subversion/libsvn_subr/string.c
    subversion/branches/dav-path-escape/subversion/mod_dav_svn/dav_svn.h
    subversion/branches/dav-path-escape/subversion/mod_dav_svn/liveprops.c
    subversion/branches/dav-path-escape/subversion/mod_dav_svn/reports/get-location-segments.c
    subversion/branches/dav-path-escape/subversion/mod_dav_svn/reports/log.c
    subversion/branches/dav-path-escape/subversion/mod_dav_svn/reports/update.c
    subversion/branches/dav-path-escape/subversion/mod_dav_svn/repos.c
    subversion/branches/dav-path-escape/subversion/mod_dav_svn/util.c
    subversion/branches/dav-path-escape/subversion/mod_dav_svn/version.c

Propchange: subversion/branches/dav-path-escape/
------------------------------------------------------------------------------
--- svn:auto-props (added)
+++ svn:auto-props Mon Nov 12 10:23:07 2018
@@ -0,0 +1,13 @@
+*.c = svn:eol-style=native
+*.cpp = svn:eol-style=native
+*.h = svn:eol-style=native
+*.hpp = svn:eol-style=native
+*.java = svn:eol-style=native
+*.py = svn:eol-style=native
+*.pl = svn:eol-style=native
+*.rb = svn:eol-style=native
+*.sql = svn:eol-style=native
+*.txt = svn:eol-style=native
+README = svn:eol-style=native
+BRANCH-README = svn:eol-style=native
+STATUS = svn:eol-style=native

Propchange: subversion/branches/dav-path-escape/
------------------------------------------------------------------------------
--- svn:ignore (added)
+++ svn:ignore Mon Nov 12 10:23:07 2018
@@ -0,0 +1,54 @@
+ChangeLog*
+Makefile
+config.cache
+config.log
+config.nice
+config.status
+configure
+libtool
+.gdb_history
+.swig_checked
+*.orig
+*.rej
+TAGS
+tags
+neon
+build-outputs.mk
+autogen-standalone.mk
+autom4te.cache
+gen-make.opts
+tests.log*
+fails.log*
+db4-win32
+db
+*.o
+*~
+.*~
+apr
+apr-util
+apr-iconv
+Release
+Debug
+ipch
+subversion_msvc.dsw
+subversion_msvc.ncb
+subversion_msvc.opt
+subversion_msvc.plg
+subversion_vcnet.*
+mkmf.log
+.project
+.classpath
+.cdtproject
+.settings
+.cproject
+zlib
+sqlite-amalgamation
+serf
+googlemock
+.git
+.gitignore
+.idea
+compile_commands.json
+.kdev4
+*.kdev4
+.vs

Propchange: subversion/branches/dav-path-escape/
------------------------------------------------------------------------------
--- svn:mergeinfo (added)
+++ svn:mergeinfo Mon Nov 12 10:23:07 2018
@@ -0,0 +1,103 @@
+/subversion/branches/1.10-cache-improvements:1669168-1694487
+/subversion/branches/1.11.x:1841316,1841548
+/subversion/branches/1.5.x-r30215:870312
+/subversion/branches/1.7.x-fs-verify:1146708,1161180
+/subversion/branches/1.9-cache-improvements:1678948-1679863
+/subversion/branches/1.9.x:1735680
+/subversion/branches/10Gb:1388102,1388163-1388190,1388195,1388202,1388205,1388211,1388276,1388362,1388375,1388394,1388636,1388639-1388640,1388643-1388644,1388654,1388720,1388789,1388795,1388801,1388805,1388807,1388810,1388816,1389044,1389276,1389289,1389662,1389867,1390017,1390209,1390216,1390407,1390409,1390414,1390419,1390955
+/subversion/branches/atomic-revprop:965046-1000689
+/subversion/branches/authzperf:1613053-1776831
+/subversion/branches/auto-props-sdc:1384106-1401643
+/subversion/branches/bdb-reverse-deltas:872050-872529
+/subversion/branches/cache-server:1458643-1476567
+/subversion/branches/diff-callbacks3:870059-870761
+/subversion/branches/diff-optimizations:1031270-1037352
+/subversion/branches/diff-optimizations-bytes:1037353-1067789
+/subversion/branches/dont-save-plaintext-passwords-by-default:870728-871118
+/subversion/branches/double-delete:870511-872970
+/subversion/branches/dump-load-cross-check:1654853-1657295
+/subversion/branches/ev2-export:1325914,1332738,1413107
+/subversion/branches/explore-wc:875486,875493,875497,875507,875511,875514,875559,875580-875581,875584,875587,875611,875627,875647,875667-875668,875711-875712,875733-875734,875736,875744-875748,875751,875758,875782,875795-875796,875830,875836,875838,875842,875852,875855,875864,875870,875873,875880,875885-875888,875890,875897-875898,875905,875907-875909,875935,875943-875944,875946,875979,875982-875983,875985-875986,875990,875997
+/subversion/branches/file-externals:871779-873302
+/subversion/branches/fs-rep-sharing:869036-873803
+/subversion/branches/fsfs-format7:1426304,1430673,1433848,1438408,1438982,1441129,1442051,1442068,1442504,1442910,1443171,1443803,1444690,1444693,1444695,1445040,1445080,1446103,1451129,1453590,1454307,1460579,1461851,1461865,1462837,1462904,1463120,1467362,1467382,1469487,1471208,1477166,1478055,1481447,1489817,1489949,1490673-1490674,1491784,1493042,1498029,1498103,1498155,1500054,1507729-1507731,1507735-1507736
+/subversion/branches/fsfs-improvements:1499981-1547039
+/subversion/branches/fsfs-lock-many:1571740-1577217
+/subversion/branches/fsfs-pack:873717-874575
+/subversion/branches/fsx:1507845-1509914
+/subversion/branches/fsx-1.10:1658219-1694500
+/subversion/branches/fsx-id:1645603-1649011
+/subversion/branches/gnome-keyring:870558-871410
+/subversion/branches/gpg-agent-password-store:1005036-1150766
+/subversion/branches/gtest_addition:1452117-1502138
+/subversion/branches/http-protocol-v2:874395-876041
+/subversion/branches/in-memory-cache:869829-871452
+/subversion/branches/in-repo-authz:1414342-1424779
+/subversion/branches/inheritable-props:1297080-1395089
+/subversion/branches/integrate-cache-item-serialization:1068724-1068739
+/subversion/branches/integrate-cache-membuffer:998649-998852
+/subversion/branches/integrate-compression-level:1068651-1072287
+/subversion/branches/integrate-io-improvements:1068684-1072297
+/subversion/branches/integrate-is-cachable:1072568-1074082
+/subversion/branches/integrate-partial-getter:1072558-1076552
+/subversion/branches/integrate-readline-speedup:1072553-1072555
+/subversion/branches/integrate-stream-api-extensions:1068695-1072516
+/subversion/branches/integrate-string-improvements:1068251-1190617
+/subversion/branches/integrate-txdelta-caching:1072541-1078213
+/subversion/branches/issue-2779-dev:965496-984198
+/subversion/branches/issue-2843-dev:871432-874179
+/subversion/branches/issue-3000:871713,871716-871719,871721-871726,871728,871734
+/subversion/branches/issue-3067-deleted-subtrees:873375-874084
+/subversion/branches/issue-3148-dev:875193-875204
+/subversion/branches/issue-3220-dev:872210-872226
+/subversion/branches/issue-3242-dev:879653-896436
+/subversion/branches/issue-3334-dirs:875156-875867
+/subversion/branches/issue-3975:1152931-1160746
+/subversion/branches/issue-4116-dev:1424719-1425040
+/subversion/branches/issue-4194-dev:1410507-1414880
+/subversion/branches/java10-compat:1840620-1841179
+/subversion/branches/javahl-ra:991978-1494640
+/subversion/branches/kwallet:870785-871314
+/subversion/branches/log-addressing:1509279-1546844
+/subversion/branches/log-g-performance:870941-871032
+/subversion/branches/merge-skips-obstructions:874525-874615
+/subversion/branches/move-tracking-2:1606692-1714632
+/subversion/branches/multi-layer-moves:1239019-1300930
+/subversion/branches/nfc-nfd-aware-client:870276,870376
+/subversion/branches/node_pool:1304828-1305388
+/subversion/branches/patch-exec:1692717-1705390
+/subversion/branches/performance:979193,980118,981087,981090,981189,981194,981287,981684,981827,982043,982355,983398,983406,983430,983474,983488,983490,983760,983764,983766,983770,984927,984973,984984,985014,985037,985046,985472,985477,985482,985487-985488,985493,985497,985500,985514,985601,985603,985606,985669,985673,985695,985697,986453,986465,986485,986491-986492,986517,986521,986605,986608,986817,986832,987865,987868-987869,987872,987886-987888,987893,988319,988898,990330,990533,990535-990537,990541,990568,990572,990574-990575,990600,990759,992899,992904,992911,993127,993141,994956,995478,995507,995603,998012,998858,999098,1001413,1001417,1004291,1022668,1022670,1022676,1022715,1022719,1025660,1025672,1027193,1027203,1027206,1027214,1027227,1028077,1028092,1028094,1028104,1028107,1028111,1028354,1029038,1029042-1029043,1029054-1029055,1029062-1029063,1029078,1029080,1029090,1029092-1029093,1029111,1029151,1029158,1029229-1029230,1029232,1029335-1029336,1029339-1029340,1029342,10
 29344,1030763,1030827,1031203,1031235,1032285,1032333,1033040,1033057,1033294,1035869,1035882,1039511,1043705,1053735,1056015,1066452,1067683,1067697-1078365
+/subversion/branches/pin-externals:1643757-1659392
+/subversion/branches/py-tests-as-modules:956579-1033052
+/subversion/branches/ra-svn-tuning:1658201-1694489
+/subversion/branches/ra_serf-digest-authn:875693-876404
+/subversion/branches/reintegrate-improvements:873853-874164
+/subversion/branches/remote-only-status:1581845-1586090
+/subversion/branches/resolve-incoming-add:1762797-1764284
+/subversion/branches/revprop-cache:1298521-1326293
+/subversion/branches/revprop-caching-ng:1620597,1620599
+/subversion/branches/revprop-packing:1143907,1143971,1143997,1144017,1144499,1144568,1146145
+/subversion/branches/shelve:1802592-1815226
+/subversion/branches/shelve-checkpoint:1801593-1801923,1801970,1817320,1828508,1828521
+/subversion/branches/subtree-mergeinfo:876734-878766
+/subversion/branches/svn-auth-x509:1603509-1655900
+/subversion/branches/svn-info-detail:1660035-1662618
+/subversion/branches/svn-mergeinfo-enhancements:870119-870195,870197-870288
+/subversion/branches/svn-mergeinfo-normalizer:1642232-1695991
+/subversion/branches/svn-patch-improvements:918519-934609
+/subversion/branches/svn_mutex:1141683-1182099
+/subversion/branches/svnpatch-diff:865738-876477
+/subversion/branches/svnraisetc:874709-875149
+/subversion/branches/svnserve-logging:869828-870893
+/subversion/branches/tc-issue-3334:874697-874773
+/subversion/branches/tc-merge-notify:874017-874062
+/subversion/branches/tc-resolve:874191-874239
+/subversion/branches/tc_url_rev:874351-874483
+/subversion/branches/tree-conflicts:868291-873154
+/subversion/branches/tree-conflicts-notify:873926-874008
+/subversion/branches/tristate-chunked-request:1502394-1502681
+/subversion/branches/tweak-build-take-two:1424288-1425049,1425051-1425613
+/subversion/branches/uris-as-urls:1060426-1064427
+/subversion/branches/verify-at-commit:1462039-1462408
+/subversion/branches/verify-keep-going:1439280-1546110
+/subversion/branches/wc-collate-path:1402685-1480384

Added: subversion/branches/dav-path-escape/BRANCH-README
URL: http://svn.apache.org/viewvc/subversion/branches/dav-path-escape/BRANCH-README?rev=1846391&view=auto
==============================================================================
--- subversion/branches/dav-path-escape/BRANCH-README (added)
+++ subversion/branches/dav-path-escape/BRANCH-README Mon Nov 12 10:23:07 2018
@@ -0,0 +1,102 @@
+This branch aims to transport control characters in paths over DAV.
+
+Currently, if a path with a control character exists in the HEAD revision,
+operations involving this path will fail over DAV, until the offending path
+has been removed with 'svn rm', This branch aims to make all SVN operations
+work with such paths over DAV.
+
+Firstly, here is a python script to create a repository that has all
+characters from 0x01 to 0x7F (apart from '/' and '\n') in file and
+directory names.
+
+[[[
+#!/usr/bin/python
+from svn import repos, fs
+import sys
+
+repos.create(sys.argv[1], "", "", None, None)
+f = repos.fs(repos.open(sys.argv[1]))
+h = fs.youngest_rev(f)
+t = fs.begin_txn(f, h)
+r = fs.txn_root(t)
+for i in range(1,128):
+    if chr(i) in ['/', '\n']:
+        continue
+    dirname = "D" + "%0.2X" % i
+    fs.make_dir(r, dirname)
+    subdirname = dirname + "/S" + chr(i)
+    fs.make_dir(r, subdirname)
+    filename = subdirname + "/F" + chr(i)
+    fs.make_file(r, filename)
+    fs.change_node_prop(r, filename, "p", "v")
+fs.commit_txn(t)
+]]]
+
+With the patch on this branch it is possible to checkout/update/log/switch
+this working copy.  It's possible to use curl to get each of the files.
+It's possible to use 'svn pg p URL' to get a property from each file.
+The escape support is negotiated, so the new server supports old clients
+that do not have escape support.
+
+How the patch works:
+
+The server sends a new header as part of the OPTIONS reponse:
+
+  SVN-XML-Filename-Escape: 0x25
+
+to indicate that it supports escaping.  If the new client sees the
+header then it includes the same header in requests and can % escape any
+paths in the request body as necessary.  If the new client does not see the
+header then it cannot escape paths in the request body and any path that
+would require escaping will result in a client error to the user:
+"server too old".   The old client will not send the header and will not
+escape paths in the request body.
+
+If the server sees the header when handling a request it is able to
+unescape any paths in the request body.  The server includes the same
+header in the response and is able to escape any paths in the response
+body.  The client sees the header in the response and it is able to
+unescape any paths in the reponse body.
+
+If the server does not see the header when handling a request then it
+knows that any paths in the request body are not escaped.  The server
+includes a header
+
+  SVN-XML-Filename-Escape: 0x7f
+
+and uses that character to escape any paths in the response body.  The
+old client will not be able to unescape paths in the response body but
+most of the paths affected by this problem are ones that the client
+cannot currently use over HTTP.  The only existing path that the old
+client will get wrong is a directory containing an 0x7f character.
+
+New client to new server:
+New server to new client:
+
+  SVN-XML-Filename-Escape: 0x25
+  'A' '5' '0' '%' 'B'   encoded as "A50%%B"
+  'A' '\x1f' 'B'        encoded as "A%1fB"
+
+New client to old server:
+
+  'A' '5' '0' '%' 'B'   encoded as "A50%B"
+  'A' '\x1f' 'B'        client error "server too old"
+
+New server to old client
+
+  SVN-XML-Filename-Escape: 0x7f
+  'A' '5' '0' '%' 'B'   encoded as "A50%B"
+  'A' '\x1f' 'B'        encoded as 'A' '\x7f' '1' 'f' 'B'  (*)
+  'A' '\x7f' 'B'        encoded as 'A' '\x7f' '\x7f' 'B'   (*)
+
+In the (*) cases the path '\x1f' will be misinterpreted by the old
+client but any such path is not currently supported.  The path
+containing '\x7f' will also be misinterpreted by the old client, it is
+the only currently supported path that will break and can only be a
+directory.
+
+Current status:
+
+The patch is not complete, it doesn't handle the full range of requests,
+and I haven't implemented the client-side check to throw errors when an
+escape is required and the server is too old.

Propchange: subversion/branches/dav-path-escape/BRANCH-README
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: subversion/branches/dav-path-escape/subversion/include/private/svn_string_private.h
URL: http://svn.apache.org/viewvc/subversion/branches/dav-path-escape/subversion/include/private/svn_string_private.h?rev=1846391&r1=1846390&r2=1846391&view=diff
==============================================================================
--- subversion/branches/dav-path-escape/subversion/include/private/svn_string_private.h (original)
+++ subversion/branches/dav-path-escape/subversion/include/private/svn_string_private.h Mon Nov 12 10:23:07 2018
@@ -324,6 +324,23 @@ int
 svn_prefix_string__compare(const svn_prefix_string__t *lhs,
                            const svn_prefix_string__t *rhs);
 
+/**
+ * Escape control characters in @a str and return the escaped string,
+ * or return @a str if no escaping required.
+ */
+const char *
+svn__cntrl_escape(const char *str,
+                  char escape,
+                  apr_pool_t *pool);
+
+/**
+ * Unescape control characters in @a str and return the unescaped string,
+ * or return @a str if no unescaping required.
+ */
+const char *
+svn__cntrl_unescape(const char *str,
+                    char escape,
+                    apr_pool_t *pool);
 /** @} */
 
 /** @} */

Modified: subversion/branches/dav-path-escape/subversion/include/svn_dav.h
URL: http://svn.apache.org/viewvc/subversion/branches/dav-path-escape/subversion/include/svn_dav.h?rev=1846391&r1=1846390&r2=1846391&view=diff
==============================================================================
--- subversion/branches/dav-path-escape/subversion/include/svn_dav.h (original)
+++ subversion/branches/dav-path-escape/subversion/include/svn_dav.h Mon Nov 12 10:23:07 2018
@@ -206,6 +206,10 @@ extern "C" {
 #define SVN_DAV_REPOSITORY_MERGEINFO "SVN-Repository-MergeInfo"
 
 /**
+ * @since New in 1.11. FIXME also 1.10.? and 1.9.? */
+#define SVN_DAV_XML_NAME_ESCAPE_HEADER "SVN-XML-Name-Escape"
+
+/**
  * @name Fulltext MD5 headers
  *
  * These headers are for client and server to verify that the base

Modified: subversion/branches/dav-path-escape/subversion/libsvn_ra_serf/getlocationsegments.c
URL: http://svn.apache.org/viewvc/subversion/branches/dav-path-escape/subversion/libsvn_ra_serf/getlocationsegments.c?rev=1846391&r1=1846390&r2=1846391&view=diff
==============================================================================
--- subversion/branches/dav-path-escape/subversion/libsvn_ra_serf/getlocationsegments.c (original)
+++ subversion/branches/dav-path-escape/subversion/libsvn_ra_serf/getlocationsegments.c Mon Nov 12 10:23:07 2018
@@ -34,6 +34,7 @@
 #include "svn_path.h"
 #include "svn_private_config.h"
 #include "../libsvn_ra/ra_loader.h"
+#include "private/svn_string_private.h"
 
 #include "ra_serf.h"
 
@@ -45,6 +46,7 @@ typedef struct gls_context_t {
   svn_revnum_t start_rev;
   svn_revnum_t end_rev;
   const char *path;
+  char xml_name_escape;
 
   /* location segment callback function/baton */
   svn_location_segment_receiver_t receiver;
@@ -90,7 +92,8 @@ gls_closed(svn_ra_serf__xml_estate_t *xe
 
   SVN_ERR_ASSERT(leaving_state == SEGMENT);
 
-  path = svn_hash_gets(attrs, "path");
+  path = svn__cntrl_unescape(svn_hash_gets(attrs, "path"),
+                             gls_ctx->xml_name_escape, scratch_pool);
   start_str = svn_hash_gets(attrs, "range-start");
   end_str = svn_hash_gets(attrs, "range-end");
 
@@ -153,6 +156,20 @@ create_gls_body(serf_bucket_t **body_bkt
   return SVN_NO_ERROR;
 }
 
+static svn_error_t *
+setup_getlocationsegments_headers(serf_bucket_t *headers,
+                                  void *setup_baton,
+                                  apr_pool_t *pool /* request pool */,
+                                  apr_pool_t *scratch_pool)
+
+{
+  svn_ra_serf__session_t *session = setup_baton;
+
+  svn_ra_serf__setup_xml_name_escape(headers, session, pool);
+
+  return SVN_NO_ERROR;
+}
+
 svn_error_t *
 svn_ra_serf__get_location_segments(svn_ra_session_t *ra_session,
                                    const char *path,
@@ -175,6 +192,7 @@ svn_ra_serf__get_location_segments(svn_r
   gls_ctx->peg_revision = peg_revision;
   gls_ctx->start_rev = start_rev;
   gls_ctx->end_rev = end_rev;
+  gls_ctx->xml_name_escape = session->xml_name_escape;
   gls_ctx->receiver = receiver;
   gls_ctx->receiver_baton = receiver_baton;
 
@@ -193,6 +211,8 @@ svn_ra_serf__get_location_segments(svn_r
   handler->body_delegate = create_gls_body;
   handler->body_delegate_baton = gls_ctx;
   handler->body_type = "text/xml";
+  handler->header_delegate = setup_getlocationsegments_headers;
+  handler->header_delegate_baton = session;
 
   err = svn_ra_serf__context_run_one(handler, pool);
 

Modified: subversion/branches/dav-path-escape/subversion/libsvn_ra_serf/log.c
URL: http://svn.apache.org/viewvc/subversion/branches/dav-path-escape/subversion/libsvn_ra_serf/log.c?rev=1846391&r1=1846390&r2=1846391&view=diff
==============================================================================
--- subversion/branches/dav-path-escape/subversion/libsvn_ra_serf/log.c (original)
+++ subversion/branches/dav-path-escape/subversion/libsvn_ra_serf/log.c Mon Nov 12 10:23:07 2018
@@ -505,6 +505,20 @@ create_log_body(serf_bucket_t **body_bkt
   return SVN_NO_ERROR;
 }
 
+static svn_error_t *
+setup_get_log_headers(serf_bucket_t *headers,
+                      void *setup_baton,
+                      apr_pool_t *pool /* request pool */,
+                      apr_pool_t *scratch_pool)
+
+{
+  svn_ra_serf__session_t *session = setup_baton;
+
+  svn_ra_serf__setup_xml_name_escape(headers, session, pool);
+
+  return SVN_NO_ERROR;
+}
+
 svn_error_t *
 svn_ra_serf__get_log(svn_ra_session_t *ra_session,
                      const apr_array_header_t *paths,
@@ -595,6 +609,8 @@ svn_ra_serf__get_log(svn_ra_session_t *r
   handler->body_delegate = create_log_body;
   handler->body_delegate_baton = log_ctx;
   handler->body_type = "text/xml";
+  handler->header_delegate = setup_get_log_headers;
+  handler->header_delegate_baton = session;
 
   SVN_ERR(svn_ra_serf__context_run_one(handler, pool));
 

Modified: subversion/branches/dav-path-escape/subversion/libsvn_ra_serf/options.c
URL: http://svn.apache.org/viewvc/subversion/branches/dav-path-escape/subversion/libsvn_ra_serf/options.c?rev=1846391&r1=1846390&r2=1846391&view=diff
==============================================================================
--- subversion/branches/dav-path-escape/subversion/libsvn_ra_serf/options.c (original)
+++ subversion/branches/dav-path-escape/subversion/libsvn_ra_serf/options.c Mon Nov 12 10:23:07 2018
@@ -340,6 +340,13 @@ capabilities_headers_iterator_callback(v
               svn_hash_sets(session->supported_posts, post_val, (void *)1);
             }
         }
+      else if (svn_cstring_casecmp(key, SVN_DAV_XML_NAME_ESCAPE_HEADER) == 0)
+        {
+          if (val[0] == '%'
+              && svn_ctype_isxdigit(val[1]) && svn_ctype_isxdigit(val[2])
+              && !val[3])
+            session->xml_name_escape = (char)strtoul(val + 1, NULL, 16);
+        }
       else if (svn_cstring_casecmp(key, SVN_DAV_REPOSITORY_MERGEINFO) == 0)
         {
           if (svn_cstring_casecmp(val, "yes") == 0)

Modified: subversion/branches/dav-path-escape/subversion/libsvn_ra_serf/property.c
URL: http://svn.apache.org/viewvc/subversion/branches/dav-path-escape/subversion/libsvn_ra_serf/property.c?rev=1846391&r1=1846390&r2=1846391&view=diff
==============================================================================
--- subversion/branches/dav-path-escape/subversion/libsvn_ra_serf/property.c (original)
+++ subversion/branches/dav-path-escape/subversion/libsvn_ra_serf/property.c Mon Nov 12 10:23:07 2018
@@ -82,6 +82,8 @@ typedef struct propfind_context_t {
    * "good"; otherwise, they'll get discarded.
    */
   apr_hash_t *ps_props;
+
+  svn_ra_serf__session_t *sess;
 } propfind_context_t;
 
 
@@ -359,6 +361,8 @@ setup_propfind_headers(serf_bucket_t *he
       serf_bucket_headers_setn(headers, "Label", ctx->label);
     }
 
+  svn_ra_serf__setup_xml_name_escape(headers, ctx->sess, pool);
+
   return SVN_NO_ERROR;
 }
 
@@ -472,6 +476,7 @@ svn_ra_serf__create_propfind_handler(svn
   new_prop_ctx->prop_func = prop_func;
   new_prop_ctx->prop_func_baton = prop_func_baton;
   new_prop_ctx->depth = depth;
+  new_prop_ctx->sess = sess;
 
   if (SVN_IS_VALID_REVNUM(rev))
     {

Modified: subversion/branches/dav-path-escape/subversion/libsvn_ra_serf/ra_serf.h
URL: http://svn.apache.org/viewvc/subversion/branches/dav-path-escape/subversion/libsvn_ra_serf/ra_serf.h?rev=1846391&r1=1846390&r2=1846391&view=diff
==============================================================================
--- subversion/branches/dav-path-escape/subversion/libsvn_ra_serf/ra_serf.h (original)
+++ subversion/branches/dav-path-escape/subversion/libsvn_ra_serf/ra_serf.h Mon Nov 12 10:23:07 2018
@@ -273,6 +273,11 @@ struct svn_ra_serf__session_t {
    * to a successful PUT request. */
   svn_boolean_t supports_put_result_checksum;
 
+  /* The XML name escape character from the header in the OPTIONS
+     response. NUL if no header, i.e. the server does not support
+     escaping. */
+  char xml_name_escape;
+
   apr_interval_time_t conn_latency;
 };
 
@@ -1599,6 +1604,11 @@ void
 svn_ra_serf__setup_svndiff_accept_encoding(serf_bucket_t *headers,
                                            svn_ra_serf__session_t *session);
 
+void
+svn_ra_serf__setup_xml_name_escape(serf_bucket_t *headers,
+                                   svn_ra_serf__session_t *session,
+                                   apr_pool_t *request_pool);
+
 svn_boolean_t
 svn_ra_serf__is_low_latency_connection(svn_ra_serf__session_t *session);
 

Modified: subversion/branches/dav-path-escape/subversion/libsvn_ra_serf/update.c
URL: http://svn.apache.org/viewvc/subversion/branches/dav-path-escape/subversion/libsvn_ra_serf/update.c?rev=1846391&r1=1846390&r2=1846391&view=diff
==============================================================================
--- subversion/branches/dav-path-escape/subversion/libsvn_ra_serf/update.c (original)
+++ subversion/branches/dav-path-escape/subversion/libsvn_ra_serf/update.c Mon Nov 12 10:23:07 2018
@@ -1524,6 +1524,8 @@ update_opened(svn_ra_serf__xml_estate_t
           name = svn_hash_gets(attrs, "name");
           if (!name)
             name = "";
+          name = svn__cntrl_unescape(name, ctx->sess->xml_name_escape,
+                                     scratch_pool);
 
           SVN_ERR(create_dir_baton(&dir, ctx, name, scratch_pool));
 
@@ -1569,11 +1571,14 @@ update_opened(svn_ra_serf__xml_estate_t
       case ADD_FILE:
         {
           file_baton_t *file;
+          const char *name;
 
           attrs = svn_ra_serf__xml_gather_since(xes, entered_state);
+          name = svn_hash_gets(attrs, "name");
+          name = svn__cntrl_unescape(name, ctx->sess->xml_name_escape,
+                                     scratch_pool);
 
-          SVN_ERR(create_file_baton(&file, ctx, svn_hash_gets(attrs, "name"),
-                                    scratch_pool));
+          SVN_ERR(create_file_baton(&file, ctx, name, scratch_pool));
 
           if (entered_state == OPEN_FILE)
             {
@@ -1908,6 +1913,8 @@ update_closed(svn_ra_serf__xml_estate_t
 
           SVN_ERR(ensure_dir_opened(ctx->cur_dir, scratch_pool));
 
+          name = svn__cntrl_unescape(name, ctx->sess->xml_name_escape,
+                                     scratch_pool);
           revstr = svn_hash_gets(attrs, "rev");
 
           if (revstr)
@@ -1931,6 +1938,9 @@ update_closed(svn_ra_serf__xml_estate_t
 
           SVN_ERR(ensure_dir_opened(ctx->cur_dir, scratch_pool));
 
+          name = svn__cntrl_unescape(name, ctx->sess->xml_name_escape,
+                                     scratch_pool);
+
           SVN_ERR(ctx->editor->absent_directory(
                                     svn_relpath_join(ctx->cur_dir->relpath,
                                                      name, scratch_pool),
@@ -1944,6 +1954,9 @@ update_closed(svn_ra_serf__xml_estate_t
 
           SVN_ERR(ensure_dir_opened(ctx->cur_dir, scratch_pool));
 
+          name = svn__cntrl_unescape(name, ctx->sess->xml_name_escape,
+                                     scratch_pool);
+
           SVN_ERR(ctx->editor->absent_file(
                                     svn_relpath_join(ctx->cur_dir->relpath,
                                                      name, scratch_pool),
@@ -2170,6 +2183,8 @@ setup_update_report_headers(serf_bucket_
 
   svn_ra_serf__setup_svndiff_accept_encoding(headers, report->sess);
 
+  svn_ra_serf__setup_xml_name_escape(headers, report->sess, pool);
+
   return SVN_NO_ERROR;
 }
 
@@ -2690,7 +2705,10 @@ make_update_reporter(svn_ra_session_t *r
       make_simple_xml_tag(&buf, "S:include-props", "yes", scratch_pool);
     }
 
-  make_simple_xml_tag(&buf, "S:src-path", report->source, scratch_pool);
+  make_simple_xml_tag(&buf, "S:src-path",
+                      svn__cntrl_escape(report->source, sess->xml_name_escape,
+                                        scratch_pool),
+                      scratch_pool);
 
   if (SVN_IS_VALID_REVNUM(report->target_rev))
     {
@@ -2701,13 +2719,19 @@ make_update_reporter(svn_ra_session_t *r
 
   if (report->destination && *report->destination)
     {
-      make_simple_xml_tag(&buf, "S:dst-path", report->destination,
+      make_simple_xml_tag(&buf, "S:dst-path",
+                          svn__cntrl_escape(report->destination,
+                                            sess->xml_name_escape,
+                                            scratch_pool),
                           scratch_pool);
     }
 
   if (report->update_target && *report->update_target)
     {
-      make_simple_xml_tag(&buf, "S:update-target", report->update_target,
+      make_simple_xml_tag(&buf, "S:update-target",
+                          svn__cntrl_escape(report->update_target,
+                                            sess->xml_name_escape,
+                                            scratch_pool),
                           scratch_pool);
     }
 

Modified: subversion/branches/dav-path-escape/subversion/libsvn_ra_serf/util.c
URL: http://svn.apache.org/viewvc/subversion/branches/dav-path-escape/subversion/libsvn_ra_serf/util.c?rev=1846391&r1=1846390&r2=1846391&view=diff
==============================================================================
--- subversion/branches/dav-path-escape/subversion/libsvn_ra_serf/util.c (original)
+++ subversion/branches/dav-path-escape/subversion/libsvn_ra_serf/util.c Mon Nov 12 10:23:07 2018
@@ -2079,6 +2079,18 @@ svn_ra_serf__setup_svndiff_accept_encodi
     }
 }
 
+void
+svn_ra_serf__setup_xml_name_escape(serf_bucket_t *headers,
+                                   svn_ra_serf__session_t *session,
+                                   apr_pool_t *request_pool)
+{
+  if (session->xml_name_escape)
+    serf_bucket_headers_setn(headers,
+                             SVN_DAV_XML_NAME_ESCAPE_HEADER,
+                             apr_psprintf(request_pool, "%%%02X",
+                                          session->xml_name_escape));
+}
+
 svn_boolean_t
 svn_ra_serf__is_low_latency_connection(svn_ra_serf__session_t *session)
 {

Modified: subversion/branches/dav-path-escape/subversion/libsvn_subr/path.c
URL: http://svn.apache.org/viewvc/subversion/branches/dav-path-escape/subversion/libsvn_subr/path.c?rev=1846391&r1=1846390&r2=1846391&view=diff
==============================================================================
--- subversion/branches/dav-path-escape/subversion/libsvn_subr/path.c (original)
+++ subversion/branches/dav-path-escape/subversion/libsvn_subr/path.c Mon Nov 12 10:23:07 2018
@@ -1319,4 +1319,3 @@ svn_path_resolve_repos_relative_url(cons
 
   return SVN_NO_ERROR;
 }
-

Modified: subversion/branches/dav-path-escape/subversion/libsvn_subr/string.c
URL: http://svn.apache.org/viewvc/subversion/branches/dav-path-escape/subversion/libsvn_subr/string.c?rev=1846391&r1=1846390&r2=1846391&view=diff
==============================================================================
--- subversion/branches/dav-path-escape/subversion/libsvn_subr/string.c (original)
+++ subversion/branches/dav-path-escape/subversion/libsvn_subr/string.c Mon Nov 12 10:23:07 2018
@@ -1577,3 +1577,92 @@ svn_cstring_skip_prefix(const char *str,
       return NULL;
     }
 }
+
+const char *
+svn__cntrl_escape(const char *str,
+                  char escape,
+                  apr_pool_t *pool)
+{
+  svn_stringbuf_t *buf = NULL;
+  const char *p, *next;
+
+  for(p = str; *p; ++p)
+    {
+      if (svn_ctype_iscntrl(*p) || *p == escape)
+        {
+          if (!buf)
+              buf = svn_stringbuf_ncreate(str, p - str, pool);
+          else
+            svn_stringbuf_appendbytes(buf, next, p - next);
+
+          if (*p == escape)
+            {
+              char twice[2];
+              twice[0] = twice[1] = escape;
+              
+              svn_stringbuf_appendbytes(buf, twice, 2);
+            }
+          else
+            {
+              svn_stringbuf_ensure(buf, buf->len + 4);
+              apr_snprintf(buf->data + buf->len, 4, "%c%02X",
+                           escape, (unsigned char)*p);
+              buf->len += 3;
+            }
+
+          next = p + 1;
+        }
+    }
+  if (buf)
+    svn_stringbuf_appendbytes(buf, next, p - next);
+
+  return buf ? buf->data : str;
+}
+
+
+const char *
+svn__cntrl_unescape(const char *str,
+                    char escape,
+                    apr_pool_t *pool)
+{
+  svn_stringbuf_t *buf = NULL;
+  const char *p, *next;
+
+  if (!escape)
+    return str;
+  
+  for(p = str; *p; ++p)
+    {
+      if (p[0] == escape
+          && (p[1] == escape
+              || (svn_ctype_isxdigit(p[1]) && svn_ctype_isxdigit(p[2]))))
+        {
+          if (!buf)
+              buf = svn_stringbuf_ncreate(str, p - str, pool);
+          else
+            svn_stringbuf_appendbytes(buf, next, p - next);
+
+          if (p[1] == escape)
+            {
+              svn_stringbuf_appendbytes(buf, &escape, 1);
+              ++p;
+            }
+          else
+            {
+              char digitz[3], c[1];
+              digitz[0] = p[1];
+              digitz[1] = p[2];
+              digitz[2] = '\0';
+              c[0] = (char)(strtol(digitz, NULL, 16));
+              svn_stringbuf_appendbytes(buf, c, 1);
+              p += 2;
+            }
+
+          next = p + 1;
+        }
+    }
+  if (buf)
+    svn_stringbuf_appendbytes(buf, next, p - next);
+
+  return buf ? buf->data : str;
+}

Modified: subversion/branches/dav-path-escape/subversion/mod_dav_svn/dav_svn.h
URL: http://svn.apache.org/viewvc/subversion/branches/dav-path-escape/subversion/mod_dav_svn/dav_svn.h?rev=1846391&r1=1846390&r2=1846391&view=diff
==============================================================================
--- subversion/branches/dav-path-escape/subversion/mod_dav_svn/dav_svn.h (original)
+++ subversion/branches/dav-path-escape/subversion/mod_dav_svn/dav_svn.h Mon Nov 12 10:23:07 2018
@@ -300,6 +300,8 @@ struct dav_resource_private {
      (ie: /path/to/item?kw=1)? */
   svn_boolean_t keyword_subst;
 
+  char xml_name_escape;
+
   /* whether this resource parameters are fixed and won't change
      between requests. */
   svn_boolean_t idempotent;
@@ -1153,6 +1155,12 @@ apr_status_t dav_svn__location_header_fi
 apr_status_t dav_svn__location_body_filter(ap_filter_t *f,
                                            apr_bucket_brigade *bb);
 
+void
+dav_svn__set_xml_name_encoding(const dav_resource *resource);
+
+const char *
+dav_svn__quote_escape(const char *str, char escape, apr_pool_t *pool);
+
 
 #ifdef __cplusplus
 }

Modified: subversion/branches/dav-path-escape/subversion/mod_dav_svn/liveprops.c
URL: http://svn.apache.org/viewvc/subversion/branches/dav-path-escape/subversion/mod_dav_svn/liveprops.c?rev=1846391&r1=1846390&r2=1846391&view=diff
==============================================================================
--- subversion/branches/dav-path-escape/subversion/mod_dav_svn/liveprops.c (original)
+++ subversion/branches/dav-path-escape/subversion/mod_dav_svn/liveprops.c Mon Nov 12 10:23:07 2018
@@ -39,6 +39,7 @@
 #include "svn_ctype.h"
 
 #include "private/svn_dav_protocol.h"
+#include "private/svn_string_private.h"
 
 #include "dav_svn.h"
 
@@ -676,7 +677,8 @@ insert_prop_internal(const dav_resource
 
       /* drop the leading slash, so it is relative */
       s = resource->info->repos_path + 1;
-      value = apr_xml_quote_string(scratch_pool, s, 1);
+      value = dav_svn__quote_escape(s, resource->info->xml_name_escape,
+                                    scratch_pool);
       break;
 
     case SVN_PROPID_md5_checksum:
@@ -974,6 +976,7 @@ dav_svn__insert_all_liveprops(request_re
       return;
     }
 
+  dav_svn__set_xml_name_encoding(resource);
   iterpool = svn_pool_create(resource->pool);
   for (spec = props; spec->name != NULL; ++spec)
     {

Modified: subversion/branches/dav-path-escape/subversion/mod_dav_svn/reports/get-location-segments.c
URL: http://svn.apache.org/viewvc/subversion/branches/dav-path-escape/subversion/mod_dav_svn/reports/get-location-segments.c?rev=1846391&r1=1846390&r2=1846391&view=diff
==============================================================================
--- subversion/branches/dav-path-escape/subversion/mod_dav_svn/reports/get-location-segments.c (original)
+++ subversion/branches/dav-path-escape/subversion/mod_dav_svn/reports/get-location-segments.c Mon Nov 12 10:23:07 2018
@@ -51,6 +51,7 @@ struct location_segment_baton
   dav_svn__output *output;
   apr_bucket_brigade *bb;
   dav_svn__authz_read_baton arb;
+  char xml_name_escape;
 };
 
 
@@ -84,7 +85,9 @@ location_segment_receiver(svn_location_s
 
   if (segment->path)
     {
-      const char *path_quoted = apr_xml_quote_string(pool, segment->path, 1);
+      const char *path_quoted = dav_svn__quote_escape(segment->path,
+                                                      b->xml_name_escape,
+                                                      pool);
 
       SVN_ERR(dav_svn__brigade_printf(b->bb, b->output,
                            "<S:location-segment path=\"%s\" "
@@ -221,6 +224,7 @@ dav_svn__get_location_segments_report(co
   location_segment_baton.sent_opener = FALSE;
   location_segment_baton.output = output;
   location_segment_baton.bb = bb;
+  location_segment_baton.xml_name_escape = resource->info->xml_name_escape;
   if ((serr = svn_repos_node_location_segments(resource->info->repos->repos,
                                                abs_path, peg_revision,
                                                start_rev, end_rev,

Modified: subversion/branches/dav-path-escape/subversion/mod_dav_svn/reports/log.c
URL: http://svn.apache.org/viewvc/subversion/branches/dav-path-escape/subversion/mod_dav_svn/reports/log.c?rev=1846391&r1=1846390&r2=1846391&view=diff
==============================================================================
--- subversion/branches/dav-path-escape/subversion/mod_dav_svn/reports/log.c (original)
+++ subversion/branches/dav-path-escape/subversion/mod_dav_svn/reports/log.c Mon Nov 12 10:23:07 2018
@@ -71,6 +71,8 @@ struct log_receiver_baton
   /* whether the client can handle encoded binary property values */
   svn_boolean_t encode_binary_props;
 
+  char xml_name_escape;
+
   /* Helper variables to force early bucket brigade flushes */
   int result_count;
   int next_forced_flush;
@@ -144,9 +146,9 @@ start_path_with_copy_from(const char **e
             (lrb->bb, lrb->output,
              "<%s copyfrom-path=\"%s\" copyfrom-rev=\"%ld\"",
              *element,
-             apr_xml_quote_string(pool,
-                                  log_item->copyfrom_path,
-                                  1), /* escape quotes */
+             dav_svn__quote_escape(log_item->copyfrom_path,
+                                   lrb->xml_name_escape,
+                                   pool),
              log_item->copyfrom_rev));
   else
     SVN_ERR(dav_svn__brigade_printf(lrb->bb, lrb->output, "<%s", *element));
@@ -211,7 +213,8 @@ log_change_receiver(void *baton,
               svn_node_kind_to_word(change->node_kind),
               change->text_mod ? "true" : "false",
               change->prop_mod ? "true" : "false",
-              apr_xml_quote_string(scratch_pool, change->path.data, 0),
+              dav_svn__quote_escape(change->path.data, lrb->xml_name_escape,
+                                    scratch_pool),
               close_element));
 
   return SVN_NO_ERROR;
@@ -494,6 +497,7 @@ dav_svn__log_report(const dav_resource *
   lrb.needs_header = TRUE;
   lrb.needs_log_item = TRUE;
   lrb.stack_depth = 0;
+  lrb.xml_name_escape = resource->info->xml_name_escape;
   /* lrb.requested_custom_revprops set above */
 
   lrb.result_count = 0;

Modified: subversion/branches/dav-path-escape/subversion/mod_dav_svn/reports/update.c
URL: http://svn.apache.org/viewvc/subversion/branches/dav-path-escape/subversion/mod_dav_svn/reports/update.c?rev=1846391&r1=1846390&r2=1846391&view=diff
==============================================================================
--- subversion/branches/dav-path-escape/subversion/mod_dav_svn/reports/update.c (original)
+++ subversion/branches/dav-path-escape/subversion/mod_dav_svn/reports/update.c Mon Nov 12 10:23:07 2018
@@ -42,6 +42,7 @@
 
 #include "private/svn_log.h"
 #include "private/svn_fspath.h"
+#include "private/svn_string_private.h"
 
 #include "../dav_svn.h"
 
@@ -96,6 +97,8 @@ typedef struct update_ctx_t {
      resource" and are we advertising support for as much? */
   svn_boolean_t enable_v2_response;
 
+  char xml_name_escape;
+
 } update_ctx_t;
 
 
@@ -283,9 +286,8 @@ absent_helper(svn_boolean_t is_dir,
               (uc->bb, uc->output,
                "<S:absent-%s name=\"%s\"/>" DEBUG_CR,
                DIR_OR_FILE(is_dir),
-               apr_xml_quote_string(pool,
-                                    svn_relpath_basename(path, NULL),
-                                    1)));
+               dav_svn__quote_escape(svn_relpath_basename(path, NULL),
+                                     uc->xml_name_escape, pool)));
     }
 
   return SVN_NO_ERROR;
@@ -330,7 +332,8 @@ add_helper(svn_boolean_t is_dir,
     }
   else
     {
-      const char *qname = apr_xml_quote_string(pool, child->name, 1);
+      const char *qname = dav_svn__quote_escape(child->name,
+                                                uc->xml_name_escape, pool);
       const char *elt;
       const char *real_path = get_real_fs_path(child, pool);
       const char *bc_url_str = "";
@@ -385,7 +388,8 @@ add_helper(svn_boolean_t is_dir,
         }
       else
         {
-          const char *qcopy = apr_xml_quote_string(pool, copyfrom_path, 1);
+          const char *qcopy = dav_svn__quote_escape(copyfrom_path,
+                                                    uc->xml_name_escape, pool);
 
           elt = apr_psprintf(pool,
                              "<S:add-%s name=\"%s\"%s%s "
@@ -427,7 +431,9 @@ open_helper(svn_boolean_t is_dir,
             void **child_baton)
 {
   item_baton_t *child = make_child_baton(parent, path, pool);
-  const char *qname = apr_xml_quote_string(pool, child->name, 1);
+  update_ctx_t *uc = child->uc;
+  const char *qname = dav_svn__quote_escape(child->name,
+                                            uc->xml_name_escape, pool);
 
   SVN_ERR(dav_svn__brigade_printf(child->uc->bb, child->uc->output,
                                   "<S:open-%s name=\"%s\""
@@ -566,9 +572,9 @@ upd_delete_entry(const char *path,
                  apr_pool_t *pool)
 {
   item_baton_t *parent = parent_baton;
-  const char *qname = apr_xml_quote_string(pool,
-                                           svn_relpath_basename(path, NULL),
-                                           1);
+  update_ctx_t *uc = parent->uc;
+  const char *qname = dav_svn__quote_escape(svn_relpath_basename(path, NULL),
+                                            uc->xml_name_escape, pool);
   return dav_svn__brigade_printf(parent->uc->bb, parent->uc->output,
                                  "<S:delete-entry name=\"%s\" rev=\"%ld\"/>"
                                    DEBUG_CR, qname, revision);
@@ -1197,6 +1203,7 @@ dav_svn__update_report(const dav_resourc
     }
 
   uc.svndiff_version = resource->info->svndiff_version;
+  uc.xml_name_escape = resource->info->xml_name_escape;
   uc.compression_level = dav_svn__get_compression_level(resource->info->r);
   uc.resource = resource;
   uc.output = output;

Modified: subversion/branches/dav-path-escape/subversion/mod_dav_svn/repos.c
URL: http://svn.apache.org/viewvc/subversion/branches/dav-path-escape/subversion/mod_dav_svn/repos.c?rev=1846391&r1=1846390&r2=1846391&view=diff
==============================================================================
--- subversion/branches/dav-path-escape/subversion/mod_dav_svn/repos.c (original)
+++ subversion/branches/dav-path-escape/subversion/mod_dav_svn/repos.c Mon Nov 12 10:23:07 2018
@@ -57,6 +57,7 @@
 #include "private/svn_fspath.h"
 #include "private/svn_repos_private.h"
 #include "private/svn_sorts_private.h"
+#include "private/svn_string_private.h"
 
 #include "dav_svn.h"
 
@@ -1821,6 +1822,23 @@ negotiate_encoding_prefs(request_rec *r,
     }
 }
 
+static void
+get_xml_name_encoding(request_rec *r, char *xml_name_escape)
+{
+  const char *val = apr_table_get(r->headers_in,
+                                  SVN_DAV_XML_NAME_ESCAPE_HEADER);
+  char escape;
+
+  if (val && val[0] == '%'
+      && svn_ctype_isxdigit(val[1]) && svn_ctype_isxdigit(val[2])
+      && !val[3])
+    escape = (char)strtoul(val + 1, NULL, 16);
+  else
+    escape = '\x7F';
+
+  *xml_name_escape = escape;
+}
+
 
 /* The only two possible values for a capability. */
 static const char *capability_yes = "yes";
@@ -2269,6 +2287,8 @@ get_resource(request_rec *r,
 
   negotiate_encoding_prefs(r, &comb->priv.svndiff_version);
 
+  get_xml_name_encoding(r, &comb->priv.xml_name_escape);
+
   /* ### and another hack for computing diffs to send to the client */
   comb->priv.delta_base = apr_table_get(r->headers_in,
                                         SVN_DAV_DELTA_BASE_HEADER);
@@ -3127,12 +3147,16 @@ dav_svn__getetag(const dav_resource *res
 
   /* Use the "weak" format of the etag for collections because our GET
      requests on collections include dynamic data (the HEAD revision,
-     the build version of Subversion, etc.). */
+     the build version of Subversion, etc.).
+
+     This etag is used in both the ETag: header and in the XML body of
+     the PROPFIND response, the value must be valid for both uses. We
+     are free to always use '%' to escape as Subversion doesn't ever
+     unescape it. */
   return apr_psprintf(pool, "%s\"%ld/%s\"",
                       resource->collection ? "W/" : "",
                       created_rev,
-                      apr_xml_quote_string(pool,
-                                           resource->info->repos_path, 1));
+                      dav_svn__quote_escape(resource->info->repos_path, '%', pool));
 }
 
 

Modified: subversion/branches/dav-path-escape/subversion/mod_dav_svn/util.c
URL: http://svn.apache.org/viewvc/subversion/branches/dav-path-escape/subversion/mod_dav_svn/util.c?rev=1846391&r1=1846390&r2=1846391&view=diff
==============================================================================
--- subversion/branches/dav-path-escape/subversion/mod_dav_svn/util.c (original)
+++ subversion/branches/dav-path-escape/subversion/mod_dav_svn/util.c Mon Nov 12 10:23:07 2018
@@ -1000,3 +1000,18 @@ dav_svn__fuzzy_escape_author(const char
 
   return apr_xml_quote_string(result_pool, author, 1);
 }
+
+void
+dav_svn__set_xml_name_encoding(const dav_resource *resource)
+{
+  apr_table_set(resource->info->r->headers_out,
+                SVN_DAV_XML_NAME_ESCAPE_HEADER,
+                apr_psprintf(resource->pool, "%%%02X",
+                             resource->info->xml_name_escape));
+}
+
+const char *
+dav_svn__quote_escape(const char *str, char escape, apr_pool_t *pool)
+{
+  return apr_xml_quote_string(pool, svn__cntrl_escape(str, escape, pool), 1);
+}

Modified: subversion/branches/dav-path-escape/subversion/mod_dav_svn/version.c
URL: http://svn.apache.org/viewvc/subversion/branches/dav-path-escape/subversion/mod_dav_svn/version.c?rev=1846391&r1=1846390&r2=1846391&view=diff
==============================================================================
--- subversion/branches/dav-path-escape/subversion/mod_dav_svn/version.c (original)
+++ subversion/branches/dav-path-escape/subversion/mod_dav_svn/version.c Mon Nov 12 10:23:07 2018
@@ -370,6 +370,9 @@ get_option(const dav_resource *resource,
                      apr_pstrdup(r->pool, capabilities[i].capability_name));
     }
 
+  /* FIXME: check master version */
+  apr_table_set(r->headers_out, SVN_DAV_XML_NAME_ESCAPE_HEADER, "%25");
+
   return NULL;
 }
 
@@ -1115,7 +1118,6 @@ report_label_header_allowed(const apr_xm
   return 0;
 }
 
-
 static dav_error *
 deliver_report(request_rec *r,
                const dav_resource *resource,
@@ -1134,6 +1136,7 @@ deliver_report(request_rec *r,
 
       if (strcmp(doc->root->name, "update-report") == 0)
         {
+          dav_svn__set_xml_name_encoding(resource);
           return dav_svn__update_report(resource, doc, output);
         }
       else if (strcmp(doc->root->name, "log-report") == 0)