Modified: subversion/branches/addremove/subversion/libsvn_ra_serf/commit.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/libsvn_ra_serf/commit.c?rev=1805769&r1=1805768&r2=1805769&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/libsvn_ra_serf/commit.c (original)
+++ subversion/branches/addremove/subversion/libsvn_ra_serf/commit.c Tue Aug 22 
14:19:36 2017
@@ -176,12 +176,18 @@ typedef struct file_context_t {
   /* Buffer holding the svndiff (can spill to disk). */
   svn_ra_serf__request_body_t *svndiff;
 
+  /* Did we send the svndiff in apply_textdelta_stream()? */
+  svn_boolean_t svndiff_sent;
+
   /* Our base checksum as reported by the WC. */
   const char *base_checksum;
 
   /* Our resulting checksum as reported by the WC. */
   const char *result_checksum;
 
+  /* Our resulting checksum as reported by the server. */
+  svn_checksum_t *remote_result_checksum;
+
   /* Changed properties (const char * -> svn_prop_t *) */
   apr_hash_t *prop_changes;
 
@@ -1859,61 +1865,50 @@ open_file(const char *path,
   return SVN_NO_ERROR;
 }
 
-static svn_error_t *
-apply_textdelta(void *file_baton,
-                const char *base_checksum,
-                apr_pool_t *pool,
-                svn_txdelta_window_handler_t *handler,
-                void **handler_baton)
+static void
+negotiate_put_encoding(int *svndiff_version_p,
+                       int *svndiff_compression_level_p,
+                       svn_ra_serf__session_t *session)
 {
-  file_context_t *ctx = file_baton;
   int svndiff_version;
   int compression_level;
 
-  /* Construct a holder for the request body; we'll give it to serf when we
-   * close this file.
-   *
-   * TODO: There should be a way we can stream the request body instead of
-   * possibly writing to a temporary file (ugh). A special svn stream serf
-   * bucket that returns EAGAIN until we receive the done call?  But, when
-   * would we run through the serf context?  Grr.
-   *
-   * BH: If you wait to a specific event... why not use that event to
-   *     trigger the operation?
-   *     Having a request (body) bucket return EAGAIN until done stalls
-   *     the entire HTTP pipeline after writing the first part of the
-   *     request. It is not like we can interrupt some part of a request
-   *     and continue later. Or somebody else must use tempfiles and
-   *     always assume that clients work this bad... as it only knows
-   *     for sure after the request is completely available.
-   */
-
-  ctx->svndiff =
-    svn_ra_serf__request_body_create(SVN_RA_SERF__REQUEST_BODY_IN_MEM_SIZE,
-                                     ctx->pool);
-  ctx->stream = svn_ra_serf__request_body_get_stream(ctx->svndiff);
-
-  if (ctx->commit_ctx->session->supports_svndiff1 &&
-      ctx->commit_ctx->session->using_compression)
+  if (session->using_compression == svn_tristate_unknown)
     {
-      /* Prefer svndiff1 when using http compression, as svndiff2 is not a
+      /* With http-compression=auto, 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.
+       *
+       * Note: For future compatibility, we also handle a theoretically
+       * possible case where the server has advertised only svndiff2 support.
+       */
+      if (session->supports_svndiff2 &&
+          svn_ra_serf__is_low_latency_connection(session))
+        svndiff_version = 2;
+      else if (session->supports_svndiff1)
+        svndiff_version = 1;
+      else if (session->supports_svndiff2)
+        svndiff_version = 2;
+      else
+        svndiff_version = 0;
+    }
+  else if (session->using_compression == svn_tristate_true)
+    {
+      /* Otherwise, prefer svndiff1, as svndiff2 is not a reasonable
        * substitute for svndiff1 with default compression level.  (It gives
        * better speed and compression ratio comparable to svndiff1 with
        * compression level 1, but not 5).
        *
-       * It might make sense to tweak the current format negotiation scheme
-       * so that the server would say which versions of svndiff it accepts,
-       * _including_ the preferred order.  This would allow us to dynamically
-       * pick svndiff2 if that's what the server thinks is appropriate.
+       * Note: For future compatibility, we also handle a theoretically
+       * possible case where the server has advertised only svndiff2 support.
        */
-      svndiff_version = 1;
-      compression_level = SVN_DELTA_COMPRESSION_LEVEL_DEFAULT;
-    }
-  else if (ctx->commit_ctx->session->supports_svndiff2 &&
-           ctx->commit_ctx->session->using_compression)
-    {
-      svndiff_version = 2;
-      compression_level = SVN_DELTA_COMPRESSION_LEVEL_NONE;
+      if (session->supports_svndiff1)
+        svndiff_version = 1;
+      else if (session->supports_svndiff2)
+        svndiff_version = 2;
+      else
+        svndiff_version = 0;
     }
   else
     {
@@ -1928,9 +1923,46 @@ apply_textdelta(void *file_baton,
        * client configuration option, if they want to.
        */
       svndiff_version = 0;
-      compression_level = SVN_DELTA_COMPRESSION_LEVEL_NONE;
     }
 
+  if (svndiff_version == 0)
+    compression_level = SVN_DELTA_COMPRESSION_LEVEL_NONE;
+  else
+    compression_level = SVN_DELTA_COMPRESSION_LEVEL_DEFAULT;
+
+  *svndiff_version_p = svndiff_version;
+  *svndiff_compression_level_p = compression_level;
+}
+
+static svn_error_t *
+apply_textdelta(void *file_baton,
+                const char *base_checksum,
+                apr_pool_t *pool,
+                svn_txdelta_window_handler_t *handler,
+                void **handler_baton)
+{
+  file_context_t *ctx = file_baton;
+  int svndiff_version;
+  int compression_level;
+
+  /* Construct a holder for the request body; we'll give it to serf when we
+   * close this file.
+   *
+   * Please note that if this callback is used, large request bodies will
+   * be spilled into temporary files (that requires disk space and prevents
+   * simultaneous processing by the server and the client).  A better approach
+   * that streams the request body is implemented in apply_textdelta_stream().
+   * It will be used with most recent servers having the "send result checksum
+   * in response to a PUT" capability, and only if the editor driver uses the
+   * new callback.
+   */
+  ctx->svndiff =
+    svn_ra_serf__request_body_create(SVN_RA_SERF__REQUEST_BODY_IN_MEM_SIZE,
+                                     ctx->pool);
+  ctx->stream = svn_ra_serf__request_body_get_stream(ctx->svndiff);
+
+  negotiate_put_encoding(&svndiff_version, &compression_level,
+                         ctx->commit_ctx->session);
   /* Disown the stream; we'll close it explicitly in close_file(). */
   svn_txdelta_to_svndiff3(handler, handler_baton,
                           svn_stream_disown(ctx->stream, pool),
@@ -1942,6 +1974,146 @@ apply_textdelta(void *file_baton,
   return SVN_NO_ERROR;
 }
 
+typedef struct open_txdelta_baton_t
+{
+  svn_ra_serf__session_t *session;
+  svn_txdelta_stream_open_func_t open_func;
+  void *open_baton;
+  svn_error_t *err;
+} open_txdelta_baton_t;
+
+static void
+txdelta_stream_errfunc(void *baton, svn_error_t *err)
+{
+  open_txdelta_baton_t *b = baton;
+
+  /* Remember extended error info from the stream bucket.  Note that
+   * theoretically this errfunc could be called multiple times -- say,
+   * if the request gets restarted after an error.  Compose the errors
+   * so we don't leak one of them if this happens. */
+  b->err = svn_error_compose_create(b->err, svn_error_dup(err));
+}
+
+/* Implements svn_ra_serf__request_body_delegate_t */
+static svn_error_t *
+create_body_from_txdelta_stream(serf_bucket_t **body_bkt,
+                                void *baton,
+                                serf_bucket_alloc_t *alloc,
+                                apr_pool_t *pool /* request pool */,
+                                apr_pool_t *scratch_pool)
+{
+  open_txdelta_baton_t *b = baton;
+  svn_txdelta_stream_t *txdelta_stream;
+  svn_stream_t *stream;
+  int svndiff_version;
+  int compression_level;
+
+  SVN_ERR(b->open_func(&txdelta_stream, b->open_baton, pool, scratch_pool));
+
+  negotiate_put_encoding(&svndiff_version, &compression_level, b->session);
+  stream = svn_txdelta_to_svndiff_stream(txdelta_stream, svndiff_version,
+                                         compression_level, pool);
+  *body_bkt = svn_ra_serf__create_stream_bucket(stream, alloc,
+                                                txdelta_stream_errfunc, b);
+
+  return SVN_NO_ERROR;
+}
+
+/* Handler baton for PUT request. */
+typedef struct put_response_ctx_t
+{
+  svn_ra_serf__handler_t *handler;
+  file_context_t *file_ctx;
+} put_response_ctx_t;
+
+/* Implements svn_ra_serf__response_handler_t */
+static svn_error_t *
+put_response_handler(serf_request_t *request,
+                     serf_bucket_t *response,
+                     void *baton,
+                     apr_pool_t *scratch_pool)
+{
+  put_response_ctx_t *prc = baton;
+  serf_bucket_t *hdrs;
+  const char *val;
+
+  hdrs = serf_bucket_response_get_headers(response);
+  val = serf_bucket_headers_get(hdrs, SVN_DAV_RESULT_FULLTEXT_MD5_HEADER);
+  SVN_ERR(svn_checksum_parse_hex(&prc->file_ctx->remote_result_checksum,
+                                 svn_checksum_md5, val, prc->file_ctx->pool));
+
+  return svn_error_trace(
+           svn_ra_serf__expect_empty_body(request, response,
+                                          prc->handler, scratch_pool));
+}
+
+static svn_error_t *
+apply_textdelta_stream(const svn_delta_editor_t *editor,
+                       void *file_baton,
+                       const char *base_checksum,
+                       svn_txdelta_stream_open_func_t open_func,
+                       void *open_baton,
+                       apr_pool_t *scratch_pool)
+{
+  file_context_t *ctx = file_baton;
+  open_txdelta_baton_t open_txdelta_baton = {0};
+  svn_ra_serf__handler_t *handler;
+  put_response_ctx_t *prc;
+  int expected_result;
+  svn_error_t *err;
+
+  /* Remember that we have sent the svndiff.  A case when we need to
+   * perform a zero-byte file PUT (during add_file, close_file editor
+   * sequences) is handled in close_file().
+   */
+  ctx->svndiff_sent = TRUE;
+  ctx->base_checksum = base_checksum;
+
+  handler = svn_ra_serf__create_handler(ctx->commit_ctx->session,
+                                        scratch_pool);
+  handler->method = "PUT";
+  handler->path = ctx->url;
+
+  prc = apr_pcalloc(scratch_pool, sizeof(*prc));
+  prc->handler = handler;
+  prc->file_ctx = ctx;
+
+  handler->response_handler = put_response_handler;
+  handler->response_baton = prc;
+
+  open_txdelta_baton.session = ctx->commit_ctx->session;
+  open_txdelta_baton.open_func = open_func;
+  open_txdelta_baton.open_baton = open_baton;
+  open_txdelta_baton.err = SVN_NO_ERROR;
+
+  handler->body_delegate = create_body_from_txdelta_stream;
+  handler->body_delegate_baton = &open_txdelta_baton;
+  handler->body_type = SVN_SVNDIFF_MIME_TYPE;
+
+  handler->header_delegate = setup_put_headers;
+  handler->header_delegate_baton = ctx;
+
+  err = svn_ra_serf__context_run_one(handler, scratch_pool);
+  /* Do we have an error from the stream bucket?  If yes, use it. */
+  if (open_txdelta_baton.err)
+    {
+      svn_error_clear(err);
+      return svn_error_trace(open_txdelta_baton.err);
+    }
+  else if (err)
+    return svn_error_trace(err);
+
+  if (ctx->added && !ctx->copy_path)
+    expected_result = 201; /* Created */
+  else
+    expected_result = 204; /* Updated */
+
+  if (handler->sline.code != expected_result)
+    return svn_error_trace(svn_ra_serf__unexpected_status(handler));
+
+  return SVN_NO_ERROR;
+}
+
 static svn_error_t *
 change_file_prop(void *file_baton,
                  const char *name,
@@ -1977,8 +2149,8 @@ close_file(void *file_baton,
   if ((!ctx->svndiff) && ctx->added && (!ctx->copy_path))
     put_empty_file = TRUE;
 
-  /* If we had a stream of changes, push them to the server... */
-  if (ctx->svndiff || put_empty_file)
+  /* If we have a stream of changes, push them to the server... */
+  if ((ctx->svndiff || put_empty_file) && !ctx->svndiff_sent)
     {
       svn_ra_serf__handler_t *handler;
       int expected_result;
@@ -2043,6 +2215,22 @@ close_file(void *file_baton,
                                  proppatch, scratch_pool));
     }
 
+  if (ctx->result_checksum && ctx->remote_result_checksum)
+    {
+      svn_checksum_t *result_checksum;
+
+      SVN_ERR(svn_checksum_parse_hex(&result_checksum, svn_checksum_md5,
+                                     ctx->result_checksum, scratch_pool));
+
+      if (!svn_checksum_match(result_checksum, ctx->remote_result_checksum))
+        return svn_checksum_mismatch_err(result_checksum,
+                                         ctx->remote_result_checksum,
+                                         scratch_pool,
+                                         _("Checksum mismatch for '%s'"),
+                                         svn_dirent_local_style(ctx->relpath,
+                                                                scratch_pool));
+    }
+
   ctx->commit_ctx->open_batons--;
 
   return SVN_NO_ERROR;
@@ -2218,6 +2406,12 @@ svn_ra_serf__get_commit_editor(svn_ra_se
   editor->close_file = close_file;
   editor->close_edit = close_edit;
   editor->abort_edit = abort_edit;
+  /* Only install the callback that allows streaming PUT request bodies
+   * if the server has the necessary capability.  Otherwise, this will
+   * fallback to the default implementation using the temporary files.
+   * See default_editor.c:apply_textdelta_stream(). */
+  if (session->supports_put_result_checksum)
+    editor->apply_textdelta_stream = apply_textdelta_stream;
 
   *ret_editor = editor;
   *edit_baton = ctx;

Modified: subversion/branches/addremove/subversion/libsvn_ra_serf/get_file.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/libsvn_ra_serf/get_file.c?rev=1805769&r1=1805768&r2=1805769&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/libsvn_ra_serf/get_file.c 
(original)
+++ subversion/branches/addremove/subversion/libsvn_ra_serf/get_file.c Tue Aug 
22 14:19:36 2017
@@ -60,7 +60,7 @@ typedef struct stream_ctx_t {
   /* Have we read our response headers yet? */
   svn_boolean_t read_headers;
 
-  svn_boolean_t using_compression;
+  svn_ra_serf__session_t *session;
 
   /* This flag is set when our response is aborted before we reach the
    * end and we decide to requeue this request.
@@ -88,7 +88,7 @@ headers_fetch(serf_bucket_t *headers,
 {
   stream_ctx_t *fetch_ctx = baton;
 
-  if (fetch_ctx->using_compression)
+  if (fetch_ctx->session->using_compression != svn_tristate_false)
     {
       serf_bucket_headers_setn(headers, "Accept-Encoding", "gzip");
     }
@@ -396,7 +396,7 @@ svn_ra_serf__get_file(svn_ra_session_t *
           /* Create the fetch context. */
           stream_ctx = apr_pcalloc(scratch_pool, sizeof(*stream_ctx));
           stream_ctx->result_stream = stream;
-          stream_ctx->using_compression = session->using_compression;
+          stream_ctx->session = session;
 
           handler = svn_ra_serf__create_handler(session, scratch_pool);
 

Modified: subversion/branches/addremove/subversion/libsvn_ra_serf/options.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/libsvn_ra_serf/options.c?rev=1805769&r1=1805768&r2=1805769&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/libsvn_ra_serf/options.c (original)
+++ subversion/branches/addremove/subversion/libsvn_ra_serf/options.c Tue Aug 
22 14:19:36 2017
@@ -237,6 +237,10 @@ capabilities_headers_iterator_callback(v
           /* Same for svndiff2. */
           session->supports_svndiff2 = TRUE;
         }
+      if (svn_cstring_match_list(SVN_DAV_NS_DAV_SVN_PUT_RESULT_CHECKSUM, vals))
+        {
+          session->supports_put_result_checksum = TRUE;
+        }
     }
 
   /* SVN-specific headers -- if present, server supports HTTP protocol v2 */
@@ -361,6 +365,7 @@ options_response_handler(serf_request_t
     {
       svn_ra_serf__session_t *session = opt_ctx->session;
       serf_bucket_t *hdrs = serf_bucket_response_get_headers(response);
+      serf_connection_t *conn;
 
       /* Start out assuming all capabilities are unsupported. */
       svn_hash_sets(session->capabilities, SVN_RA_CAPABILITY_PARTIAL_REPLAY,
@@ -390,6 +395,10 @@ options_response_handler(serf_request_t
         svn_hash_sets(session->capabilities, SVN_RA_CAPABILITY_MERGEINFO,
                       capability_no);
 
+      /* Remember our latency. */
+      conn = serf_request_get_conn(request);
+      session->conn_latency = serf_connection_get_latency(conn);
+
       opt_ctx->headers_processed = TRUE;
     }
 

Modified: subversion/branches/addremove/subversion/libsvn_ra_serf/ra_serf.h
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/libsvn_ra_serf/ra_serf.h?rev=1805769&r1=1805768&r2=1805769&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/libsvn_ra_serf/ra_serf.h (original)
+++ subversion/branches/addremove/subversion/libsvn_ra_serf/ra_serf.h Tue Aug 
22 14:19:36 2017
@@ -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;
@@ -264,6 +268,12 @@ struct svn_ra_serf__session_t {
 
   /* 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)
@@ -1572,10 +1582,13 @@ svn_ra_serf__uri_parse(apr_uri_t *uri,
                        apr_pool_t *result_pool);
 
 /* Setup the "Accept-Encoding" header value for requests that expect
-   svndiff-encoded deltas, depending on the USING_COMPRESSION value. */
+   svndiff-encoded deltas, depending on the SESSION state. */
 void
 svn_ra_serf__setup_svndiff_accept_encoding(serf_bucket_t *headers,
-                                           svn_boolean_t using_compression);
+                                           svn_ra_serf__session_t *session);
+
+svn_boolean_t
+svn_ra_serf__is_low_latency_connection(svn_ra_serf__session_t *session);
 
 /* Default limit for in-memory size of a request body. */
 #define SVN_RA_SERF__REQUEST_BODY_IN_MEM_SIZE 256 * 1024
@@ -1609,6 +1622,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/addremove/subversion/libsvn_ra_serf/replay.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/libsvn_ra_serf/replay.c?rev=1805769&r1=1805768&r2=1805769&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/libsvn_ra_serf/replay.c (original)
+++ subversion/branches/addremove/subversion/libsvn_ra_serf/replay.c Tue Aug 22 
14:19:36 2017
@@ -166,7 +166,7 @@ typedef struct revision_report_t {
   svn_ra_serf__handler_t *propfind_handler;
   svn_ra_serf__handler_t *report_handler; /* For done handler */
 
-  svn_boolean_t using_compression;
+  svn_ra_serf__session_t *session;
 
 } revision_report_t;
 
@@ -641,8 +641,7 @@ setup_headers(serf_bucket_t *headers,
 {
   struct revision_report_t *ctx = baton;
 
-  svn_ra_serf__setup_svndiff_accept_encoding(headers,
-                                             ctx->using_compression);
+  svn_ra_serf__setup_svndiff_accept_encoding(headers, ctx->session);
 
   return SVN_NO_ERROR;
 }
@@ -741,7 +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->using_compression = session->using_compression;
+          rev_ctx->session = session;
 
           /* Request all properties of a certain revision. */
           rev_ctx->rev_props = apr_hash_make(rev_ctx->pool);

Modified: subversion/branches/addremove/subversion/libsvn_ra_serf/serf.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/libsvn_ra_serf/serf.c?rev=1805769&r1=1805768&r2=1805769&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/libsvn_ra_serf/serf.c (original)
+++ subversion/branches/addremove/subversion/libsvn_ra_serf/serf.c Tue Aug 22 
14:19:36 2017
@@ -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);
 
@@ -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);
 

Modified: subversion/branches/addremove/subversion/libsvn_ra_serf/update.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/libsvn_ra_serf/update.c?rev=1805769&r1=1805768&r2=1805769&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/libsvn_ra_serf/update.c (original)
+++ subversion/branches/addremove/subversion/libsvn_ra_serf/update.c Tue Aug 22 
14:19:36 2017
@@ -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;
@@ -797,10 +797,9 @@ headers_fetch(serf_bucket_t *headers,
     {
       serf_bucket_headers_setn(headers, SVN_DAV_DELTA_BASE_HEADER,
                                fetch_ctx->delta_base);
-      svn_ra_serf__setup_svndiff_accept_encoding(headers,
-                                                 fetch_ctx->using_compression);
+      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");
     }
@@ -1278,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))
@@ -2169,8 +2168,7 @@ setup_update_report_headers(serf_bucket_
 {
   report_context_t *report = baton;
 
-  svn_ra_serf__setup_svndiff_accept_encoding(headers,
-                                             report->sess->using_compression);
+  svn_ra_serf__setup_svndiff_accept_encoding(headers, report->sess);
 
   return SVN_NO_ERROR;
 }

Modified: subversion/branches/addremove/subversion/libsvn_ra_serf/util.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/libsvn_ra_serf/util.c?rev=1805769&r1=1805768&r2=1805769&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/libsvn_ra_serf/util.c (original)
+++ subversion/branches/addremove/subversion/libsvn_ra_serf/util.c Tue Aug 22 
14:19:36 2017
@@ -1571,7 +1571,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";
@@ -2026,20 +2026,42 @@ svn_ra_serf__uri_parse(apr_uri_t *uri,
 
 void
 svn_ra_serf__setup_svndiff_accept_encoding(serf_bucket_t *headers,
-                                           svn_boolean_t using_compression)
+                                           svn_ra_serf__session_t *session)
 {
-  if (using_compression)
+  if (session->using_compression == svn_tristate_false)
     {
-      /* We are equally interested in svndiff2 and svndiff1, let the
-         server choose the wire format. */
+      /* 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.9,svndiff;q=0.8");
+        "gzip,svndiff2;q=0.9,svndiff1;q=0.8,svndiff;q=0.7");
     }
   else
     {
-      /* Do not advertise svndiff1 support if we're not interested in
-         compression. */
-      serf_bucket_headers_setn(headers, "Accept-Encoding", "svndiff");
+      /* 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);
+}

Modified: subversion/branches/addremove/subversion/libsvn_ra_svn/client.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/libsvn_ra_svn/client.c?rev=1805769&r1=1805768&r2=1805769&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/libsvn_ra_svn/client.c (original)
+++ subversion/branches/addremove/subversion/libsvn_ra_svn/client.c Tue Aug 22 
14:19:36 2017
@@ -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;
@@ -746,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,
@@ -810,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,
@@ -843,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;
 

Modified: subversion/branches/addremove/subversion/libsvn_ra_svn/editorp.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/libsvn_ra_svn/editorp.c?rev=1805769&r1=1805768&r2=1805769&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/libsvn_ra_svn/editorp.c (original)
+++ subversion/branches/addremove/subversion/libsvn_ra_svn/editorp.c Tue Aug 22 
14:19:36 2017
@@ -353,6 +353,8 @@ static svn_error_t *ra_svn_apply_textdel
 
   /* If the connection does not support SVNDIFF1 or if we don't want to use
    * compression, use the non-compressing "version 0" implementation */
+ /* ### TODO: Check SVN_RA_SVN_CAP_SVNDIFF2_ACCEPTED and decide between
+  * ###       svndiff1[at compression_level] and svndiff2 */
   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,

Modified: subversion/branches/addremove/subversion/libsvn_ra_svn/protocol
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/libsvn_ra_svn/protocol?rev=1805769&r1=1805768&r2=1805769&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/libsvn_ra_svn/protocol (original)
+++ subversion/branches/addremove/subversion/libsvn_ra_svn/protocol Tue Aug 22 
14:19:36 2017
@@ -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.

Modified: subversion/branches/addremove/subversion/libsvn_repos/repos.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/libsvn_repos/repos.c?rev=1805769&r1=1805768&r2=1805769&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/libsvn_repos/repos.c (original)
+++ subversion/branches/addremove/subversion/libsvn_repos/repos.c Tue Aug 22 
14:19:36 2017
@@ -882,7 +882,7 @@ create_conf(svn_repos_t *repos, apr_pool
 "[sasl]"                                                                     NL
 "### This option specifies whether you want to use the Cyrus SASL"           NL
 "### library for authentication. Default is false."                          NL
-"### This section will be ignored if svnserve is not built with Cyrus"       NL
+"### Enabling this option requires svnserve to have been built with Cyrus"   NL
 "### SASL support; to check, run 'svnserve --version' and look for a line"   NL
 "### reading 'Cyrus SASL authentication is available.'"                      NL
 "# use-sasl = true"                                                          NL

Modified: subversion/branches/addremove/subversion/libsvn_subr/checksum.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/libsvn_subr/checksum.c?rev=1805769&r1=1805768&r2=1805769&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/libsvn_subr/checksum.c (original)
+++ subversion/branches/addremove/subversion/libsvn_subr/checksum.c Tue Aug 22 
14:19:36 2017
@@ -570,6 +570,36 @@ svn_checksum_ctx_create(svn_checksum_kin
 }
 
 svn_error_t *
+svn_checksum_ctx_reset(svn_checksum_ctx_t *ctx)
+{
+  switch (ctx->kind)
+    {
+      case svn_checksum_md5:
+        memset(ctx->apr_ctx, 0, sizeof(apr_md5_ctx_t));
+        apr_md5_init(ctx->apr_ctx);
+        break;
+
+      case svn_checksum_sha1:
+        memset(ctx->apr_ctx, 0, sizeof(apr_sha1_ctx_t));
+        apr_sha1_init(ctx->apr_ctx);
+        break;
+
+      case svn_checksum_fnv1a_32:
+        svn_fnv1a_32__context_reset(ctx->apr_ctx);
+        break;
+
+      case svn_checksum_fnv1a_32x4:
+        svn_fnv1a_32x4__context_reset(ctx->apr_ctx);
+        break;
+
+      default:
+        SVN_ERR_MALFUNCTION();
+    }
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
 svn_checksum_update(svn_checksum_ctx_t *ctx,
                     const void *data,
                     apr_size_t len)

Modified: subversion/branches/addremove/subversion/libsvn_subr/config_file.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/libsvn_subr/config_file.c?rev=1805769&r1=1805768&r2=1805769&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/libsvn_subr/config_file.c 
(original)
+++ subversion/branches/addremove/subversion/libsvn_subr/config_file.c Tue Aug 
22 14:19:36 2017
@@ -1148,6 +1148,7 @@ svn_config_ensure(const char *config_dir
         "###   http-timeout               Timeout for HTTP requests in seconds"
                                                                              NL
         "###   http-compression           Whether to compress HTTP requests" NL
+        "###                              (yes/no/auto)."                    NL
         "###   http-max-connections       Maximum number of parallel server" NL
         "###                              connections to use for any given"  NL
         "###                              HTTP operation."                   NL
@@ -1307,7 +1308,7 @@ svn_config_ensure(const char *config_dir
         "# http-proxy-port = 7000"                                           NL
         "# http-proxy-username = defaultusername"                            NL
         "# http-proxy-password = defaultpassword"                            NL
-        "# http-compression = no"                                            NL
+        "# http-compression = auto"                                          NL
         "# No http-timeout, so just use the builtin default."                NL
         "# ssl-authority-files = /path/to/CAcert.pem;/path/to/CAcert2.pem"   NL
         "#"                                                                  NL
@@ -1447,12 +1448,12 @@ svn_config_ensure(const char *config_dir
         "### passed to the tunnel agent as <user>@<hostname>.)  If the"      NL
         "### built-in ssh scheme were not predefined, it could be defined"   NL
         "### as:"                                                            NL
-        "# ssh = $SVN_SSH ssh -q"                                            NL
+        "# ssh = $SVN_SSH ssh -q --"                                         NL
         "### If you wanted to define a new 'rsh' scheme, to be used with"    NL
         "### 'svn+rsh:' URLs, you could do so as follows:"                   NL
-        "# rsh = rsh"                                                        NL
+        "# rsh = rsh --"                                                     NL
         "### Or, if you wanted to specify a full path and arguments:"        NL
-        "# rsh = /path/to/rsh -l myusername"                                 NL
+        "# rsh = /path/to/rsh -l myusername --"                              NL
         "### On Windows, if you are specifying a full path to a command,"    NL
         "### use a forward slash (/) or a paired backslash (\\\\) as the"    NL
         "### path separator.  A single backslash will be treated as an"      NL

Modified: subversion/branches/addremove/subversion/libsvn_subr/dirent_uri.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/libsvn_subr/dirent_uri.c?rev=1805769&r1=1805768&r2=1805769&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/libsvn_subr/dirent_uri.c (original)
+++ subversion/branches/addremove/subversion/libsvn_subr/dirent_uri.c Tue Aug 
22 14:19:36 2017
@@ -1862,18 +1862,18 @@ svn_uri_is_canonical(const char *uri, ap
           ptr++;
         }
 
-      if (ptr == schema_data)
+      if (ptr == schema_data && (*ptr == '/' || *ptr == '\0'))
         return FALSE; /* Fail on "http://host:"; */
 
-      if (*ptr && *ptr != '/')
-        return FALSE; /* Not a port number */
-
       if (port == 80 && strncmp(uri, "http:", 5) == 0)
         return FALSE;
       else if (port == 443 && strncmp(uri, "https:", 6) == 0)
         return FALSE;
       else if (port == 3690 && strncmp(uri, "svn:", 4) == 0)
         return FALSE;
+
+      while (*ptr && *ptr != '/')
+        ++ptr; /* Allow "http://host:stuff"; */
     }
 
   schema_data = ptr;

Modified: subversion/branches/addremove/subversion/libsvn_subr/fnv1a.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/libsvn_subr/fnv1a.c?rev=1805769&r1=1805768&r2=1805769&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/libsvn_subr/fnv1a.c (original)
+++ subversion/branches/addremove/subversion/libsvn_subr/fnv1a.c Tue Aug 22 
14:19:36 2017
@@ -166,6 +166,12 @@ svn_fnv1a_32__context_create(apr_pool_t
 }
 
 void
+svn_fnv1a_32__context_reset(svn_fnv1a_32__context_t *context)
+{
+  context->hash = FNV1_BASE_32;
+}
+
+void
 svn_fnv1a_32__update(svn_fnv1a_32__context_t *context,
                      const void *data,
                      apr_size_t len)
@@ -203,6 +209,17 @@ svn_fnv1a_32x4__context_create(apr_pool_
 }
 
 void
+svn_fnv1a_32x4__context_reset(svn_fnv1a_32x4__context_t *context)
+{
+  context->hashes[0] = FNV1_BASE_32;
+  context->hashes[1] = FNV1_BASE_32;
+  context->hashes[2] = FNV1_BASE_32;
+  context->hashes[3] = FNV1_BASE_32;
+
+  context->buffered = 0;
+}
+
+void
 svn_fnv1a_32x4__update(svn_fnv1a_32x4__context_t *context,
                        const void *data,
                        apr_size_t len)

Modified: subversion/branches/addremove/subversion/libsvn_subr/fnv1a.h
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/libsvn_subr/fnv1a.h?rev=1805769&r1=1805768&r2=1805769&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/libsvn_subr/fnv1a.h (original)
+++ subversion/branches/addremove/subversion/libsvn_subr/fnv1a.h Tue Aug 22 
14:19:36 2017
@@ -41,6 +41,11 @@ typedef struct svn_fnv1a_32__context_t s
 svn_fnv1a_32__context_t *
 svn_fnv1a_32__context_create(apr_pool_t *pool);
 
+/* Reset the FNV-1a checksum CONTEXT to initial state.
+ */
+void
+svn_fnv1a_32__context_reset(svn_fnv1a_32__context_t *context);
+
 /* Feed LEN bytes from DATA into the FNV-1a checksum creation CONTEXT.
  */
 void
@@ -63,6 +68,11 @@ typedef struct svn_fnv1a_32x4__context_t
 svn_fnv1a_32x4__context_t *
 svn_fnv1a_32x4__context_create(apr_pool_t *pool);
 
+/* Reset the modified FNV-1a checksum CONTEXT to initial state.
+ */
+void
+svn_fnv1a_32x4__context_reset(svn_fnv1a_32x4__context_t *context);
+
 /* Feed LEN bytes from DATA into the modified FNV-1a checksum creation
  * CONTEXT.
  */

Modified: subversion/branches/addremove/subversion/libsvn_subr/lz4/lz4.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/libsvn_subr/lz4/lz4.c?rev=1805769&r1=1805768&r2=1805769&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/libsvn_subr/lz4/lz4.c (original)
+++ subversion/branches/addremove/subversion/libsvn_subr/lz4/lz4.c Tue Aug 22 
14:19:36 2017
@@ -1,3 +1,5 @@
+#include "svn_private_config.h"
+#if SVN_INTERNAL_LZ4
 /*
    LZ4 - Fast LZ compression algorithm
    Copyright (C) 2011-2016, Yann Collet.
@@ -89,7 +91,7 @@
 /*-************************************
 *  Dependency
 **************************************/
-#include "lz4.h"
+#include "lz4internal.h"
 /* see also "memory routines" below */
 
 
@@ -1463,3 +1465,4 @@ int LZ4_decompress_fast_withPrefix64k(co
 }
 
 #endif   /* LZ4_COMMONDEFS_ONLY */
+#endif /* SVN_INTERNAL_LZ4 */

Modified: subversion/branches/addremove/subversion/libsvn_subr/stream.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/libsvn_subr/stream.c?rev=1805769&r1=1805768&r2=1805769&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/libsvn_subr/stream.c (original)
+++ subversion/branches/addremove/subversion/libsvn_subr/stream.c Tue Aug 22 
14:19:36 2017
@@ -235,6 +235,12 @@ svn_stream_supports_mark(svn_stream_t *s
   return stream->mark_fn != NULL;
 }
 
+svn_boolean_t
+svn_stream_supports_reset(svn_stream_t *stream)
+{
+  return stream->seek_fn != NULL;
+}
+
 svn_error_t *
 svn_stream_mark(svn_stream_t *stream, svn_stream_mark_t **mark,
                 apr_pool_t *pool)
@@ -670,6 +676,7 @@ svn_stream_disown(svn_stream_t *stream,
 struct baton_apr {
   apr_file_t *file;
   apr_pool_t *pool;
+  svn_boolean_t truncate_on_seek;
 };
 
 /* svn_stream_mark_t for streams backed by APR files. */
@@ -790,7 +797,16 @@ seek_handler_apr(void *baton, const svn_
   struct baton_apr *btn = baton;
   apr_off_t offset = (mark != NULL) ? ((const struct mark_apr *)mark)->off : 0;
 
-  SVN_ERR(svn_io_file_seek(btn->file, APR_SET, &offset, btn->pool));
+  if (btn->truncate_on_seek)
+    {
+      /* The apr_file_trunc() function always does seek + trunc,
+       * and this is documented, so don't seek when truncating. */
+      SVN_ERR(svn_io_file_trunc(btn->file, offset, btn->pool));
+    }
+  else
+    {
+      SVN_ERR(svn_io_file_seek(btn->file, APR_SET, &offset, btn->pool));
+    }
 
   return SVN_NO_ERROR;
 }
@@ -1052,6 +1068,7 @@ static svn_stream_t *
 make_stream_from_apr_file(apr_file_t *file,
                           svn_boolean_t disown,
                           svn_boolean_t supports_seek,
+                          svn_boolean_t truncate_on_seek,
                           apr_pool_t *pool)
 {
   struct baton_apr *baton;
@@ -1063,6 +1080,7 @@ make_stream_from_apr_file(apr_file_t *fi
   baton = apr_palloc(pool, sizeof(*baton));
   baton->file = file;
   baton->pool = pool;
+  baton->truncate_on_seek = truncate_on_seek;
   stream = svn_stream_create(baton, pool);
   svn_stream_set_read2(stream, read_handler_apr, read_full_handler_apr);
   svn_stream_set_write(stream, write_handler_apr);
@@ -1085,11 +1103,20 @@ make_stream_from_apr_file(apr_file_t *fi
 }
 
 svn_stream_t *
+svn_stream__from_aprfile(apr_file_t *file,
+                         svn_boolean_t disown,
+                         svn_boolean_t truncate_on_seek,
+                         apr_pool_t *pool)
+{
+  return make_stream_from_apr_file(file, disown, TRUE, truncate_on_seek, pool);
+}
+
+svn_stream_t *
 svn_stream_from_aprfile2(apr_file_t *file,
                          svn_boolean_t disown,
                          apr_pool_t *pool)
 {
-  return make_stream_from_apr_file(file, disown, TRUE, pool);
+  return make_stream_from_apr_file(file, disown, TRUE, FALSE, pool);
 }
 
 apr_file_t *
@@ -1427,6 +1454,31 @@ close_handler_checksum(void *baton)
   return svn_error_trace(svn_stream_close(btn->proxy));
 }
 
+static svn_error_t *
+seek_handler_checksum(void *baton, const svn_stream_mark_t *mark)
+{
+  struct checksum_stream_baton *btn = baton;
+
+  /* Only reset support. */
+  if (mark)
+    {
+      return svn_error_create(SVN_ERR_STREAM_SEEK_NOT_SUPPORTED,
+                              NULL, NULL);
+    }
+  else
+    {
+      if (btn->read_ctx)
+        svn_checksum_ctx_reset(btn->read_ctx);
+
+      if (btn->write_ctx)
+        svn_checksum_ctx_reset(btn->write_ctx);
+
+      SVN_ERR(svn_stream_reset(btn->proxy));
+    }
+
+  return SVN_NO_ERROR;
+}
+
 
 svn_stream_t *
 svn_stream_checksummed2(svn_stream_t *stream,
@@ -1464,6 +1516,8 @@ svn_stream_checksummed2(svn_stream_t *st
   svn_stream_set_write(s, write_handler_checksum);
   svn_stream_set_data_available(s, data_available_handler_checksum);
   svn_stream_set_close(s, close_handler_checksum);
+  if (svn_stream_supports_reset(stream))
+    svn_stream_set_seek(s, seek_handler_checksum);
   return s;
 }
 
@@ -1842,7 +1896,7 @@ svn_stream_for_stdin2(svn_stream_t **in,
      it does not, or the behavior is implementation-specific.  Hence,
      we cannot safely advertise mark(), seek() and non-default skip()
      support. */
-  *in = make_stream_from_apr_file(stdin_file, TRUE, FALSE, pool);
+  *in = make_stream_from_apr_file(stdin_file, TRUE, FALSE, FALSE, pool);
 
   return SVN_NO_ERROR;
 }
@@ -1862,7 +1916,7 @@ svn_stream_for_stdout(svn_stream_t **out
      it does not, or the behavior is implementation-specific.  Hence,
      we cannot safely advertise mark(), seek() and non-default skip()
      support. */
-  *out = make_stream_from_apr_file(stdout_file, TRUE, FALSE, pool);
+  *out = make_stream_from_apr_file(stdout_file, TRUE, FALSE, FALSE, pool);
 
   return SVN_NO_ERROR;
 }
@@ -1882,7 +1936,7 @@ svn_stream_for_stderr(svn_stream_t **err
      it does not, or the behavior is implementation-specific.  Hence,
      we cannot safely advertise mark(), seek() and non-default skip()
      support. */
-  *err = make_stream_from_apr_file(stderr_file, TRUE, FALSE, pool);
+  *err = make_stream_from_apr_file(stderr_file, TRUE, FALSE, FALSE, pool);
 
   return SVN_NO_ERROR;
 }
@@ -2247,7 +2301,9 @@ svn_stream__create_for_install(svn_strea
                                    svn_io_file_del_none,
                                    result_pool, scratch_pool));
 #endif
-  *install_stream = svn_stream_from_aprfile2(file, FALSE, result_pool);
+  /* Set the temporary file to be truncated on seeks. */
+  *install_stream = svn_stream__from_aprfile(file, FALSE, TRUE,
+                                             result_pool);
 
   ib = apr_pcalloc(result_pool, sizeof(*ib));
   ib->baton_apr = *(struct baton_apr*)(*install_stream)->baton;

Modified: subversion/branches/addremove/subversion/libsvn_subr/utf8proc.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/libsvn_subr/utf8proc.c?rev=1805769&r1=1805768&r2=1805769&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/libsvn_subr/utf8proc.c (original)
+++ subversion/branches/addremove/subversion/libsvn_subr/utf8proc.c Tue Aug 22 
14:19:36 2017
@@ -29,12 +29,16 @@
 #include "private/svn_utf_private.h"
 #include "svn_private_config.h"
 
+#if SVN_INTERNAL_UTF8PROC
 #define UTF8PROC_INLINE
 /* Somehow utf8proc thinks it is nice to use strlen as an argument name,
    while this function is already defined via apr.h */
 #define strlen svn__strlen_var
 #include "utf8proc/utf8proc.c"
 #undef strlen
+#else
+#include <utf8proc.h>
+#endif
 
 
 

Modified: 
subversion/branches/addremove/subversion/libsvn_subr/utf8proc/utf8proc.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/libsvn_subr/utf8proc/utf8proc.c?rev=1805769&r1=1805768&r2=1805769&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/libsvn_subr/utf8proc/utf8proc.c 
(original)
+++ subversion/branches/addremove/subversion/libsvn_subr/utf8proc/utf8proc.c 
Tue Aug 22 14:19:36 2017
@@ -1,3 +1,5 @@
+#include "svn_private_config.h"
+#if SVN_INTERNAL_UTF8PROC
 /*
  *  Copyright (c) 2009 Public Software Group e. V., Berlin, Germany
  *
@@ -39,7 +41,7 @@
  */
 
 
-#include "utf8proc.h"
+#include "utf8proc_internal.h"
 #include "utf8proc_data.c"
 
 
@@ -609,3 +611,4 @@ uint8_t *utf8proc_NFKC(const uint8_t *st
   return retval;
 }
 
+#endif /* SVN_INTERNAL_UTF8PROC */

Modified: subversion/branches/addremove/subversion/libsvn_wc/adm_crawler.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/libsvn_wc/adm_crawler.c?rev=1805769&r1=1805768&r2=1805769&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/libsvn_wc/adm_crawler.c (original)
+++ subversion/branches/addremove/subversion/libsvn_wc/adm_crawler.c Tue Aug 22 
14:19:36 2017
@@ -906,6 +906,27 @@ close_handler_copy(void *baton)
   return svn_stream_close(btn->source);
 }
 
+/* Implements svn_stream_seek_fn_t */
+static svn_error_t *
+seek_handler_copy(void *baton, const svn_stream_mark_t *mark)
+{
+  struct copying_stream_baton *btn = baton;
+
+  /* Only reset support. */
+  if (mark)
+    {
+      return svn_error_create(SVN_ERR_STREAM_SEEK_NOT_SUPPORTED,
+                              NULL, NULL);
+    }
+  else
+    {
+      SVN_ERR(svn_stream_reset(btn->source));
+      SVN_ERR(svn_stream_reset(btn->target));
+    }
+
+  return SVN_NO_ERROR;
+}
+
 
 /* Return a stream - allocated in POOL - which reads its input
  * from SOURCE and, while returning that to the caller, at the
@@ -928,6 +949,11 @@ copying_stream(svn_stream_t *source,
                        read_handler_copy);
   svn_stream_set_close(stream, close_handler_copy);
 
+  if (svn_stream_supports_reset(source) && svn_stream_supports_reset(target))
+    {
+      svn_stream_set_seek(stream, seek_handler_copy);
+    }
+
   return stream;
 }
 
@@ -995,9 +1021,38 @@ read_and_checksum_pristine_text(svn_stre
   return SVN_NO_ERROR;
 }
 
+typedef struct open_txdelta_stream_baton_t
+{
+  svn_boolean_t need_reset;
+  svn_stream_t *base_stream;
+  svn_stream_t *local_stream;
+} open_txdelta_stream_baton_t;
+
+/* Implements svn_txdelta_stream_open_func_t */
+static svn_error_t *
+open_txdelta_stream(svn_txdelta_stream_t **txdelta_stream_p,
+                    void *baton,
+                    apr_pool_t *result_pool,
+                    apr_pool_t *scratch_pool)
+{
+  open_txdelta_stream_baton_t *b = baton;
+
+  if (b->need_reset)
+    {
+      /* Under rare circumstances, we can be restarted and would need to
+       * supply the delta stream again.  In this case, reset both streams. */
+      SVN_ERR(svn_stream_reset(b->base_stream));
+      SVN_ERR(svn_stream_reset(b->local_stream));
+    }
+
+  svn_txdelta2(txdelta_stream_p, b->base_stream, b->local_stream,
+               FALSE, result_pool);
+  b->need_reset = TRUE;
+  return SVN_NO_ERROR;
+}
 
 svn_error_t *
-svn_wc__internal_transmit_text_deltas(const char **tempfile,
+svn_wc__internal_transmit_text_deltas(svn_stream_t *tempstream,
                                       const svn_checksum_t 
**new_text_base_md5_checksum,
                                       const svn_checksum_t 
**new_text_base_sha1_checksum,
                                       svn_wc__db_t *db,
@@ -1008,8 +1063,6 @@ svn_wc__internal_transmit_text_deltas(co
                                       apr_pool_t *result_pool,
                                       apr_pool_t *scratch_pool)
 {
-  svn_txdelta_window_handler_t handler;
-  void *wh_baton;
   const svn_checksum_t *expected_md5_checksum;  /* recorded MD5 of BASE_S. */
   svn_checksum_t *verify_checksum;  /* calc'd MD5 of BASE_STREAM */
   svn_checksum_t *local_md5_checksum;  /* calc'd MD5 of LOCAL_STREAM */
@@ -1027,22 +1080,13 @@ svn_wc__internal_transmit_text_deltas(co
                                              scratch_pool, scratch_pool));
 
   /* If the caller wants a copy of the working file translated to
-   * repository-normal form, make the copy by tee-ing the stream and set
-   * *TEMPFILE to the path to it.  This is only needed for the 1.6 API,
-   * 1.7 doesn't set TEMPFILE.  Even when using the 1.6 API this file
-   * is not used by the functions that would have used it when using
-   * the 1.6 code.  It's possible that 3rd party users (if there are any)
-   * might expect this file to be a text-base. */
-  if (tempfile)
-    {
-      svn_stream_t *tempstream;
-
-      /* It can't be the same location as in 1.6 because the admin directory
-         no longer exists. */
-      SVN_ERR(svn_stream_open_unique(&tempstream, tempfile,
-                                     NULL, svn_io_file_del_none,
-                                     result_pool, scratch_pool));
-
+   * repository-normal form, make the copy by tee-ing the TEMPSTREAM.
+   * This is only needed for the 1.6 API.  Even when using the 1.6 API
+   * this temporary file is not used by the functions that would have used
+   * it when using the 1.6 code.  It's possible that 3rd party users (if
+   * there are any) might expect this file to be a text-base. */
+  if (tempstream)
+    {
       /* Wrap the translated stream with a new stream that writes the
          translated contents into the new text base file as we read from it.
          Note that the new text base file will be closed when the new stream
@@ -1088,30 +1132,33 @@ svn_wc__internal_transmit_text_deltas(co
       verify_checksum = NULL;
     }
 
-  /* Tell the editor that we're about to apply a textdelta to the
-     file baton; the editor returns to us a window consumer and baton.  */
+  /* Arrange the stream to calculate the resulting MD5. */
+  local_stream = svn_stream_checksummed2(local_stream, &local_md5_checksum,
+                                         NULL, svn_checksum_md5, TRUE,
+                                         scratch_pool);
+
+  /* Tell the editor to apply a textdelta stream to the file baton. */
   {
-    /* apply_textdelta() is working against a base with this checksum */
+    open_txdelta_stream_baton_t baton = { 0 };
+
+    /* apply_textdelta_stream() is working against a base with this checksum */
     const char *base_digest_hex = NULL;
 
     if (expected_md5_checksum)
       /* ### Why '..._display()'?  expected_md5_checksum should never be all-
        * zero, but if it is, we would want to pass NULL not an all-zero
-       * digest to apply_textdelta(), wouldn't we? */
+       * digest to apply_textdelta_stream(), wouldn't we? */
       base_digest_hex = svn_checksum_to_cstring_display(expected_md5_checksum,
                                                         scratch_pool);
 
-    SVN_ERR(editor->apply_textdelta(file_baton, base_digest_hex, scratch_pool,
-                                    &handler, &wh_baton));
+    baton.need_reset = FALSE;
+    baton.base_stream = svn_stream_disown(base_stream, scratch_pool);
+    baton.local_stream = svn_stream_disown(local_stream, scratch_pool);
+    err = editor->apply_textdelta_stream(editor, file_baton, base_digest_hex,
+                                         open_txdelta_stream, &baton,
+                                         scratch_pool);
   }
 
-  /* Run diff processing, throwing windows at the handler. */
-  err = svn_txdelta_run(base_stream, local_stream,
-                        handler, wh_baton,
-                        svn_checksum_md5, &local_md5_checksum,
-                        NULL, NULL,
-                        scratch_pool, scratch_pool);
-
   /* Close the two streams to force writing the digest */
   err2 = svn_stream_close(base_stream);
   if (err2)
@@ -1141,11 +1188,6 @@ svn_wc__internal_transmit_text_deltas(co
          investigate.  Other commands could be affected,
          too, such as `svn diff'.  */
 
-      if (tempfile)
-        err = svn_error_compose_create(
-                      err,
-                      svn_io_remove_file2(*tempfile, TRUE, scratch_pool));
-
       err = svn_error_compose_create(
               svn_checksum_mismatch_err(expected_md5_checksum, verify_checksum,
                             scratch_pool,

Modified: subversion/branches/addremove/subversion/libsvn_wc/deprecated.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/libsvn_wc/deprecated.c?rev=1805769&r1=1805768&r2=1805769&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/libsvn_wc/deprecated.c (original)
+++ subversion/branches/addremove/subversion/libsvn_wc/deprecated.c Tue Aug 22 
14:19:36 2017
@@ -39,6 +39,7 @@
 
 #include "private/svn_subr_private.h"
 #include "private/svn_wc_private.h"
+#include "private/svn_io_private.h"
 
 #include "wc.h"
 #include "entries.h"
@@ -478,20 +479,49 @@ svn_wc_transmit_text_deltas2(const char
   const char *local_abspath;
   svn_wc_context_t *wc_ctx;
   const svn_checksum_t *new_text_base_md5_checksum;
+  svn_stream_t *tempstream;
+  svn_error_t *err;
 
   SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, pool));
   SVN_ERR(svn_wc__context_create_with_db(&wc_ctx, NULL /* config */,
                                          svn_wc__adm_get_db(adm_access),
                                          pool));
+  if (tempfile)
+    {
+      apr_file_t *f;
+
+      /* The temporary file can't be the same location as in 1.6 because the
+       * admin directory no longer exists. */
+      SVN_ERR(svn_io_open_unique_file3(&f, tempfile, NULL,
+                                       svn_io_file_del_none,
+                                       pool, pool));
+      tempstream = svn_stream__from_aprfile(f, FALSE, TRUE, pool);
+    }
+  else
+    {
+      tempstream = NULL;
+    }
+
+  err = svn_wc__internal_transmit_text_deltas(svn_stream_disown(tempstream, 
pool),
+                                              (digest
+                                               ? &new_text_base_md5_checksum
+                                               : NULL),
+                                              NULL, wc_ctx->db,
+                                              local_abspath, fulltext,
+                                              editor, file_baton,
+                                              pool, pool);
+  if (tempfile)
+    {
+      err = svn_error_compose_create(err, svn_stream_close(tempstream));
+
+      if (err)
+        {
+          err = svn_error_compose_create(
+                  err, svn_io_remove_file2(*tempfile, TRUE, pool));
+        }
+    }
 
-  SVN_ERR(svn_wc__internal_transmit_text_deltas(tempfile,
-                                                (digest
-                                                 ? &new_text_base_md5_checksum
-                                                 : NULL),
-                                                NULL, wc_ctx->db,
-                                                local_abspath, fulltext,
-                                                editor, file_baton,
-                                                pool, pool));
+  SVN_ERR(err);
 
   if (digest)
     memcpy(digest, new_text_base_md5_checksum->digest, APR_MD5_DIGESTSIZE);

Modified: subversion/branches/addremove/subversion/libsvn_wc/translate.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/libsvn_wc/translate.c?rev=1805769&r1=1805768&r2=1805769&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/libsvn_wc/translate.c (original)
+++ subversion/branches/addremove/subversion/libsvn_wc/translate.c Tue Aug 22 
14:19:36 2017
@@ -440,3 +440,20 @@ svn_wc__sync_flags_with_props(svn_boolea
 
   return SVN_NO_ERROR;
 }
+
+svn_error_t *
+svn_wc__translated_stream(svn_stream_t **stream,
+                          svn_wc_context_t *wc_ctx,
+                          const char *local_abspath,
+                          const char *versioned_abspath,
+                          apr_uint32_t flags,
+                          apr_pool_t *result_pool,
+                          apr_pool_t *scratch_pool)
+{
+  return svn_error_trace(
+           svn_wc__internal_translated_stream(stream, wc_ctx->db,
+                                              local_abspath,
+                                              versioned_abspath,
+                                              flags, result_pool,
+                                              scratch_pool));
+}

Modified: subversion/branches/addremove/subversion/libsvn_wc/wc.h
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/libsvn_wc/wc.h?rev=1805769&r1=1805768&r2=1805769&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/libsvn_wc/wc.h (original)
+++ subversion/branches/addremove/subversion/libsvn_wc/wc.h Tue Aug 22 14:19:36 
2017
@@ -480,7 +480,7 @@ svn_wc__conflicted_for_update_p(svn_bool
 
 /* Internal version of svn_wc_transmit_text_deltas3(). */
 svn_error_t *
-svn_wc__internal_transmit_text_deltas(const char **tempfile,
+svn_wc__internal_transmit_text_deltas(svn_stream_t *tempstream,
                                       const svn_checksum_t 
**new_text_base_md5_checksum,
                                       const svn_checksum_t 
**new_text_base_sha1_checksum,
                                       svn_wc__db_t *db,

Modified: subversion/branches/addremove/subversion/mod_dav_svn/repos.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/mod_dav_svn/repos.c?rev=1805769&r1=1805768&r2=1805769&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/mod_dav_svn/repos.c (original)
+++ subversion/branches/addremove/subversion/mod_dav_svn/repos.c Tue Aug 22 
14:19:36 2017
@@ -1739,6 +1739,18 @@ static int sort_encoding_pref(const void
   return (diff == 0 ? 0 : (diff > 0 ? -1 : 1));
 }
 
+static int get_svndiff_version(const struct accept_rec *rec)
+{
+  if (strcmp(rec->name, "svndiff2") == 0)
+    return 2;
+  else if (strcmp(rec->name, "svndiff1") == 0)
+    return 1;
+  else if (strcmp(rec->name, "svndiff") == 0)
+    return 0;
+  else
+    return -1;
+}
+
 /* Parse and handle any possible Accept-Encoding header that has been
    sent as part of the request.  */
 static void
@@ -1752,7 +1764,7 @@ negotiate_encoding_prefs(request_rec *r,
      necessary ones in this file. */
   int i;
   apr_array_header_t *encoding_prefs;
-  svn_boolean_t accepts_svndiff1 = FALSE;
+  apr_array_header_t *svndiff_encodings;
   svn_boolean_t accepts_svndiff2 = FALSE;
 
   encoding_prefs = do_header_line(r->pool,
@@ -1765,33 +1777,43 @@ negotiate_encoding_prefs(request_rec *r,
       return;
     }
 
-  svn_sort__array(encoding_prefs, sort_encoding_pref);
+  svndiff_encodings = apr_array_make(r->pool, 3, sizeof(struct accept_rec));
   for (i = 0; i < encoding_prefs->nelts; i++)
     {
-      struct accept_rec rec = APR_ARRAY_IDX(encoding_prefs, i,
-                                            struct accept_rec);
-      if (strcmp(rec.name, "svndiff2") == 0)
-        {
-          accepts_svndiff2 = TRUE;
-        }
-      else if (strcmp(rec.name, "svndiff1") == 0)
-        {
-          accepts_svndiff1 = TRUE;
-        }
+      const struct accept_rec *rec = &APR_ARRAY_IDX(encoding_prefs, i,
+                                                    struct accept_rec);
+      int version = get_svndiff_version(rec);
+
+      if (version > 0)
+        APR_ARRAY_PUSH(svndiff_encodings, struct accept_rec) = *rec;
+
+      if (version == 2)
+        accepts_svndiff2 = TRUE;
     }
 
-  /* Enable svndiff2 if the client can read it, and if the server-side
-   * compression level is set to 1.  Svndiff2 offers better speed and
-   * compression ratio comparable to svndiff1 with compression level 1,
-   * but with for other compression levels.
-   */
-  if (accepts_svndiff2 && dav_svn__get_compression_level(r) == 1)
+  if (dav_svn__get_compression_level(r) == 0)
+    {
+      /* If the compression is disabled on the server, use the uncompressed
+       * svndiff0 format, which we assume is always supported. */
+      *svndiff_version = 0;
+    }
+  else if (accepts_svndiff2 && dav_svn__get_compression_level(r) == 1)
     {
+      /* Enable svndiff2 if the client can read it, and if the server-side
+       * compression level is set to 1.  Svndiff2 offers better speed and
+       * compression ratio comparable to svndiff1 with compression level 1,
+       * but not with other compression levels.
+       */
       *svndiff_version = 2;
     }
-  else if (accepts_svndiff1)
+  else if (svndiff_encodings->nelts > 0)
     {
-      *svndiff_version = 1;
+      const struct accept_rec *rec;
+
+      /* Otherwise, use what the client prefers to see. */
+      svn_sort__array(svndiff_encodings, sort_encoding_pref);
+      rec = &APR_ARRAY_IDX(svndiff_encodings, 0, struct accept_rec);
+      *svndiff_version = get_svndiff_version(rec);
     }
   else
     {
@@ -2987,6 +3009,26 @@ close_stream(dav_stream *stream, int com
            pool);
     }
 
+  if (stream->wstream != NULL || stream->delta_handler != NULL)
+    {
+      request_rec *r = stream->res->info->r;
+      svn_checksum_t *checksum;
+
+      serr = svn_fs_file_checksum(&checksum, svn_checksum_md5,
+                                  stream->res->info->root.root,
+                                  stream->res->info->repos_path,
+                                  FALSE, pool);
+      if (serr)
+        return dav_svn__convert_err
+          (serr, HTTP_INTERNAL_SERVER_ERROR,
+            "mod_dav_svn close_stream: error getting file checksum",
+            pool);
+
+      if (checksum)
+        apr_table_set(r->headers_out, SVN_DAV_RESULT_FULLTEXT_MD5_HEADER,
+                      svn_checksum_to_cstring(checksum, pool));
+    }
+
   return NULL;
 }
 

Modified: subversion/branches/addremove/subversion/mod_dav_svn/version.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/mod_dav_svn/version.c?rev=1805769&r1=1805768&r2=1805769&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/mod_dav_svn/version.c (original)
+++ subversion/branches/addremove/subversion/mod_dav_svn/version.c Tue Aug 22 
14:19:36 2017
@@ -154,6 +154,7 @@ get_vsn_options(apr_pool_t *p, apr_text_
   apr_text_append(p, phdr, SVN_DAV_NS_DAV_SVN_REVERSE_FILE_REVS);
   apr_text_append(p, phdr, SVN_DAV_NS_DAV_SVN_SVNDIFF1);
   apr_text_append(p, phdr, SVN_DAV_NS_DAV_SVN_SVNDIFF2);
+  apr_text_append(p, phdr, SVN_DAV_NS_DAV_SVN_PUT_RESULT_CHECKSUM);
   /* Mergeinfo is a special case: here we merely say that the server
    * knows how to handle mergeinfo -- whether the repository does too
    * is a separate matter.

Modified: subversion/branches/addremove/subversion/svn/cl.h
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/svn/cl.h?rev=1805769&r1=1805768&r2=1805769&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/svn/cl.h (original)
+++ subversion/branches/addremove/subversion/svn/cl.h Tue Aug 22 14:19:36 2017
@@ -83,7 +83,10 @@ typedef enum svn_cl__accept_t
   svn_cl__accept_edit,
 
   /* Launch user's resolver and resolve conflict with edited file. */
-  svn_cl__accept_launch
+  svn_cl__accept_launch,
+
+  /* Use recommended resolution if available, else leave the conflict alone. */
+  svn_cl__accept_recommended
 
 } svn_cl__accept_t;
 
@@ -97,6 +100,7 @@ typedef enum svn_cl__accept_t
 #define SVN_CL__ACCEPT_THEIRS_FULL "theirs-full"
 #define SVN_CL__ACCEPT_EDIT "edit"
 #define SVN_CL__ACCEPT_LAUNCH "launch"
+#define SVN_CL__ACCEPT_RECOMMENDED "recommended"
 
 /* Return the svn_cl__accept_t value corresponding to WORD, using exact
  * case-sensitive string comparison. Return svn_cl__accept_invalid if WORD
@@ -250,6 +254,7 @@ typedef struct svn_cl__opt_state_t
   svn_boolean_t pin_externals;     /* pin externals to last-changed revisions 
*/
   const char *show_item;           /* print only the given item */
   svn_boolean_t adds_as_modification; /* update 'add vs add' no tree conflict 
*/
+  svn_boolean_t vacuum_pristines; /* remove unreferenced pristines */
 } svn_cl__opt_state_t;
 
 /* Conflict stats for operations such as update and merge. */

Modified: subversion/branches/addremove/subversion/svn/cleanup-cmd.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/svn/cleanup-cmd.c?rev=1805769&r1=1805768&r2=1805769&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/svn/cleanup-cmd.c (original)
+++ subversion/branches/addremove/subversion/svn/cleanup-cmd.c Tue Aug 22 
14:19:36 2017
@@ -72,13 +72,14 @@ svn_cl__cleanup(apr_getopt_t *os,
 
       SVN_ERR(svn_dirent_get_absolute(&target_abspath, target, iterpool));
 
-      if (opt_state->remove_unversioned || opt_state->remove_ignored)
+      if (opt_state->remove_unversioned || opt_state->remove_ignored ||
+          opt_state->vacuum_pristines)
         {
           svn_error_t *err = svn_client_vacuum(target_abspath,
                                                opt_state->remove_unversioned,
                                                opt_state->remove_ignored,
                                                TRUE /* fix_timestamps */,
-                                               FALSE /* vacuum_pristines */,
+                                               opt_state->vacuum_pristines,
                                                opt_state->include_externals,
                                                ctx, iterpool);
 

Modified: subversion/branches/addremove/subversion/svn/conflict-callbacks.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/svn/conflict-callbacks.c?rev=1805769&r1=1805768&r2=1805769&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/svn/conflict-callbacks.c (original)
+++ subversion/branches/addremove/subversion/svn/conflict-callbacks.c Tue Aug 
22 14:19:36 2017
@@ -78,6 +78,9 @@ svn_cl__accept_from_word(const char *wor
   if (strcmp(word, SVN_CL__ACCEPT_LAUNCH) == 0
       || strcmp(word, "l") == 0 || strcmp(word, ":-l") == 0)
     return svn_cl__accept_launch;
+  if (strcmp(word, SVN_CL__ACCEPT_RECOMMENDED) == 0
+      || strcmp(word, "r"))
+    return svn_cl__accept_recommended;
   /* word is an invalid action. */
   return svn_cl__accept_invalid;
 }
@@ -2174,6 +2177,19 @@ svn_cl__resolve_conflict(svn_boolean_t *
             }
         }
     }
+  else if (accept_which == svn_cl__accept_recommended)
+    {
+      svn_client_conflict_option_id_t recommended_id;
+
+      if (tree_conflicted)
+        SVN_ERR(svn_client_conflict_tree_get_details(conflict, ctx,
+                                                     scratch_pool));
+      recommended_id = svn_client_conflict_get_recommended_option_id(conflict);
+      if (recommended_id != svn_client_conflict_option_unspecified)
+        option_id = recommended_id;
+      else
+        option_id = svn_client_conflict_option_postpone;
+    }
   else
     SVN_ERR_MALFUNCTION();
 

Modified: subversion/branches/addremove/subversion/svn/merge-cmd.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/svn/merge-cmd.c?rev=1805769&r1=1805768&r2=1805769&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/svn/merge-cmd.c (original)
+++ subversion/branches/addremove/subversion/svn/merge-cmd.c Tue Aug 22 
14:19:36 2017
@@ -182,6 +182,7 @@ conflict_func_merge_cmd(svn_wc_conflict_
     case svn_cl__accept_postpone:
     case svn_cl__accept_invalid:
     case svn_cl__accept_unspecified:
+    case svn_cl__accept_recommended:
       /* Postpone or no valid --accept option, postpone the conflict. */
       choice = svn_wc_conflict_choose_postpone;
       break;

Modified: subversion/branches/addremove/subversion/svn/notify.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/svn/notify.c?rev=1805769&r1=1805768&r2=1805769&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/svn/notify.c (original)
+++ subversion/branches/addremove/subversion/svn/notify.c Tue Aug 22 14:19:36 
2017
@@ -54,6 +54,7 @@ struct notify_baton
   svn_boolean_t is_wc_to_repos_copy;
   svn_boolean_t sent_first_txdelta;
   int in_external;
+  svn_revnum_t progress_revision;
   svn_boolean_t had_print_error; /* Used to not keep printing error messages
                                     when we've already had one print error. */
 
@@ -477,14 +478,27 @@ notify_body(struct notify_baton *nb,
                                  _("Searching tree conflict details for '%s' "
                                    "in repository:\n"),
                                  path_local));
+      nb->progress_revision = 0;
       break;
 
     case svn_wc_notify_tree_conflict_details_progress:
-      SVN_ERR(svn_cmdline_printf(pool, _("\rChecking r%ld..."), n->revision));
+      /* First printf is to obliterate any previous progress printf,
+         assuming no more than 10 digit revisions.  Avoid i18n so the
+         text length is known.  We only need to do this if the new
+         revision is 4 digits less than the previous revision but that
+         requires counting digits.  Dividing by 1000 works well
+         enough: it triggers when needed, it sometimes triggers when
+         not needed, but in typical cases it doesn't trigger as the
+         revisions don't vary much. */
+      if (n->revision < nb->progress_revision / 1000)
+        SVN_ERR(svn_cmdline_printf(pool, "\rChecking r             "));
+      SVN_ERR(svn_cmdline_printf(pool, "\rChecking r%ld...", n->revision));
+      nb->progress_revision = n->revision;
       break;
 
     case svn_wc_notify_end_search_tree_conflict_details:
       SVN_ERR(svn_cmdline_printf(pool, _(" done\n")));
+      nb->progress_revision = 0;
       break;
 
     case svn_wc_notify_add:
@@ -1235,6 +1249,7 @@ svn_cl__get_notifier(svn_wc_notify_func2
   nb->is_export = FALSE;
   nb->is_wc_to_repos_copy = FALSE;
   nb->in_external = 0;
+  nb->progress_revision = 0;
   nb->had_print_error = FALSE;
   nb->conflict_stats = conflict_stats;
   SVN_ERR(svn_dirent_get_absolute(&nb->path_prefix, "", pool));

Modified: subversion/branches/addremove/subversion/svn/svn.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/svn/svn.c?rev=1805769&r1=1805768&r2=1805769&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/svn/svn.c (original)
+++ subversion/branches/addremove/subversion/svn/svn.c Tue Aug 22 14:19:36 2017
@@ -143,7 +143,8 @@ typedef enum svn_cl__longopt_t {
   opt_show_passwords,
   opt_pin_externals,
   opt_show_item,
-  opt_adds_as_modification
+  opt_adds_as_modification,
+  opt_vacuum_pristines,
 } svn_cl__longopt_t;
 
 
@@ -328,9 +329,9 @@ const apr_getopt_option_t svn_cl__option
                        "                             "
                        "'theirs-conflict', 'mine-full', 'theirs-full',\n"
                        "                             "
-                       "'edit', 'launch')\n"
+                       "'edit', 'launch', 'recommended') (shorthand:\n"
                        "                             "
-                       "(shorthand: 'p', 'mc', 'tc', 'mf', 'tf', 'e', 'l')"
+                       "'p', 'mc', 'tc', 'mf', 'tf', 'e', 'l', 'r')"
                        )},
   {"show-revs",     opt_show_revs, 1,
                     N_("specify which collection of revisions to display\n"
@@ -459,6 +460,9 @@ const apr_getopt_option_t svn_cl__option
                        "                             "
                        "resolve tree conflicts instead.")},
 
+  {"vacuum-pristines", opt_vacuum_pristines, 0,
+                       N_("remove unreferenced pristines from .svn 
directory")},
+
   /* Long-opt Aliases
    *
    * These have NULL desriptions, but an option code that matches some
@@ -620,30 +624,36 @@ const svn_opt_subcommand_desc2_t svn_cl_
     {'r', 'q', 'N', opt_depth, opt_force, opt_ignore_externals} },
 
   { "cleanup", svn_cl__cleanup, {0}, N_
-    ("Recursively clean up the working copy, removing write locks, resuming\n"
-     "unfinished operations, etc.\n"
-     "usage: cleanup [WCPATH...]\n"
-     "\n"
-     "  By default, finish any unfinished business in the working copy at 
WCPATH,\n"
-     "  and remove write locks (shown as 'L' by the 'svn status' command) 
from\n"
-     "  the working copy. Usually, this is only necessary if a Subversion 
client\n"
-     "  has crashed while using the working copy, leaving it in an unusable 
state.\n"
-     "\n"
-     "  WARNING: There is no mechanism that will protect write locks still\n"
-     "           being used by other Subversion clients. Running this 
command\n"
-     "           while another client is using the working copy can corrupt\n"
-     "           the working copy beyond repair!\n"
-     "\n"
-     "  If the --remove-unversioned option or the --remove-ignored option\n"
-     "  is given, remove any unversioned or ignored items within WCPATH.\n"
-     "  To prevent accidental working copy corruption, unversioned or 
ignored\n"
-     "  items can only be removed if the working copy is not already locked\n"
-     "  for writing by another Subversion client.\n"
-     "  Note that the 'svn status' command shows unversioned items as '?',\n"
-     "  and ignored items as 'I' if the --no-ignore option is given to it.\n"),
-    {opt_merge_cmd, opt_remove_unversioned, opt_remove_ignored,
-     opt_include_externals, 'q'} },
-
+    ("Either recover from an interrupted operation that left the working copy 
locked,\n"
+     "or remove unwanted files.\n"
+     "usage: 1. cleanup [WCPATH...]\n"
+     "       2. cleanup --remove-unversioned [WCPATH...]\n"
+     "          cleanup --remove-ignored [WCPATH...]\n"
+     "       3. cleanup --vacuum-pristines [WCPATH...]\n"
+     "\n"
+     "  1. When none of the options --remove-unversioned, --remove-ignored, 
and\n"
+     "    --vacuum-pristines is specified, remove all write locks (shown as 
'L' by\n"
+     "    the 'svn status' command) from the working copy.  Usually, this is 
only\n"
+     "    necessary if a Subversion client has crashed while using the working 
copy,\n"
+     "    leaving it in an unusable state.\n"
+     "\n"
+     "    WARNING: There is no mechanism that will protect write locks still\n"
+     "             being used by other Subversion clients. Running this 
command\n"
+     "             without any options while another client is using the 
working\n"
+     "             copy can corrupt the working copy beyond repair!\n"
+     "\n"
+     "  2. If the --remove-unversioned option or the --remove-ignored option\n"
+     "    is given, remove any unversioned or ignored items within WCPATH.\n"
+     "    Note that the 'svn status' command shows unversioned items as '?',\n"
+     "    and ignored items as 'I' if the --no-ignore option is given to it.\n"
+     "\n"
+     "  3. If the --vacuum-pristines option is given, remove pristine copies 
of\n"
+     "    files which are stored inside the .svn directory and which are no 
longer\n"
+     "    referenced by any file in the working copy.\n"),
+    { opt_remove_unversioned, opt_remove_ignored, opt_vacuum_pristines,
+      opt_include_externals, 'q', opt_merge_cmd }, 
+    { { opt_merge_cmd, N_("deprecated and ignored") } } },
+      
   { "commit", svn_cl__commit, {"ci"},
     N_("Send changes from your working copy to the repository.\n"
        "usage: commit [PATH...]\n"
@@ -1331,11 +1341,10 @@ const svn_opt_subcommand_desc2_t svn_cl_
      "  Furthermore, WC -> WC moves will refuse to move a mixed-revision 
subtree.\n"
      "  To avoid unnecessary conflicts, it is recommended to run 'svn 
update'\n"
      "  to update the subtree to a single revision before moving it.\n"
-     "  The --allow-mixed-revisions option is provided for backward 
compatibility.\n"
-     "\n"
-     "  The --revision option has no use and is deprecated.\n"),
-    {'r', 'q', opt_force, opt_parents, opt_allow_mixed_revisions,
-     SVN_CL__LOG_MSG_OPTIONS} },
+     "  The --allow-mixed-revisions option is provided for backward 
compatibility.\n"),
+    {'q', opt_force, opt_parents, opt_allow_mixed_revisions,
+     SVN_CL__LOG_MSG_OPTIONS, 'r'},
+    {{'r', "deprecated and ignored"}} },
 
   { "patch", svn_cl__patch, {0}, N_
     ("Apply a patch to a working copy.\n"
@@ -1783,12 +1792,14 @@ const svn_opt_subcommand_desc2_t svn_cl_
      "    svn switch --relocate http:// svn://\n"
      "    svn switch --relocate http://www.example.com/repo/project \\\n"
      "                          svn://svn.example.com/repo/project\n"),
-    { 'r', 'N', opt_depth, opt_set_depth, 'q', opt_merge_cmd, opt_relocate,
-      opt_ignore_externals, opt_ignore_ancestry, opt_force, opt_accept},
+    { 'r', 'N', opt_depth, opt_set_depth, 'q', opt_merge_cmd,
+      opt_ignore_externals, opt_ignore_ancestry, opt_force, opt_accept,
+      opt_relocate },
     {{opt_ignore_ancestry,
      N_("allow switching to a node with no common ancestor")},
      {opt_force,
-      N_("handle unversioned obstructions as changes")}}
+      N_("handle unversioned obstructions as changes")},
+     {opt_relocate,N_("deprecated; use 'svn relocate'")}}
   },
 
   { "unlock", svn_cl__unlock, {0}, N_
@@ -2520,6 +2531,9 @@ sub_main(int *exit_code, int argc, const
       case opt_adds_as_modification:
         opt_state.adds_as_modification = TRUE;
         break;
+      case opt_vacuum_pristines:
+        opt_state.vacuum_pristines = TRUE;
+        break;
       default:
         /* Hmmm. Perhaps this would be a good place to squirrel away
            opts that commands like svn diff might need. Hmmm indeed. */
@@ -3069,10 +3083,11 @@ sub_main(int *exit_code, int argc, const
                                    SVN_CL__ACCEPT_LAUNCH);
         }
 
-      /* The default action when we're non-interactive is to postpone
-       * conflict resolution. */
+      /* The default action when we're non-interactive is to use the
+       * recommended conflict resolution (this will postpone conflicts
+       * for which no recommended resolution is available). */
       if (opt_state.accept_which == svn_cl__accept_unspecified)
-        opt_state.accept_which = svn_cl__accept_postpone;
+        opt_state.accept_which = svn_cl__accept_recommended;
     }
 
   /* Check whether interactive conflict resolution is disabled by


Reply via email to