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

svn commit: r1846002 [13/44] - in /subversion/branches/ra-git: ./ build/ build/ac-macros/ build/generator/ build/generator/swig/ build/generator/templates/ build/generator/util/ build/win32/ contrib/client-side/ contrib/client-side/svn_load_dirs/ contr...

Modified: subversion/branches/ra-git/subversion/libsvn_ra_serf/ra_serf.h
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_ra_serf/ra_serf.h?rev=1846002&r1=1846001&r2=1846002&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_ra_serf/ra_serf.h (original)
+++ subversion/branches/ra-git/subversion/libsvn_ra_serf/ra_serf.h Wed Nov  7 12:30:06 2018
@@ -113,8 +113,12 @@ struct svn_ra_serf__session_t {
   /* Are we using ssl */
   svn_boolean_t using_ssl;
 
-  /* Should we use compression for network transmissions? */
-  svn_boolean_t using_compression;
+  /* Tristate flag that indicates if we should use compression for
+     network transmissions.  If svn_tristate_true or svn_tristate_false,
+     the compression should be enabled and disabled, respectively.
+     If svn_tristate_unknown, determine this automatically based
+     on network parameters. */
+  svn_tristate_t using_compression;
 
   /* The user agent string */
   const char *useragent;
@@ -261,6 +265,15 @@ struct svn_ra_serf__session_t {
 
   /* Indicates whether the server can understand svndiff version 1. */
   svn_boolean_t supports_svndiff1;
+
+  /* Indicates whether the server can understand svndiff version 2. */
+  svn_boolean_t supports_svndiff2;
+
+  /* Indicates whether the server sends the result checksum in the response
+   * to a successful PUT request. */
+  svn_boolean_t supports_put_result_checksum;
+
+  apr_interval_time_t conn_latency;
 };
 
 #define SVN_RA_SERF__HAVE_HTTPV2_SUPPORT(sess) ((sess)->me_resource != NULL)
@@ -1418,6 +1431,18 @@ svn_ra_serf__get_locks(svn_ra_session_t
                        svn_depth_t depth,
                        apr_pool_t *pool);
 
+/* Implements svn_ra__vtable_t.list(). */
+svn_error_t *
+svn_ra_serf__list(svn_ra_session_t *ra_session,
+                  const char *path,
+                  svn_revnum_t revision,
+                  const apr_array_header_t *patterns,
+                  svn_depth_t depth,
+                  apr_uint32_t dirent_fields,
+                  svn_ra_dirent_receiver_t receiver,
+                  void *receiver_baton,
+                  apr_pool_t *scratch_pool);
+
 /* Request a mergeinfo-report from the URL attached to SESSION,
    and fill in the MERGEINFO hash with the results.
 
@@ -1568,6 +1593,24 @@ svn_ra_serf__uri_parse(apr_uri_t *uri,
                        const char *url_str,
                        apr_pool_t *result_pool);
 
+/* Setup the "Accept-Encoding" header value for requests that expect
+   svndiff-encoded deltas, depending on the SESSION state. */
+void
+svn_ra_serf__setup_svndiff_accept_encoding(serf_bucket_t *headers,
+                                           svn_ra_serf__session_t *session);
+
+svn_boolean_t
+svn_ra_serf__is_low_latency_connection(svn_ra_serf__session_t *session);
+
+/* Return an APR array of svn_ra_serf__dav_props_t containing the
+ * properties (names and namespaces) corresponding to the flegs set
+ * in DIRENT_FIELDS.  If SESSION does not support deadprops, only
+ * the generic "DAV:allprop" will be returned.  Allocate the result
+ * in RESULT_POOL. */
+apr_array_header_t *
+svn_ra_serf__get_dirent_props(apr_uint32_t dirent_fields,
+                              svn_ra_serf__session_t *session,
+                              apr_pool_t *result_pool);
 
 /* Default limit for in-memory size of a request body. */
 #define SVN_RA_SERF__REQUEST_BODY_IN_MEM_SIZE 256 * 1024
@@ -1601,6 +1644,19 @@ svn_error_t *
 svn_ra_serf__request_body_cleanup(svn_ra_serf__request_body_t *body,
                                   apr_pool_t *scratch_pool);
 
+/* Callback used in svn_ra_serf__create_stream_bucket().  ERR will be
+   will be cleared and becomes invalid after the callback returns,
+   use svn_error_dup() to preserve it. */
+typedef void
+(*svn_ra_serf__stream_bucket_errfunc_t)(void *baton, svn_error_t *err);
+
+/* Create a bucket that wraps a generic readable STREAM.  This function
+   takes ownership of the passed-in stream, and will close it. */
+serf_bucket_t *
+svn_ra_serf__create_stream_bucket(svn_stream_t *stream,
+                                  serf_bucket_alloc_t *allocator,
+                                  svn_ra_serf__stream_bucket_errfunc_t errfunc,
+                                  void *errfunc_baton);
 
 #if defined(SVN_DEBUG)
 /* Wrapper macros to collect file and line information */

Modified: subversion/branches/ra-git/subversion/libsvn_ra_serf/replay.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_ra_serf/replay.c?rev=1846002&r1=1846001&r2=1846002&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_ra_serf/replay.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_ra_serf/replay.c Wed Nov  7 12:30:06 2018
@@ -166,6 +166,8 @@ typedef struct revision_report_t {
   svn_ra_serf__handler_t *propfind_handler;
   svn_ra_serf__handler_t *report_handler; /* For done handler */
 
+  svn_ra_serf__session_t *session;
+
 } revision_report_t;
 
 /* Conforms to svn_ra_serf__xml_opened_t */
@@ -630,6 +632,20 @@ replay_done(serf_request_t *request,
   return SVN_NO_ERROR;
 }
 
+/* Implements svn_ra_serf__request_header_delegate_t */
+static svn_error_t *
+setup_headers(serf_bucket_t *headers,
+              void *baton,
+              apr_pool_t *request_pool,
+              apr_pool_t *scratch_pool)
+{
+  struct revision_report_t *ctx = baton;
+
+  svn_ra_serf__setup_svndiff_accept_encoding(headers, ctx->session);
+
+  return SVN_NO_ERROR;
+}
+
 svn_error_t *
 svn_ra_serf__replay_range(svn_ra_session_t *ra_session,
                           svn_revnum_t start_revision,
@@ -685,7 +701,7 @@ svn_ra_serf__replay_range(svn_ra_session
      wish for the best.
 
      See issue #4287:
-     http://subversion.tigris.org/issues/show_bug.cgi?id=4287
+     https://issues.apache.org/jira/browse/SVN-4287
   */
   if (session->supports_rev_rsrc_replay)
     {
@@ -724,6 +740,7 @@ svn_ra_serf__replay_range(svn_ra_session
           rev_ctx->revision = rev;
           rev_ctx->low_water_mark = low_water_mark;
           rev_ctx->send_deltas = send_deltas;
+          rev_ctx->session = session;
 
           /* Request all properties of a certain revision. */
           rev_ctx->rev_props = apr_hash_make(rev_ctx->pool);
@@ -781,6 +798,10 @@ svn_ra_serf__replay_range(svn_ra_session
           handler->done_delegate = replay_done;
           handler->done_delegate_baton = rev_ctx;
 
+          handler->custom_accept_encoding = TRUE;
+          handler->header_delegate = setup_headers;
+          handler->header_delegate_baton = rev_ctx;
+
           rev_ctx->report_handler = handler;
           svn_ra_serf__request_create(handler);
 

Modified: subversion/branches/ra-git/subversion/libsvn_ra_serf/serf.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_ra_serf/serf.c?rev=1846002&r1=1846001&r2=1846002&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_ra_serf/serf.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_ra_serf/serf.c Wed Nov  7 12:30:06 2018
@@ -180,9 +180,10 @@ load_config(svn_ra_serf__session_t *sess
       config_client = NULL;
     }
 
-  SVN_ERR(svn_config_get_bool(config, &session->using_compression,
-                              SVN_CONFIG_SECTION_GLOBAL,
-                              SVN_CONFIG_OPTION_HTTP_COMPRESSION, TRUE));
+  SVN_ERR(svn_config_get_tristate(config, &session->using_compression,
+                                  SVN_CONFIG_SECTION_GLOBAL,
+                                  SVN_CONFIG_OPTION_HTTP_COMPRESSION,
+                                  "auto", svn_tristate_unknown));
   svn_config_get(config, &timeout_str, SVN_CONFIG_SECTION_GLOBAL,
                  SVN_CONFIG_OPTION_HTTP_TIMEOUT, NULL);
 
@@ -266,10 +267,10 @@ load_config(svn_ra_serf__session_t *sess
 
   if (server_group)
     {
-      SVN_ERR(svn_config_get_bool(config, &session->using_compression,
-                                  server_group,
-                                  SVN_CONFIG_OPTION_HTTP_COMPRESSION,
-                                  session->using_compression));
+      SVN_ERR(svn_config_get_tristate(config, &session->using_compression,
+                                      server_group,
+                                      SVN_CONFIG_OPTION_HTTP_COMPRESSION,
+                                      "auto", session->using_compression));
       svn_config_get(config, &timeout_str, server_group,
                      SVN_CONFIG_OPTION_HTTP_TIMEOUT, timeout_str);
 
@@ -593,6 +594,10 @@ svn_ra_serf__open(svn_ra_session_t *sess
                  && apr_pool_is_ancestor(serf_sess->pool, scratch_pool));
 #endif
 
+  /* The actual latency will be determined as a part of the initial
+     OPTIONS request. */
+  serf_sess->conn_latency = -1;
+
   err = svn_ra_serf__exchange_capabilities(serf_sess, corrected_url,
                                            result_pool, scratch_pool);
 
@@ -686,7 +691,7 @@ ra_serf_dup_session(svn_ra_session_t *ne
 
   if (new_sess->proxy_password)
     {
-      new_sess->proxy_username
+      new_sess->proxy_password
                 = apr_pstrdup(result_pool, new_sess->proxy_password);
     }
 
@@ -752,6 +757,9 @@ ra_serf_dup_session(svn_ra_session_t *ne
   /* svn_boolean_t supports_inline_props */
   /* supports_rev_rsrc_replay */
   /* supports_svndiff1 */
+  /* supports_svndiff2 */
+  /* supports_put_result_checksum */
+  /* conn_latency */
 
   new_sess->context = serf_context_create(result_pool);
 
@@ -1055,7 +1063,7 @@ static const svn_ra__vtable_t serf_vtabl
   svn_ra_serf__get_deleted_rev,
   svn_ra_serf__get_inherited_props,
   NULL /* set_svn_ra_open */,
-  NULL /* svn_ra_list */,
+  svn_ra_serf__list,
   svn_ra_serf__register_editor_shim_callbacks,
   NULL /* commit_ev2 */,
   NULL /* replay_range_ev2 */

Modified: subversion/branches/ra-git/subversion/libsvn_ra_serf/stat.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_ra_serf/stat.c?rev=1846002&r1=1846001&r2=1846002&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_ra_serf/stat.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_ra_serf/stat.c Wed Nov  7 12:30:06 2018
@@ -216,64 +216,8 @@ get_dirent_props(apr_uint32_t dirent_fie
                  apr_pool_t *pool)
 {
   svn_ra_serf__dav_props_t *prop;
-  apr_array_header_t *props = apr_array_make
-    (pool, 7, sizeof(svn_ra_serf__dav_props_t));
-
-  if (session->supports_deadprop_count != svn_tristate_false
-      || ! (dirent_fields & SVN_DIRENT_HAS_PROPS))
-    {
-      if (dirent_fields & SVN_DIRENT_KIND)
-        {
-          prop = apr_array_push(props);
-          prop->xmlns = "DAV:";
-          prop->name = "resourcetype";
-        }
-
-      if (dirent_fields & SVN_DIRENT_SIZE)
-        {
-          prop = apr_array_push(props);
-          prop->xmlns = "DAV:";
-          prop->name = "getcontentlength";
-        }
-
-      if (dirent_fields & SVN_DIRENT_HAS_PROPS)
-        {
-          prop = apr_array_push(props);
-          prop->xmlns = SVN_DAV_PROP_NS_DAV;
-          prop->name = "deadprop-count";
-        }
-
-      if (dirent_fields & SVN_DIRENT_CREATED_REV)
-        {
-          svn_ra_serf__dav_props_t *p = apr_array_push(props);
-          p->xmlns = "DAV:";
-          p->name = SVN_DAV__VERSION_NAME;
-        }
-
-      if (dirent_fields & SVN_DIRENT_TIME)
-        {
-          prop = apr_array_push(props);
-          prop->xmlns = "DAV:";
-          prop->name = SVN_DAV__CREATIONDATE;
-        }
-
-      if (dirent_fields & SVN_DIRENT_LAST_AUTHOR)
-        {
-          prop = apr_array_push(props);
-          prop->xmlns = "DAV:";
-          prop->name = "creator-displayname";
-        }
-    }
-  else
-    {
-      /* We found an old subversion server that can't handle
-         the deadprop-count property in the way we expect.
-
-         The neon behavior is to retrieve all properties in this case */
-      prop = apr_array_push(props);
-      prop->xmlns = "DAV:";
-      prop->name = "allprop";
-    }
+  apr_array_header_t *props = svn_ra_serf__get_dirent_props(dirent_fields,
+                                                            session, pool);
 
   prop = apr_array_push(props);
   prop->xmlns = NULL;

Modified: subversion/branches/ra-git/subversion/libsvn_ra_serf/update.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_ra_serf/update.c?rev=1846002&r1=1846001&r2=1846002&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_ra_serf/update.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_ra_serf/update.c Wed Nov  7 12:30:06 2018
@@ -365,7 +365,7 @@ typedef struct fetch_ctx_t {
   /* The handler representing this particular fetch.  */
   svn_ra_serf__handler_t *handler;
 
-  svn_boolean_t using_compression;
+  svn_ra_serf__session_t *session;
 
   /* Stores the information for the file we want to fetch. */
   file_baton_t *file;
@@ -603,7 +603,7 @@ get_best_connection(report_context_t *ct
      ### simply can't handle the way ra_serf violates the editor v1
      ### drive ordering requirements.
      ###
-     ### See http://subversion.tigris.org/issues/show_bug.cgi?id=4116.
+     ### See https://issues.apache.org/jira/browse/SVN-4116.
   */
   if (ctx->report_received && (ctx->sess->max_connections > 2))
     first_conn = 0;
@@ -797,19 +797,9 @@ headers_fetch(serf_bucket_t *headers,
     {
       serf_bucket_headers_setn(headers, SVN_DAV_DELTA_BASE_HEADER,
                                fetch_ctx->delta_base);
-      if (fetch_ctx->using_compression)
-        {
-          serf_bucket_headers_setn(headers, "Accept-Encoding",
-                                   "svndiff1;q=0.9,svndiff;q=0.8");
-        }
-      else
-        {
-          /* Do not advertise svndiff1 support if we're not interested in
-             compression. */
-          serf_bucket_headers_setn(headers, "Accept-Encoding", "svndiff");
-        }
+      svn_ra_serf__setup_svndiff_accept_encoding(headers, fetch_ctx->session);
     }
-  else if (fetch_ctx->using_compression)
+  else if (fetch_ctx->session->using_compression != svn_tristate_false)
     {
       serf_bucket_headers_setn(headers, "Accept-Encoding", "gzip");
     }
@@ -1287,7 +1277,7 @@ fetch_for_file(file_baton_t *file,
 
           fetch_ctx = apr_pcalloc(file->pool, sizeof(*fetch_ctx));
           fetch_ctx->file = file;
-          fetch_ctx->using_compression = ctx->sess->using_compression;
+          fetch_ctx->session = ctx->sess;
 
           /* Can we somehow get away with just obtaining a DIFF? */
           if (SVN_RA_SERF__HAVE_HTTPV2_SUPPORT(ctx->sess))
@@ -2178,17 +2168,7 @@ setup_update_report_headers(serf_bucket_
 {
   report_context_t *report = baton;
 
-  if (report->sess->using_compression)
-    {
-      serf_bucket_headers_setn(headers, "Accept-Encoding",
-                               "gzip,svndiff1;q=0.9,svndiff;q=0.8");
-    }
-  else
-    {
-      /* Do not advertise svndiff1 support if we're not interested in
-         compression. */
-      serf_bucket_headers_setn(headers, "Accept-Encoding", "svndiff");
-    }
+  svn_ra_serf__setup_svndiff_accept_encoding(headers, report->sess);
 
   return SVN_NO_ERROR;
 }

Modified: subversion/branches/ra-git/subversion/libsvn_ra_serf/util.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_ra_serf/util.c?rev=1846002&r1=1846001&r2=1846002&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_ra_serf/util.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_ra_serf/util.c Wed Nov  7 12:30:06 2018
@@ -756,6 +756,9 @@ handle_client_cert_pw(void *data,
 
     if (creds)
       {
+        /* At this stage we are unable to check whether the password
+           is correct; if it is incorrect serf will fail to establish
+           an SSL connection and will return a generic SSL error. */
         svn_auth_cred_ssl_client_cert_pw_t *pw_creds;
         pw_creds = creds;
         *password = pw_creds->password;
@@ -1445,6 +1448,23 @@ handle_response(serf_request_t *request,
 
  process_body:
 
+  /* A client cert file password was obtained and worked (any HTTP
+     response means that the SSL connection was established.) */
+  if (handler->conn->ssl_client_pw_auth_state)
+    {
+      SVN_ERR(svn_auth_save_credentials(handler->conn->ssl_client_pw_auth_state,
+                                        handler->session->pool));
+      handler->conn->ssl_client_pw_auth_state = NULL;
+    }
+  if (handler->conn->ssl_client_auth_state)
+    {
+      /* The cert file provider doesn't have any code to save creds so
+         this is currently a no-op. */
+      SVN_ERR(svn_auth_save_credentials(handler->conn->ssl_client_auth_state,
+                                        handler->session->pool));
+      handler->conn->ssl_client_auth_state = NULL;
+    }
+
   /* We've been instructed to ignore the body. Drain whatever is present.  */
   if (handler->discard_body)
     {
@@ -1571,7 +1591,7 @@ setup_request(serf_request_t *request,
     {
       accept_encoding = NULL;
     }
-  else if (handler->session->using_compression)
+  else if (handler->session->using_compression != svn_tristate_false)
     {
       /* Accept gzip compression if enabled. */
       accept_encoding = "gzip";
@@ -2023,3 +2043,114 @@ svn_ra_serf__uri_parse(apr_uri_t *uri,
 
   return SVN_NO_ERROR;
 }
+
+void
+svn_ra_serf__setup_svndiff_accept_encoding(serf_bucket_t *headers,
+                                           svn_ra_serf__session_t *session)
+{
+  if (session->using_compression == svn_tristate_false)
+    {
+      /* Don't advertise support for compressed svndiff formats if
+         compression is disabled. */
+      serf_bucket_headers_setn(
+        headers, "Accept-Encoding", "svndiff");
+    }
+  else if (session->using_compression == svn_tristate_unknown &&
+           svn_ra_serf__is_low_latency_connection(session))
+    {
+      /* With http-compression=auto, advertise that we prefer svndiff2
+         to svndiff1 with a low latency connection (assuming the underlying
+         network has high bandwidth), as it is faster and in this case, we
+         don't care about worse compression ratio. */
+      serf_bucket_headers_setn(
+        headers, "Accept-Encoding",
+        "gzip,svndiff2;q=0.9,svndiff1;q=0.8,svndiff;q=0.7");
+    }
+  else
+    {
+      /* Otherwise, advertise that we prefer svndiff1 over svndiff2.
+         svndiff2 is not a reasonable substitute for svndiff1 with default
+         compression level, because, while it is faster, it also gives worse
+         compression ratio.  While we can use svndiff2 in some cases (see
+         above), we can't do this generally. */
+      serf_bucket_headers_setn(
+        headers, "Accept-Encoding",
+        "gzip,svndiff1;q=0.9,svndiff2;q=0.8,svndiff;q=0.7");
+    }
+}
+
+svn_boolean_t
+svn_ra_serf__is_low_latency_connection(svn_ra_serf__session_t *session)
+{
+  return session->conn_latency >= 0 &&
+         session->conn_latency < apr_time_from_msec(5);
+}
+
+apr_array_header_t *
+svn_ra_serf__get_dirent_props(apr_uint32_t dirent_fields,
+                              svn_ra_serf__session_t *session,
+                              apr_pool_t *result_pool)
+{
+  svn_ra_serf__dav_props_t *prop;
+  apr_array_header_t *props = apr_array_make
+    (result_pool, 7, sizeof(svn_ra_serf__dav_props_t));
+
+  if (session->supports_deadprop_count != svn_tristate_false
+      || ! (dirent_fields & SVN_DIRENT_HAS_PROPS))
+    {
+      if (dirent_fields & SVN_DIRENT_KIND)
+        {
+          prop = apr_array_push(props);
+          prop->xmlns = "DAV:";
+          prop->name = "resourcetype";
+        }
+
+      if (dirent_fields & SVN_DIRENT_SIZE)
+        {
+          prop = apr_array_push(props);
+          prop->xmlns = "DAV:";
+          prop->name = "getcontentlength";
+        }
+
+      if (dirent_fields & SVN_DIRENT_HAS_PROPS)
+        {
+          prop = apr_array_push(props);
+          prop->xmlns = SVN_DAV_PROP_NS_DAV;
+          prop->name = "deadprop-count";
+        }
+
+      if (dirent_fields & SVN_DIRENT_CREATED_REV)
+        {
+          svn_ra_serf__dav_props_t *p = apr_array_push(props);
+          p->xmlns = "DAV:";
+          p->name = SVN_DAV__VERSION_NAME;
+        }
+
+      if (dirent_fields & SVN_DIRENT_TIME)
+        {
+          prop = apr_array_push(props);
+          prop->xmlns = "DAV:";
+          prop->name = SVN_DAV__CREATIONDATE;
+        }
+
+      if (dirent_fields & SVN_DIRENT_LAST_AUTHOR)
+        {
+          prop = apr_array_push(props);
+          prop->xmlns = "DAV:";
+          prop->name = "creator-displayname";
+        }
+    }
+  else
+    {
+      /* We found an old subversion server that can't handle
+         the deadprop-count property in the way we expect.
+
+         The neon behavior is to retrieve all properties in this case */
+      prop = apr_array_push(props);
+      prop->xmlns = "DAV:";
+      prop->name = "allprop";
+    }
+
+  return props;
+}
+

Modified: subversion/branches/ra-git/subversion/libsvn_ra_svn/client.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_ra_svn/client.c?rev=1846002&r1=1846001&r2=1846002&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_ra_svn/client.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_ra_svn/client.c Wed Nov  7 12:30:06 2018
@@ -46,6 +46,7 @@
 #include "svn_props.h"
 #include "svn_mergeinfo.h"
 #include "svn_version.h"
+#include "svn_ctype.h"
 
 #include "svn_private_config.h"
 
@@ -398,7 +399,7 @@ static svn_error_t *find_tunnel_agent(co
        * versions have it too. If the user is using some other ssh
        * implementation that doesn't accept it, they can override it
        * in the [tunnels] section of the config. */
-      val = "$SVN_SSH ssh -q";
+      val = "$SVN_SSH ssh -q --";
     }
 
   if (!val || !*val)
@@ -443,7 +444,7 @@ static svn_error_t *find_tunnel_agent(co
   for (n = 0; cmd_argv[n] != NULL; n++)
     argv[n] = cmd_argv[n];
 
-  argv[n++] = svn_path_uri_decode(hostinfo, pool);
+  argv[n++] = hostinfo;
   argv[n++] = "svnserve";
   argv[n++] = "-t";
   argv[n] = NULL;
@@ -629,11 +630,17 @@ static svn_error_t *open_session(svn_ra_
   svn_ra_svn__list_t *mechlist, *server_caplist, *repos_caplist;
   const char *client_string = NULL;
   apr_pool_t *pool = result_pool;
+  svn_ra_svn__parent_t *parent;
+
+  parent = apr_pcalloc(pool, sizeof(*parent));
+  parent->client_url = svn_stringbuf_create(url, pool);
+  parent->server_url = svn_stringbuf_create(url, pool);
+  parent->path = svn_stringbuf_create_empty(pool);
 
   sess = apr_palloc(pool, sizeof(*sess));
   sess->pool = pool;
   sess->is_tunneled = (tunnel_name != NULL);
-  sess->url = apr_pstrdup(pool, url);
+  sess->parent = parent;
   sess->user = uri->user;
   sess->hostname = uri->hostname;
   sess->tunnel_name = tunnel_name;
@@ -740,10 +747,11 @@ static svn_error_t *open_session(svn_ra_
    * capability list, and the URL, and subsequently there is an auth
    * request. */
   /* Client-side capabilities list: */
-  SVN_ERR(svn_ra_svn__write_tuple(conn, pool, "n(wwwwww)cc(?c)",
+  SVN_ERR(svn_ra_svn__write_tuple(conn, pool, "n(wwwwwww)cc(?c)",
                                   (apr_uint64_t) 2,
                                   SVN_RA_SVN_CAP_EDIT_PIPELINE,
                                   SVN_RA_SVN_CAP_SVNDIFF1,
+                                  SVN_RA_SVN_CAP_SVNDIFF2_ACCEPTED,
                                   SVN_RA_SVN_CAP_ABSENT_ENTRIES,
                                   SVN_RA_SVN_CAP_DEPTH,
                                   SVN_RA_SVN_CAP_MERGEINFO,
@@ -804,6 +812,32 @@ ra_svn_get_schemes(apr_pool_t *pool)
 }
 
 
+/* A simple whitelist to ensure the following are valid:
+ *   user@server
+ *   [::1]:22
+ *   server-name
+ *   server_name
+ *   127.0.0.1
+ * with an extra restriction that a leading '-' is invalid.
+ */
+static svn_boolean_t
+is_valid_hostinfo(const char *hostinfo)
+{
+  const char *p = hostinfo;
+
+  if (p[0] == '-')
+    return FALSE;
+
+  while (*p)
+    {
+      if (!svn_ctype_isalnum(*p) && !strchr(":.-_[]@", *p))
+        return FALSE;
+
+      ++p;
+    }
+
+  return TRUE;
+}
 
 static svn_error_t *ra_svn_open(svn_ra_session_t *session,
                                 const char **corrected_url,
@@ -837,8 +871,18 @@ static svn_error_t *ra_svn_open(svn_ra_s
           || (callbacks->check_tunnel_func && callbacks->open_tunnel_func
               && !callbacks->check_tunnel_func(callbacks->tunnel_baton,
                                                tunnel))))
-    SVN_ERR(find_tunnel_agent(tunnel, uri.hostinfo, &tunnel_argv, config,
-                              result_pool));
+    {
+      const char *decoded_hostinfo;
+
+      decoded_hostinfo = svn_path_uri_decode(uri.hostinfo, result_pool);
+
+      if (!is_valid_hostinfo(decoded_hostinfo))
+        return svn_error_createf(SVN_ERR_BAD_URL, NULL, _("Invalid host '%s'"),
+                                 uri.hostinfo);
+
+      SVN_ERR(find_tunnel_agent(tunnel, decoded_hostinfo, &tunnel_argv,
+                                config, result_pool));
+    }
   else
     tunnel_argv = NULL;
 
@@ -877,23 +921,29 @@ static svn_error_t *ra_svn_dup_session(s
   return SVN_NO_ERROR;
 }
 
-static svn_error_t *ra_svn_reparent(svn_ra_session_t *ra_session,
-                                    const char *url,
-                                    apr_pool_t *pool)
+/* Send the "reparent to URL" command to the server for RA_SESSION and
+   update the session state.  Use SCRATCH_POOL for tempoaries.
+ */
+static svn_error_t *
+reparent_server(svn_ra_session_t *ra_session,
+                const char *url,
+                apr_pool_t *scratch_pool)
 {
   svn_ra_svn__session_baton_t *sess = ra_session->priv;
+  svn_ra_svn__parent_t *parent = sess->parent;
   svn_ra_svn_conn_t *conn = sess->conn;
   svn_error_t *err;
   apr_pool_t *sess_pool;
   svn_ra_svn__session_baton_t *new_sess;
   apr_uri_t uri;
 
-  SVN_ERR(svn_ra_svn__write_cmd_reparent(conn, pool, url));
-  err = handle_auth_request(sess, pool);
+  /* Send the request to the server. */
+  SVN_ERR(svn_ra_svn__write_cmd_reparent(conn, scratch_pool, url));
+  err = handle_auth_request(sess, scratch_pool);
   if (! err)
     {
-      SVN_ERR(svn_ra_svn__read_cmd_response(conn, pool, ""));
-      sess->url = apr_pstrdup(sess->pool, url);
+      SVN_ERR(svn_ra_svn__read_cmd_response(conn, scratch_pool, ""));
+      svn_stringbuf_set(parent->server_url, url);
       return SVN_NO_ERROR;
     }
   else if (err->apr_err != SVN_ERR_RA_SVN_UNKNOWN_CMD)
@@ -924,11 +974,143 @@ static svn_error_t *ra_svn_reparent(svn_
   return SVN_NO_ERROR;
 }
 
+/* Make sure that RA_SESSION's client and server-side parent infp are in
+   sync.  Use SCRATCH_POOL for temporary allocations. */
+static svn_error_t *
+ensure_exact_server_parent(svn_ra_session_t *ra_session,
+                           apr_pool_t *scratch_pool)
+{
+  svn_ra_svn__session_baton_t *sess = ra_session->priv;
+  svn_ra_svn__parent_t *parent = sess->parent;
+
+  /* During e.g. a checkout operation, many requests will be sent for the
+     same URL that was used to create the session.  So, both sides are
+     often already in sync. */
+  if (svn_stringbuf_compare(parent->client_url, parent->server_url))
+    return SVN_NO_ERROR;
+
+  /* Actually reparent the server to the session URL. */
+  SVN_ERR(reparent_server(ra_session, parent->client_url->data,
+                          scratch_pool));
+  svn_stringbuf_setempty(parent->path);
+
+  return SVN_NO_ERROR;
+}
+
+/* Return a copy of PATH, adjusted to the RA_SESSION's server parent URL.
+   Allocate the result in RESULT_POOL. */
+static const char *
+reparent_path(svn_ra_session_t *ra_session,
+              const char *path,
+              apr_pool_t *result_pool)
+{
+  svn_ra_svn__session_baton_t *sess = ra_session->priv;
+  svn_ra_svn__parent_t *parent = sess->parent;
+
+  return svn_relpath_join(parent->path->data, path, result_pool);
+}
+
+/* Return a copy of PATHS, containing the same const char * paths but
+   adjusted to the RA_SESSION's server parent URL.  Returns NULL if
+   PATHS is NULL.  Allocate the result in RESULT_POOL. */
+static apr_array_header_t *
+reparent_path_array(svn_ra_session_t *ra_session,
+                    const apr_array_header_t *paths,
+                    apr_pool_t *result_pool)
+{
+  int i;
+  apr_array_header_t *result;
+
+  if (!paths)
+    return NULL;
+
+  result = apr_array_copy(result_pool, paths);
+  for (i = 0; i < result->nelts; ++i)
+    {
+      const char **path = &APR_ARRAY_IDX(result, i, const char *);
+      *path = reparent_path(ra_session, *path, result_pool);
+    }
+
+  return result;
+}
+
+/* Return a copy of PATHS, containing the same paths for keys but adjusted
+   to the RA_SESSION's server parent URL.  Keeps the values as-are and
+   returns NULL if PATHS is NULL.  Allocate the result in RESULT_POOL. */
+static apr_hash_t *
+reparent_path_hash(svn_ra_session_t *ra_session,
+                   apr_hash_t *paths,
+                   apr_pool_t *result_pool,
+                   apr_pool_t *scratch_pool)
+{
+  apr_hash_t *result;
+  apr_hash_index_t *hi;
+
+  if (!paths)
+    return NULL;
+
+  result = svn_hash__make(result_pool);
+  for (hi = apr_hash_first(scratch_pool, paths); hi; hi = apr_hash_next(hi))
+    {
+      const char *path = apr_hash_this_key(hi);
+      svn_hash_sets(result,
+                    reparent_path(ra_session, path, result_pool),
+                    apr_hash_this_val(hi));
+    }
+
+  return result;
+}
+
+static svn_error_t *ra_svn_reparent(svn_ra_session_t *ra_session,
+                                    const char *url,
+                                    apr_pool_t *pool)
+{
+  svn_ra_svn__session_baton_t *sess = ra_session->priv;
+  svn_ra_svn__parent_t *parent = sess->parent;
+  svn_ra_svn_conn_t *conn = sess->conn;
+  const char *path;
+
+  /* Eliminate reparent requests if they are to a sub-path of the
+     server's current parent path. */
+  path = svn_uri_skip_ancestor(parent->server_url->data, url, pool);
+  if (!path)
+    {
+      /* Send the request to the server.
+
+         If within the same repository, reparent to the repo root
+         because this will maximize the chance to turn future reparent
+         requests into a client-side update of the rel path. */
+      path = conn->repos_root
+           ? svn_uri_skip_ancestor(conn->repos_root, url, pool)
+           : NULL;
+
+      if (path)
+        SVN_ERR(reparent_server(ra_session, conn->repos_root, pool));
+      else
+        SVN_ERR(reparent_server(ra_session, url, pool));
+    }
+
+  /* Update the local PARENT information.
+     PARENT.SERVER_BASE_URL is already up-to-date. */
+  svn_stringbuf_set(parent->client_url, url);
+  if (path)
+    svn_stringbuf_set(parent->path, path);
+  else
+    svn_stringbuf_setempty(parent->path);
+
+  return SVN_NO_ERROR;
+}
+
 static svn_error_t *ra_svn_get_session_url(svn_ra_session_t *session,
-                                           const char **url, apr_pool_t *pool)
+                                           const char **url,
+                                           apr_pool_t *pool)
 {
   svn_ra_svn__session_baton_t *sess = session->priv;
-  *url = apr_pstrdup(pool, sess->url);
+  svn_ra_svn__parent_t *parent = sess->parent;
+
+  *url = apr_pstrmemdup(pool, parent->client_url->data,
+                        parent->client_url->len);
+
   return SVN_NO_ERROR;
 }
 
@@ -1137,6 +1319,9 @@ static svn_error_t *ra_svn_commit(svn_ra
                     svn_string_create(sess_baton->useragent, pool));
     }
 
+  /* Callbacks may assume that all data is relative the sessions's URL. */
+  SVN_ERR(ensure_exact_server_parent(session, pool));
+
   /* Tell the server we're starting the commit.
      Send log message here for backwards compatibility with servers
      before 1.5. */
@@ -1262,6 +1447,7 @@ static svn_error_t *ra_svn_get_file(svn_
   svn_checksum_ctx_t *checksum_ctx;
   apr_pool_t *iterpool;
 
+  path = reparent_path(session, path, pool);
   SVN_ERR(svn_ra_svn__write_cmd_get_file(conn, pool, path, rev,
                                          (props != NULL), (stream != NULL)));
   SVN_ERR(handle_auth_request(sess_baton, pool));
@@ -1367,6 +1553,7 @@ static svn_error_t *ra_svn_get_dir(svn_r
   svn_ra_svn__list_t *proplist, *dirlist;
   int i;
 
+  path = reparent_path(session, path, pool);
   SVN_ERR(svn_ra_svn__write_tuple(conn, pool, "w(c(?r)bb(!", "get-dir", path,
                                   rev, (props != NULL), (dirents != NULL)));
   SVN_ERR(send_dirent_fields(conn, dirent_fields, pool));
@@ -1463,12 +1650,14 @@ static svn_error_t *ra_svn_get_mergeinfo
                                          apr_pool_t *pool)
 {
   svn_ra_svn__session_baton_t *sess_baton = session->priv;
+  svn_ra_svn__parent_t *parent = sess_baton->parent;
   svn_ra_svn_conn_t *conn = sess_baton->conn;
   int i;
   svn_ra_svn__list_t *mergeinfo_tuple;
   svn_ra_svn__item_t *elt;
   const char *path;
 
+  paths = reparent_path_array(session, paths, pool);
   SVN_ERR(svn_ra_svn__write_tuple(conn, pool, "w((!", "get-mergeinfo"));
   for (i = 0; i < paths->nelts; i++)
     {
@@ -1498,9 +1687,16 @@ static svn_error_t *ra_svn_get_mergeinfo
           SVN_ERR(svn_ra_svn__parse_tuple(&elt->u.list, "cc",
                                           &path, &to_parse));
           SVN_ERR(svn_mergeinfo_parse(&for_path, to_parse, pool));
+
           /* Correct for naughty servers that send "relative" paths
              with leading slashes! */
-          svn_hash_sets(*catalog, path[0] == '/' ? path + 1 :path, for_path);
+          if (path[0] == '/')
+            ++path;
+
+          /* Correct for the (potential) difference between client and
+             server-side session parent paths. */
+          path = svn_relpath_skip_ancestor(parent->path->data, path);
+          svn_hash_sets(*catalog, path, for_path);
         }
     }
 
@@ -1522,6 +1718,9 @@ static svn_error_t *ra_svn_update(svn_ra
   svn_ra_svn_conn_t *conn = sess_baton->conn;
   svn_boolean_t recurse = DEPTH_TO_RECURSE(depth);
 
+  /* Callbacks may assume that all data is relative the sessions's URL. */
+  SVN_ERR(ensure_exact_server_parent(session, scratch_pool));
+
   /* Tell the server we want to start an update. */
   SVN_ERR(svn_ra_svn__write_cmd_update(conn, pool, rev, target, recurse,
                                        depth, send_copyfrom_args,
@@ -1553,6 +1752,9 @@ ra_svn_switch(svn_ra_session_t *session,
   svn_ra_svn_conn_t *conn = sess_baton->conn;
   svn_boolean_t recurse = DEPTH_TO_RECURSE(depth);
 
+  /* Callbacks may assume that all data is relative the sessions's URL. */
+  SVN_ERR(ensure_exact_server_parent(session, scratch_pool));
+
   /* Tell the server we want to start a switch. */
   SVN_ERR(svn_ra_svn__write_cmd_switch(conn, pool, rev, target, recurse,
                                        switch_url, depth,
@@ -1578,6 +1780,9 @@ static svn_error_t *ra_svn_status(svn_ra
   svn_ra_svn_conn_t *conn = sess_baton->conn;
   svn_boolean_t recurse = DEPTH_TO_RECURSE(depth);
 
+  /* Callbacks may assume that all data is relative the sessions's URL. */
+  SVN_ERR(ensure_exact_server_parent(session, pool));
+
   /* Tell the server we want to start a status operation. */
   SVN_ERR(svn_ra_svn__write_cmd_status(conn, pool, target, recurse, rev,
                                        depth));
@@ -1605,6 +1810,9 @@ static svn_error_t *ra_svn_diff(svn_ra_s
   svn_ra_svn_conn_t *conn = sess_baton->conn;
   svn_boolean_t recurse = DEPTH_TO_RECURSE(depth);
 
+  /* Callbacks may assume that all data is relative the sessions's URL. */
+  SVN_ERR(ensure_exact_server_parent(session, pool));
+
   /* Tell the server we want to start a diff. */
   SVN_ERR(svn_ra_svn__write_cmd_diff(conn, pool, rev, target, recurse,
                                      ignore_ancestry, versus_url,
@@ -1869,6 +2077,16 @@ ra_svn_log(svn_ra_session_t *session,
   svn_error_t *outer_error = NULL;
   svn_error_t *err;
 
+  /* If we don't specify paths, the session's URL is implied.
+
+     Because the paths passed to callbacks are always relative the repos
+     root, there is no need *always* sync the parent URLs despite invoking
+     user-provided callbacks. */
+  if (paths)
+    paths = reparent_path_array(session, paths, pool);
+  else
+    SVN_ERR(ensure_exact_server_parent(session, pool));
+
   err = svn_error_trace(perform_ra_svn_log(&outer_error,
                                            session, paths,
                                            start, end,
@@ -1894,6 +2112,7 @@ static svn_error_t *ra_svn_check_path(sv
   svn_ra_svn_conn_t *conn = sess_baton->conn;
   const char *kind_word;
 
+  path = reparent_path(session, path, pool);
   SVN_ERR(svn_ra_svn__write_cmd_check_path(conn, pool, path, rev));
   SVN_ERR(handle_auth_request(sess_baton, pool));
   SVN_ERR(svn_ra_svn__read_cmd_response(conn, pool, "w", &kind_word));
@@ -1923,6 +2142,7 @@ static svn_error_t *ra_svn_stat(svn_ra_s
   svn_ra_svn__list_t *list = NULL;
   svn_dirent_t *the_dirent;
 
+  path = reparent_path(session, path, pool);
   SVN_ERR(svn_ra_svn__write_cmd_stat(conn, pool, path, rev));
   SVN_ERR(handle_unsupported_cmd(handle_auth_request(sess_baton, pool),
                                  N_("'stat' not implemented")));
@@ -1972,6 +2192,8 @@ static svn_error_t *ra_svn_get_locations
   apr_pool_t *iterpool;
   int i;
 
+  path = reparent_path(session, path, pool);
+
   /* Transmit the parameters. */
   SVN_ERR(svn_ra_svn__write_tuple(conn, pool, "w(cr(!",
                                   "get-locations", path, peg_revision));
@@ -2114,6 +2336,7 @@ ra_svn_get_location_segments(svn_ra_sess
   svn_error_t *outer_err = SVN_NO_ERROR;
   svn_error_t *err;
 
+  path = reparent_path(session, path, pool);
   err = svn_error_trace(
             perform_get_location_segments(&outer_err, session, path,
                                           peg_revision, start_rev, end_rev,
@@ -2138,6 +2361,7 @@ static svn_error_t *ra_svn_get_file_revs
   rev_pool = svn_pool_create(pool);
   chunk_pool = svn_pool_create(pool);
 
+  path = reparent_path(session, path, pool);
   SVN_ERR(svn_ra_svn__write_cmd_get_file_revs(sess_baton->conn, pool,
                                               path, start, end,
                                               include_merged_revisions));
@@ -2376,6 +2600,7 @@ static svn_error_t *ra_svn_lock(svn_ra_s
   svn_error_t *err;
   apr_pool_t *iterpool = svn_pool_create(pool);
 
+  path_revs = reparent_path_hash(session, path_revs, pool, pool);
   SVN_ERR(svn_ra_svn__write_tuple(conn, pool, "w((?c)b(!", "lock-many",
                                   comment, steal_lock));
 
@@ -2500,6 +2725,7 @@ static svn_error_t *ra_svn_unlock(svn_ra
   svn_error_t *err;
   const char *path;
 
+  path_tokens = reparent_path_hash(session, path_tokens, pool, pool);
   SVN_ERR(svn_ra_svn__write_tuple(conn, pool, "w(b(!", "unlock-many",
                                   break_lock));
 
@@ -2619,6 +2845,7 @@ static svn_error_t *ra_svn_get_lock(svn_
   svn_ra_svn_conn_t* conn = sess->conn;
   svn_ra_svn__list_t *list;
 
+  path = reparent_path(session, path, pool);
   SVN_ERR(svn_ra_svn__write_cmd_get_lock(conn, pool, path));
 
   /* Servers before 1.2 doesn't support locking.  Check this here. */
@@ -2667,7 +2894,8 @@ static svn_error_t *ra_svn_get_locks(svn
   int i;
 
   /* Figure out the repository abspath from PATH. */
-  full_url = svn_path_url_add_component2(sess->url, path, pool);
+  full_url = svn_path_url_add_component2(sess->parent->client_url->data,
+                                         path, pool);
   SVN_ERR(path_relative_to_root(session, &abs_path, full_url, pool));
   abs_path = svn_fspath__canonicalize(abs_path, pool);
 
@@ -2728,6 +2956,9 @@ static svn_error_t *ra_svn_replay(svn_ra
 {
   svn_ra_svn__session_baton_t *sess = session->priv;
 
+  /* Complex EDITOR callbacks may rely on client and server parent path
+     being in sync. */
+  SVN_ERR(ensure_exact_server_parent(session, pool));
   SVN_ERR(svn_ra_svn__write_cmd_replay(sess->conn, pool, revision,
                                        low_water_mark, send_deltas));
 
@@ -2758,6 +2989,9 @@ ra_svn_replay_range(svn_ra_session_t *se
   svn_revnum_t rev;
   svn_boolean_t drive_aborted = FALSE;
 
+  /* Complex EDITOR callbacks may rely on client and server parent path
+     being in sync. */
+  SVN_ERR(ensure_exact_server_parent(session, pool));
   SVN_ERR(svn_ra_svn__write_cmd_replay_range(sess->conn, pool,
                                              start_revision, end_revision,
                                              low_water_mark, send_deltas));
@@ -2872,6 +3106,8 @@ ra_svn_get_deleted_rev(svn_ra_session_t
   svn_ra_svn__session_baton_t *sess_baton = session->priv;
   svn_ra_svn_conn_t *conn = sess_baton->conn;
 
+  path = reparent_path(session, path, pool);
+
   /* Transmit the parameters. */
   SVN_ERR(svn_ra_svn__write_cmd_get_deleted_rev(conn, pool, path,
                                                peg_revision, end_revision));
@@ -2909,6 +3145,7 @@ ra_svn_get_inherited_props(svn_ra_sessio
   svn_ra_svn__list_t *iproplist;
   svn_boolean_t iprop_capable;
 
+  path = reparent_path(session, path, scratch_pool);
   SVN_ERR(ra_svn_has_capability(session, &iprop_capable,
                                 SVN_RA_CAPABILITY_INHERITED_PROPS,
                                 scratch_pool));
@@ -2932,7 +3169,7 @@ static svn_error_t *
 ra_svn_list(svn_ra_session_t *session,
             const char *path,
             svn_revnum_t revision,
-            apr_array_header_t *patterns,
+            const apr_array_header_t *patterns,
             svn_depth_t depth,
             apr_uint32_t dirent_fields,
             svn_ra_dirent_receiver_t receiver,
@@ -2944,6 +3181,8 @@ ra_svn_list(svn_ra_session_t *session,
   int i;
   apr_pool_t *iterpool = svn_pool_create(scratch_pool);
 
+  path = reparent_path(session, path, scratch_pool);
+
   /* Send the list request. */
   SVN_ERR(svn_ra_svn__write_tuple(conn, scratch_pool, "w(c(?r)w(!", "list",
                                   path, revision, svn_depth_to_word(depth)));

Modified: subversion/branches/ra-git/subversion/libsvn_ra_svn/editorp.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_ra_svn/editorp.c?rev=1846002&r1=1846001&r2=1846002&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_ra_svn/editorp.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_ra_svn/editorp.c Wed Nov  7 12:30:06 2018
@@ -351,15 +351,9 @@ static svn_error_t *ra_svn_apply_textdel
   svn_stream_set_write(diff_stream, ra_svn_svndiff_handler);
   svn_stream_set_close(diff_stream, ra_svn_svndiff_close_handler);
 
-  /* If the connection does not support SVNDIFF1 or if we don't want to use
-   * compression, use the non-compressing "version 0" implementation */
-  if (   svn_ra_svn_compression_level(b->conn) > 0
-      && svn_ra_svn_has_capability(b->conn, SVN_RA_SVN_CAP_SVNDIFF1))
-    svn_txdelta_to_svndiff3(wh, wh_baton, diff_stream, 1,
-                            b->conn->compression_level, pool);
-  else
-    svn_txdelta_to_svndiff3(wh, wh_baton, diff_stream, 0,
-                            b->conn->compression_level, pool);
+  svn_txdelta_to_svndiff3(wh, wh_baton, diff_stream,
+                          svn_ra_svn__svndiff_version(b->conn),
+                          b->conn->compression_level, pool);
   return SVN_NO_ERROR;
 }
 

Modified: subversion/branches/ra-git/subversion/libsvn_ra_svn/marshal.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_ra_svn/marshal.c?rev=1846002&r1=1846001&r2=1846002&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_ra_svn/marshal.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_ra_svn/marshal.c Wed Nov  7 12:30:06 2018
@@ -265,6 +265,24 @@ svn_ra_svn__set_capabilities(svn_ra_svn_
   return SVN_NO_ERROR;
 }
 
+int
+svn_ra_svn__svndiff_version(svn_ra_svn_conn_t *conn)
+{
+  /* If we don't want to use compression, use the non-compressing
+   * "version 0" implementation. */
+  if (svn_ra_svn_compression_level(conn) <= 0)
+    return 0;
+
+  /* Prefer SVNDIFF2 over SVNDIFF1. */
+  if (svn_ra_svn_has_capability(conn, SVN_RA_SVN_CAP_SVNDIFF2_ACCEPTED))
+    return 2;
+  if (svn_ra_svn_has_capability(conn, SVN_RA_SVN_CAP_SVNDIFF1))
+    return 1;
+
+  /* The connection does not support SVNDIFF1/2; default to "version 0". */
+  return 0;
+}
+
 apr_pool_t *
 svn_ra_svn__get_pool(svn_ra_svn_conn_t *conn)
 {
@@ -1142,10 +1160,17 @@ static svn_error_t *vwrite_tuple(svn_ra_
         SVN_ERR(opt ? vwrite_tuple_string_opt(conn, pool, ap)
                     : vwrite_tuple_string(conn, pool, ap));
       else if (*fmt == '(' && !opt)
-        SVN_ERR(write_tuple_start_list(conn, pool));
+        {
+          /* Optional sub-tuples are not supported.
+           * If OPT was set, we would fall through to the malfunction call. */
+          SVN_ERR(write_tuple_start_list(conn, pool));
+        }
       else if (*fmt == ')')
         {
           SVN_ERR(write_tuple_end_list(conn, pool));
+
+          /* OPT could not have been set when opening the list (see above),
+           * hence this is correct and handles nested tuples just fine. */
           opt = FALSE;
         }
       else if (*fmt == '?')
@@ -2921,7 +2946,7 @@ svn_ra_svn__write_dirent(svn_ra_svn_conn
                          apr_pool_t *pool,
                          const char *path,
                          svn_dirent_t *dirent,
-                         apr_uint64_t dirent_fields)
+                         apr_uint32_t dirent_fields)
 {
   const char *kind = (dirent_fields & SVN_DIRENT_KIND)
                    ? svn_node_kind_to_word(dirent->kind)

Modified: subversion/branches/ra-git/subversion/libsvn_ra_svn/protocol
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_ra_svn/protocol?rev=1846002&r1=1846001&r2=1846002&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_ra_svn/protocol (original)
+++ subversion/branches/ra-git/subversion/libsvn_ra_svn/protocol Wed Nov  7 12:30:06 2018
@@ -188,6 +188,10 @@ capability and C indicates a client capa
 [CS] svndiff1          If both the client and server support svndiff version
                        1, this will be used as the on-the-wire format for 
                        svndiff instead of svndiff version 0.
+[CS] accepts-svndiff2  This capability advertises support for accepting
+                       svndiff2 deltas.  The sender of a delta (= the editor
+                       driver) may send it in any svndiff version the receiver
+                       has announced it can accept.
 [CS] absent-entries    If the remote end announces support for this capability,
                        it will accept the absent-dir and absent-file editor
                        commands.
@@ -338,7 +342,7 @@ second place for auth-request point as n
   stat
     params:   ( path:string [ rev:number ] )
     response: ( ? entry:dirent )
-    dirent:   ( name:string kind:node-kind size:number has-props:bool
+    dirent:   ( kind:node-kind size:number has-props:bool
                 created-rev:number [ created-date:string ]
                 [ last-author:string ] )
     New in svn 1.2.  If path is non-existent, an empty response is returned.

Modified: subversion/branches/ra-git/subversion/libsvn_ra_svn/ra_svn.h
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_ra_svn/ra_svn.h?rev=1846002&r1=1846001&r2=1846002&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_ra_svn/ra_svn.h (original)
+++ subversion/branches/ra-git/subversion/libsvn_ra_svn/ra_svn.h Wed Nov  7 12:30:06 2018
@@ -125,12 +125,30 @@ struct svn_ra_svn_conn_st {
   apr_pool_t *pool;
 };
 
+/* The session's URL state for client and server side.
+ *
+ * This keeps track of the respective client-side and server-side "parent"
+ * URLs.  It tells us whether we may have to send reparent commands to the
+ * server and how to tweak path parameters when we decided to handle
+ * reparent requests on the client side only. */
+typedef struct svn_ra_svn__parent_t {
+  /* Client-side session base URL, i.e. client's parent path. */
+  svn_stringbuf_t *client_url;
+
+  /* Server-side base URL, i.e. server's parent path. */
+  svn_stringbuf_t *server_url;
+
+  /* Relative path to add to a client-side parameter to translate it for the
+   * server-side.  I.e. the relative path from SERVER_URL to CLIENT_URL. */
+  svn_stringbuf_t *path;
+} svn_ra_svn__parent_t;
+
 struct svn_ra_svn__session_baton_t {
   apr_pool_t *pool;
   svn_ra_svn_conn_t *conn;
   svn_boolean_t is_tunneled;
   svn_auth_baton_t *auth_baton;
-  const char *url;
+  svn_ra_svn__parent_t *parent;
   const char *user;
   const char *hostname; /* The remote hostname. */
   const char *realm_prefix;