You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by st...@apache.org on 2016/04/29 20:38:56 UTC

svn commit: r1741682 [21/26] - in /subversion/branches/authzperf: ./ build/ build/ac-macros/ build/generator/ contrib/server-side/svncutter/ notes/ notes/api-errata/1.9/ notes/move-tracking/ subversion/ subversion/bindings/ctypes-python/ subversion/bin...

Modified: subversion/branches/authzperf/subversion/svnserve/cyrus_auth.c
URL: http://svn.apache.org/viewvc/subversion/branches/authzperf/subversion/svnserve/cyrus_auth.c?rev=1741682&r1=1741681&r2=1741682&view=diff
==============================================================================
--- subversion/branches/authzperf/subversion/svnserve/cyrus_auth.c (original)
+++ subversion/branches/authzperf/subversion/svnserve/cyrus_auth.c Fri Apr 29 18:38:53 2016
@@ -74,6 +74,8 @@ static int canonicalize_username(sasl_co
     {
       /* The only valid realm is user_realm (i.e. the repository's realm).
          If the user gave us another realm, complain. */
+      if (realm_len != inlen-(pos-in+1))
+        return SASL_BADPROT;
       if (strncmp(pos+1, user_realm, inlen-(pos-in+1)) != 0)
         return SASL_BADPROT;
     }
@@ -110,11 +112,12 @@ static svn_error_t *initialize(void *bat
 
   /* The second parameter tells SASL to look for a configuration file
      named subversion.conf. */
-  result = sasl_server_init(callbacks, SVN_RA_SVN_SASL_NAME);
+  result = svn_sasl__server_init(callbacks, SVN_RA_SVN_SASL_NAME);
   if (result != SASL_OK)
     {
-      svn_error_t *err = svn_error_create(SVN_ERR_RA_NOT_AUTHORIZED, NULL,
-                                          sasl_errstring(result, NULL, NULL));
+      svn_error_t *err = svn_error_create(
+          SVN_ERR_RA_NOT_AUTHORIZED, NULL,
+          svn_sasl__errstring(result, NULL, NULL));
       return svn_error_quick_wrap(err,
                                   _("Could not initialize the SASL library"));
     }
@@ -133,7 +136,7 @@ svn_error_t *cyrus_init(apr_pool_t *pool
 static svn_error_t *
 fail_auth(svn_ra_svn_conn_t *conn, apr_pool_t *pool, sasl_conn_t *sasl_ctx)
 {
-  const char *msg = sasl_errdetail(sasl_ctx);
+  const char *msg = svn_sasl__errdetail(sasl_ctx);
   SVN_ERR(svn_ra_svn__write_tuple(conn, pool, "w(c)", "failure", msg));
   return svn_ra_svn__flush(conn, pool);
 }
@@ -154,7 +157,7 @@ static svn_error_t *
 fail_cmd(svn_ra_svn_conn_t *conn, apr_pool_t *pool, sasl_conn_t *sasl_ctx)
 {
   svn_error_t *err = svn_error_create(SVN_ERR_RA_NOT_AUTHORIZED, NULL,
-                                      sasl_errdetail(sasl_ctx));
+                                      svn_sasl__errdetail(sasl_ctx));
   SVN_ERR(write_failure(conn, pool, &err));
   return svn_ra_svn__flush(conn, pool);
 }
@@ -190,9 +193,10 @@ static svn_error_t *try_auth(svn_ra_svn_
     return svn_error_createf(SVN_ERR_RA_NOT_AUTHORIZED, NULL,
                              _("Initial token is too long"));
 
-  result = sasl_server_start(sasl_ctx, mech,
-                             in ? in->data : NULL,
-                             in ? (unsigned int) in->len : 0, &out, &outlen);
+  result = svn_sasl__server_start(sasl_ctx, mech,
+                                  in ? in->data : NULL,
+                                  in ? (unsigned int) in->len : 0,
+                                  &out, &outlen);
 
   if (result != SASL_OK && result != SASL_CONTINUE)
     return fail_auth(conn, pool, sasl_ctx);
@@ -221,8 +225,9 @@ static svn_error_t *try_auth(svn_ra_svn_
         return svn_error_createf(SVN_ERR_RA_NOT_AUTHORIZED, NULL,
                                  _("Step response is too long"));
 
-      result = sasl_server_step(sasl_ctx, in->data, (unsigned int) in->len,
-                                &out, &outlen);
+      result = svn_sasl__server_step(sasl_ctx, in->data,
+                                     (unsigned int) in->len,
+                                     &out, &outlen);
     }
 
   if (result != SASL_OK)
@@ -244,7 +249,7 @@ static svn_error_t *try_auth(svn_ra_svn_
 static apr_status_t sasl_dispose_cb(void *data)
 {
   sasl_conn_t *sasl_ctx = (sasl_conn_t*) data;
-  sasl_dispose(&sasl_ctx);
+  svn_sasl__dispose(&sasl_ctx);
   return APR_SUCCESS;
 }
 
@@ -276,15 +281,16 @@ svn_error_t *cyrus_auth_request(svn_ra_s
 
   /* Create a SASL context. SASL_SUCCESS_DATA tells SASL that the protocol
      supports sending data along with the final "success" message. */
-  result = sasl_server_new(SVN_RA_SVN_SASL_NAME,
-                           hostname, b->repository->realm,
-                           localaddrport, remoteaddrport,
-                           NULL, SASL_SUCCESS_DATA,
-                           &sasl_ctx);
+  result = svn_sasl__server_new(SVN_RA_SVN_SASL_NAME,
+                                hostname, b->repository->realm,
+                                localaddrport, remoteaddrport,
+                                NULL, SASL_SUCCESS_DATA,
+                                &sasl_ctx);
   if (result != SASL_OK)
     {
-      svn_error_t *err = svn_error_create(SVN_ERR_RA_NOT_AUTHORIZED, NULL,
-                                          sasl_errstring(result, NULL, NULL));
+      svn_error_t *err = svn_error_create(
+          SVN_ERR_RA_NOT_AUTHORIZED, NULL,
+          svn_sasl__errstring(result, NULL, NULL));
       SVN_ERR(write_failure(conn, pool, &err));
       return svn_ra_svn__flush(conn, pool);
     }
@@ -305,20 +311,20 @@ svn_error_t *cyrus_auth_request(svn_ra_s
   secprops.max_ssf = b->repository->max_ssf;
 
   /* Set security properties. */
-  result = sasl_setprop(sasl_ctx, SASL_SEC_PROPS, &secprops);
+  result = svn_sasl__setprop(sasl_ctx, SASL_SEC_PROPS, &secprops);
   if (result != SASL_OK)
     return fail_cmd(conn, pool, sasl_ctx);
 
   /* SASL needs to know if we are externally authenticated. */
   if (b->client_info->tunnel_user)
-    result = sasl_setprop(sasl_ctx, SASL_AUTH_EXTERNAL,
-                          b->client_info->tunnel_user);
+    result = svn_sasl__setprop(sasl_ctx, SASL_AUTH_EXTERNAL,
+                               b->client_info->tunnel_user);
   if (result != SASL_OK)
     return fail_cmd(conn, pool, sasl_ctx);
 
   /* Get the list of mechanisms. */
-  result = sasl_listmech(sasl_ctx, NULL, NULL, " ", NULL,
-                         &mechlist, NULL, &mech_count);
+  result = svn_sasl__listmech(sasl_ctx, NULL, NULL, " ", NULL,
+                              &mechlist, NULL, &mech_count);
 
   if (result != SASL_OK)
     return fail_cmd(conn, pool, sasl_ctx);
@@ -354,7 +360,7 @@ svn_error_t *cyrus_auth_request(svn_ra_s
       const void *user;
 
       /* Get the authenticated username. */
-      result = sasl_getprop(sasl_ctx, SASL_USERNAME, &user);
+      result = svn_sasl__getprop(sasl_ctx, SASL_USERNAME, &user);
 
       if (result != SASL_OK)
         return fail_cmd(conn, pool, sasl_ctx);

Modified: subversion/branches/authzperf/subversion/svnserve/serve.c
URL: http://svn.apache.org/viewvc/subversion/branches/authzperf/subversion/svnserve/serve.c?rev=1741682&r1=1741681&r2=1741682&view=diff
==============================================================================
--- subversion/branches/authzperf/subversion/svnserve/serve.c (original)
+++ subversion/branches/authzperf/subversion/svnserve/serve.c Fri Apr 29 18:38:53 2016
@@ -87,6 +87,9 @@ typedef struct log_baton_t {
   const char *fs_path;
   svn_ra_svn_conn_t *conn;
   int stack_depth;
+
+  /* Set to TRUE when at least one changed path has been sent. */
+  svn_boolean_t started;
 } log_baton_t;
 
 typedef struct file_revs_baton_t {
@@ -627,11 +630,12 @@ create_fs_access(server_baton_t *b, apr_
  * On authentication failure, report failure to the client and set
  * *success to FALSE.  On communications failure, return an error.
  * If NEEDS_USERNAME is TRUE, don't allow anonymous authentication. */
-static svn_error_t *auth(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
+static svn_error_t *auth(svn_boolean_t *success,
+                         svn_ra_svn_conn_t *conn,
                          const char *mech, const char *mecharg,
                          server_baton_t *b, enum access_type required,
                          svn_boolean_t needs_username,
-                         svn_boolean_t *success)
+                         apr_pool_t *scratch_pool)
 {
   const char *user;
   *success = FALSE;
@@ -640,10 +644,10 @@ static svn_error_t *auth(svn_ra_svn_conn
       && b->client_info->tunnel_user && strcmp(mech, "EXTERNAL") == 0)
     {
       if (*mecharg && strcmp(mecharg, b->client_info->tunnel_user) != 0)
-        return svn_ra_svn__write_tuple(conn, pool, "w(c)", "failure",
+        return svn_ra_svn__write_tuple(conn, scratch_pool, "w(c)", "failure",
                                        "Requested username does not match");
       b->client_info->user = b->client_info->tunnel_user;
-      SVN_ERR(svn_ra_svn__write_tuple(conn, pool, "w()", "success"));
+      SVN_ERR(svn_ra_svn__write_tuple(conn, scratch_pool, "w()", "success"));
       *success = TRUE;
       return SVN_NO_ERROR;
     }
@@ -651,7 +655,7 @@ static svn_error_t *auth(svn_ra_svn_conn
   if (b->repository->anon_access >= required
       && strcmp(mech, "ANONYMOUS") == 0 && ! needs_username)
     {
-      SVN_ERR(svn_ra_svn__write_tuple(conn, pool, "w()", "success"));
+      SVN_ERR(svn_ra_svn__write_tuple(conn, scratch_pool, "w()", "success"));
       *success = TRUE;
       return SVN_NO_ERROR;
     }
@@ -659,13 +663,13 @@ static svn_error_t *auth(svn_ra_svn_conn
   if (b->repository->auth_access >= required
       && b->repository->pwdb && strcmp(mech, "CRAM-MD5") == 0)
     {
-      SVN_ERR(svn_ra_svn_cram_server(conn, pool, b->repository->pwdb,
+      SVN_ERR(svn_ra_svn_cram_server(conn, scratch_pool, b->repository->pwdb,
                                      &user, success));
       b->client_info->user = apr_pstrdup(b->pool, user);
       return SVN_NO_ERROR;
     }
 
-  return svn_ra_svn__write_tuple(conn, pool, "w(c)", "failure",
+  return svn_ra_svn__write_tuple(conn, scratch_pool, "w(c)", "failure",
                                 "Must authenticate with listed mechanism");
 }
 
@@ -677,19 +681,26 @@ internal_auth_request(svn_ra_svn_conn_t
 {
   svn_boolean_t success;
   const char *mech, *mecharg;
+  apr_pool_t *iterpool;
 
   SVN_ERR(svn_ra_svn__write_tuple(conn, pool, "w((!", "success"));
   SVN_ERR(send_mechs(conn, pool, b, required, needs_username));
   SVN_ERR(svn_ra_svn__write_tuple(conn, pool, "!)c)", b->repository->realm));
+
+  iterpool = svn_pool_create(pool);
   do
     {
+      svn_pool_clear(iterpool);
+
       SVN_ERR(svn_ra_svn__read_tuple(conn, pool, "w(?c)", &mech, &mecharg));
       if (!*mech)
         break;
-      SVN_ERR(auth(conn, pool, mech, mecharg, b, required, needs_username,
-                   &success));
+      SVN_ERR(auth(&success, conn, mech, mecharg, b, required,
+                   needs_username, iterpool));
     }
   while (!success);
+  svn_pool_destroy(iterpool);
+
   return SVN_NO_ERROR;
 }
 
@@ -839,7 +850,7 @@ static svn_error_t *set_path(svn_ra_svn_
   svn_depth_t depth = svn_depth_infinity;
   svn_boolean_t start_empty;
 
-  SVN_ERR(svn_ra_svn__parse_tuple(params, pool, "crb?(?c)?w",
+  SVN_ERR(svn_ra_svn__parse_tuple(params, "crb?(?c)?w",
                                   &path, &rev, &start_empty, &lock_token,
                                   &depth_word));
   if (depth_word)
@@ -862,7 +873,7 @@ static svn_error_t *delete_path(svn_ra_s
   report_driver_baton_t *b = baton;
   const char *path;
 
-  SVN_ERR(svn_ra_svn__parse_tuple(params, pool, "c", &path));
+  SVN_ERR(svn_ra_svn__parse_tuple(params, "c", &path));
   path = svn_relpath_canonicalize(path, pool);
   if (!b->err)
     b->err = svn_repos_delete_path(b->report_baton, path, pool);
@@ -879,7 +890,7 @@ static svn_error_t *link_path(svn_ra_svn
   /* Default to infinity, for old clients that don't send depth. */
   svn_depth_t depth = svn_depth_infinity;
 
-  SVN_ERR(svn_ra_svn__parse_tuple(params, pool, "ccrb?(?c)?w",
+  SVN_ERR(svn_ra_svn__parse_tuple(params, "ccrb?(?c)?w",
                                  &path, &url, &rev, &start_empty,
                                  &lock_token, &depth_word));
 
@@ -1105,7 +1116,7 @@ reparent(svn_ra_svn_conn_t *conn,
   const char *url;
   const char *fs_path;
 
-  SVN_ERR(svn_ra_svn__parse_tuple(params, pool, "c", &url));
+  SVN_ERR(svn_ra_svn__parse_tuple(params, "c", &url));
   url = svn_uri_canonicalize(url, pool);
   SVN_ERR(trivial_auth_request(conn, pool, b));
   SVN_CMD_ERR(get_fs_path(svn_path_uri_decode(b->repository->repos_url, pool),
@@ -1145,7 +1156,7 @@ get_dated_rev(svn_ra_svn_conn_t *conn,
   apr_time_t tm;
   const char *timestr;
 
-  SVN_ERR(svn_ra_svn__parse_tuple(params, pool, "c", &timestr));
+  SVN_ERR(svn_ra_svn__parse_tuple(params, "c", &timestr));
   SVN_ERR(log_command(b, conn, pool, "get-dated-rev %s", timestr));
 
   SVN_ERR(trivial_auth_request(conn, pool, b));
@@ -1197,7 +1208,7 @@ change_rev_prop2(svn_ra_svn_conn_t *conn
   svn_string_t *old_value;
   svn_boolean_t dont_care;
 
-  SVN_ERR(svn_ra_svn__parse_tuple(params, pool, "rc(?s)(b?s)",
+  SVN_ERR(svn_ra_svn__parse_tuple(params, "rc(?s)(b?s)",
                                   &rev, &name, &value,
                                   &dont_care, &old_value));
 
@@ -1236,7 +1247,7 @@ change_rev_prop(svn_ra_svn_conn_t *conn,
 
   /* Because the revprop value was at one time mandatory, the usual
      optional element pattern "(?s)" isn't used. */
-  SVN_ERR(svn_ra_svn__parse_tuple(params, pool, "rc?s", &rev, &name, &value));
+  SVN_ERR(svn_ra_svn__parse_tuple(params, "rc?s", &rev, &name, &value));
 
   SVN_ERR(do_change_rev_prop(conn, b, rev, name, NULL, value, pool));
 
@@ -1257,7 +1268,7 @@ rev_proplist(svn_ra_svn_conn_t *conn,
   ab.server = b;
   ab.conn = conn;
 
-  SVN_ERR(svn_ra_svn__parse_tuple(params, pool, "r", &rev));
+  SVN_ERR(svn_ra_svn__parse_tuple(params, "r", &rev));
   SVN_ERR(log_command(b, conn, pool, "%s", svn_log__rev_proplist(rev, pool)));
 
   SVN_ERR(trivial_auth_request(conn, pool, b));
@@ -1286,7 +1297,7 @@ rev_prop(svn_ra_svn_conn_t *conn,
   ab.server = b;
   ab.conn = conn;
 
-  SVN_ERR(svn_ra_svn__parse_tuple(params, pool, "rc", &rev, &name));
+  SVN_ERR(svn_ra_svn__parse_tuple(params, "rc", &rev, &name));
   SVN_ERR(log_command(b, conn, pool, "%s",
                       svn_log__rev_prop(rev, name, pool)));
 
@@ -1455,7 +1466,7 @@ commit(svn_ra_svn_conn_t *conn,
     {
       /* Clients before 1.2 don't send lock-tokens, keep-locks,
          and rev-props fields. */
-      SVN_ERR(svn_ra_svn__parse_tuple(params, pool, "c", &log_msg));
+      SVN_ERR(svn_ra_svn__parse_tuple(params, "c", &log_msg));
       lock_tokens = NULL;
       keep_locks = TRUE;
       revprop_list = NULL;
@@ -1463,7 +1474,7 @@ commit(svn_ra_svn_conn_t *conn,
   else
     {
       /* Clients before 1.5 don't send the rev-props field. */
-      SVN_ERR(svn_ra_svn__parse_tuple(params, pool, "clb?l", &log_msg,
+      SVN_ERR(svn_ra_svn__parse_tuple(params, "clb?l", &log_msg,
                                       &lock_tokens, &keep_locks,
                                       &revprop_list));
     }
@@ -1568,7 +1579,7 @@ get_file(svn_ra_svn_conn_t *conn,
   ab.conn = conn;
 
   /* Parse arguments. */
-  SVN_ERR(svn_ra_svn__parse_tuple(params, pool, "c(?r)bb?B", &path, &rev,
+  SVN_ERR(svn_ra_svn__parse_tuple(params, "c(?r)bb?B", &path, &rev,
                                   &want_props, &want_contents,
                                   &wants_inherited_props));
 
@@ -1674,6 +1685,19 @@ get_dir(svn_ra_svn_conn_t *conn,
         svn_ra_svn__list_t *params,
         void *baton)
 {
+  static const svn_string_t str_kind
+    = SVN__STATIC_STRING(SVN_RA_SVN_DIRENT_KIND);
+  static const svn_string_t str_size
+    = SVN__STATIC_STRING(SVN_RA_SVN_DIRENT_SIZE);
+  static const svn_string_t str_has_props
+    = SVN__STATIC_STRING(SVN_RA_SVN_DIRENT_HAS_PROPS);
+  static const svn_string_t str_created_rev
+    = SVN__STATIC_STRING(SVN_RA_SVN_DIRENT_CREATED_REV);
+  static const svn_string_t str_time
+    = SVN__STATIC_STRING(SVN_RA_SVN_DIRENT_TIME);
+  static const svn_string_t str_last_author
+    = SVN__STATIC_STRING(SVN_RA_SVN_DIRENT_LAST_AUTHOR);
+
   server_baton_t *b = baton;
   const char *path, *full_path;
   svn_revnum_t rev;
@@ -1693,7 +1717,7 @@ get_dir(svn_ra_svn_conn_t *conn,
   ab.server = b;
   ab.conn = conn;
 
-  SVN_ERR(svn_ra_svn__parse_tuple(params, pool, "c(?r)bb?l?B", &path, &rev,
+  SVN_ERR(svn_ra_svn__parse_tuple(params, "c(?r)bb?l?B", &path, &rev,
                                   &want_props, &want_contents,
                                   &dirent_fields_list,
                                   &wants_inherited_props));
@@ -1717,17 +1741,17 @@ get_dir(svn_ra_svn_conn_t *conn,
             return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
                                     "Dirent field not a string");
 
-          if (strcmp(SVN_RA_SVN_DIRENT_KIND, elt->u.word) == 0)
+          if (svn_string_compare(&str_kind, &elt->u.word))
             dirent_fields |= SVN_DIRENT_KIND;
-          else if (strcmp(SVN_RA_SVN_DIRENT_SIZE, elt->u.word) == 0)
+          else if (svn_string_compare(&str_size, &elt->u.word))
             dirent_fields |= SVN_DIRENT_SIZE;
-          else if (strcmp(SVN_RA_SVN_DIRENT_HAS_PROPS, elt->u.word) == 0)
+          else if (svn_string_compare(&str_has_props, &elt->u.word))
             dirent_fields |= SVN_DIRENT_HAS_PROPS;
-          else if (strcmp(SVN_RA_SVN_DIRENT_CREATED_REV, elt->u.word) == 0)
+          else if (svn_string_compare(&str_created_rev, &elt->u.word))
             dirent_fields |= SVN_DIRENT_CREATED_REV;
-          else if (strcmp(SVN_RA_SVN_DIRENT_TIME, elt->u.word) == 0)
+          else if (svn_string_compare(&str_time, &elt->u.word))
             dirent_fields |= SVN_DIRENT_TIME;
-          else if (strcmp(SVN_RA_SVN_DIRENT_LAST_AUTHOR, elt->u.word) == 0)
+          else if (svn_string_compare(&str_last_author, &elt->u.word))
             dirent_fields |= SVN_DIRENT_LAST_AUTHOR;
         }
     }
@@ -1807,7 +1831,7 @@ get_dir(svn_ra_svn_conn_t *conn,
               entry_kind = fsent->kind;
 
           if (dirent_fields & SVN_DIRENT_SIZE)
-              if (entry_kind != svn_node_dir)
+              if (fsent->kind != svn_node_dir)
                 SVN_CMD_ERR(svn_fs_file_length(&entry_size, root, file_path,
                                                subpool));
 
@@ -1890,7 +1914,7 @@ update(svn_ra_svn_conn_t *conn,
   svn_boolean_t is_checkout;
 
   /* Parse the arguments. */
-  SVN_ERR(svn_ra_svn__parse_tuple(params, pool, "(?r)cb?w3?3", &rev, &target,
+  SVN_ERR(svn_ra_svn__parse_tuple(params, "(?r)cb?w3?3", &rev, &target,
                                   &recurse, &depth_word,
                                   &send_copyfrom_args, &ignore_ancestry));
   target = svn_relpath_canonicalize(target, pool);
@@ -1948,7 +1972,7 @@ switch_cmd(svn_ra_svn_conn_t *conn,
   svn_tristate_t ignore_ancestry; /* Optional; default TRUE */
 
   /* Parse the arguments. */
-  SVN_ERR(svn_ra_svn__parse_tuple(params, pool, "(?r)cbc?w?33", &rev, &target,
+  SVN_ERR(svn_ra_svn__parse_tuple(params, "(?r)cbc?w?33", &rev, &target,
                                   &recurse, &switch_url, &depth_word,
                                   &send_copyfrom_args, &ignore_ancestry));
   target = svn_relpath_canonicalize(target, pool);
@@ -1998,7 +2022,7 @@ status(svn_ra_svn_conn_t *conn,
   svn_depth_t depth = svn_depth_unknown;
 
   /* Parse the arguments. */
-  SVN_ERR(svn_ra_svn__parse_tuple(params, pool, "cb?(?r)?w",
+  SVN_ERR(svn_ra_svn__parse_tuple(params, "cb?(?r)?w",
                                   &target, &recurse, &rev, &depth_word));
   target = svn_relpath_canonicalize(target, pool);
 
@@ -2041,14 +2065,14 @@ diff(svn_ra_svn_conn_t *conn,
   if (params->nelts == 5)
     {
       /* Clients before 1.4 don't send the text_deltas boolean or depth. */
-      SVN_ERR(svn_ra_svn__parse_tuple(params, pool, "(?r)cbbc", &rev, &target,
+      SVN_ERR(svn_ra_svn__parse_tuple(params, "(?r)cbbc", &rev, &target,
                                       &recurse, &ignore_ancestry, &versus_url));
       text_deltas = TRUE;
       depth_word = NULL;
     }
   else
     {
-      SVN_ERR(svn_ra_svn__parse_tuple(params, pool, "(?r)cbbcb?w",
+      SVN_ERR(svn_ra_svn__parse_tuple(params, "(?r)cbbcb?w",
                                       &rev, &target, &recurse,
                                       &ignore_ancestry, &versus_url,
                                       &text_deltas, &depth_word));
@@ -2113,7 +2137,7 @@ get_mergeinfo(svn_ra_svn_conn_t *conn,
   ab.server = b;
   ab.conn = conn;
 
-  SVN_ERR(svn_ra_svn__parse_tuple(params, pool, "l(?r)wb", &paths, &rev,
+  SVN_ERR(svn_ra_svn__parse_tuple(params, "l(?r)wb", &paths, &rev,
                                   &inherit_word, &include_descendants));
   inherit = svn_inheritance_from_word(inherit_word);
 
@@ -2166,14 +2190,58 @@ get_mergeinfo(svn_ra_svn_conn_t *conn,
   return SVN_NO_ERROR;
 }
 
-/* Send a log entry to the client. */
-static svn_error_t *log_receiver(void *baton,
-                                 svn_log_entry_t *log_entry,
-                                 apr_pool_t *pool)
+/* Send a changed paths list entry to the client.
+   This implements svn_repos_path_change_receiver_t. */
+static svn_error_t *
+path_change_receiver(void *baton,
+                     svn_repos_path_change_t *change,
+                     apr_pool_t *scratch_pool)
+{
+  const char symbol[] = "MADR";
+
+  log_baton_t *b = baton;
+  svn_ra_svn_conn_t *conn = b->conn;
+
+  /* Sanitize and convert change kind to ra-svn level action.
+
+     Pushing that conversion down into libsvn_ra_svn would add yet another
+     API dependency there. */
+  char action = (   change->change_kind < svn_fs_path_change_modify
+                 || change->change_kind > svn_fs_path_change_replace)
+              ? 0
+              : symbol[change->change_kind];
+
+  /* Open lists once: LOG_ENTRY and LOG_ENTRY->CHANGED_PATHS. */
+  if (!b->started)
+    {
+      SVN_ERR(svn_ra_svn__start_list(conn, scratch_pool));
+      SVN_ERR(svn_ra_svn__start_list(conn, scratch_pool));
+      b->started = TRUE;
+    }
+
+  /* Serialize CHANGE. */
+  SVN_ERR(svn_ra_svn__write_data_log_changed_path(
+              conn, scratch_pool,
+              &change->path,
+              action,
+              change->copyfrom_path,
+              change->copyfrom_rev,
+              change->node_kind,
+              change->text_mod,
+              change->prop_mod));
+
+  return SVN_NO_ERROR;
+}
+
+/* Send a the meta data and the revpros for LOG_ENTRY to the client.
+   This implements svn_log_entry_receiver_t. */
+static svn_error_t *
+revision_receiver(void *baton,
+                  svn_repos_log_entry_t *log_entry,
+                  apr_pool_t *scratch_pool)
 {
   log_baton_t *b = baton;
   svn_ra_svn_conn_t *conn = b->conn;
-  apr_hash_index_t *h;
   svn_boolean_t invalid_revnum = FALSE;
   const svn_string_t *author, *date, *message;
   unsigned revprop_count;
@@ -2194,55 +2262,52 @@ static svn_error_t *log_receiver(void *b
 
   svn_compat_log_revprops_out_string(&author, &date, &message,
                                      log_entry->revprops);
-  svn_compat_log_revprops_clear(log_entry->revprops);
-  if (log_entry->revprops)
-    revprop_count = apr_hash_count(log_entry->revprops);
-  else
-    revprop_count = 0;
 
-  /* send LOG_ENTRY */
-  SVN_ERR(svn_ra_svn__start_list(conn, pool));
-
-  /* send LOG_ENTRY->CHANGED_PATHS2 */
-  SVN_ERR(svn_ra_svn__start_list(conn, pool));
-  if (log_entry->changed_paths2)
+  /* Revprops list filtering is somewhat expensive.
+     Avoid doing that for the 90% case where only the standard revprops
+     have been requested and delivered. */
+  if (author && date && message && apr_hash_count(log_entry->revprops) == 3)
     {
-      for (h = apr_hash_first(pool, log_entry->changed_paths2); h;
-                                                        h = apr_hash_next(h))
-        {
-          const char *path = apr_hash_this_key(h);
-          svn_log_changed_path2_t *change = apr_hash_this_val(h);
+      revprop_count = 0;
+    }
+  else
+    {
+      svn_compat_log_revprops_clear(log_entry->revprops);
+      if (log_entry->revprops)
+        revprop_count = apr_hash_count(log_entry->revprops);
+      else
+        revprop_count = 0;
+    }
 
-          SVN_ERR(svn_ra_svn__write_data_log_changed_path(
-                      conn, pool,
-                      path,
-                      change->action,
-                      change->copyfrom_path,
-                      change->copyfrom_rev,
-                      change->node_kind,
-                      /* text_modified and props_modified are never unknown */
-                      change->text_modified  == svn_tristate_true,
-                      change->props_modified == svn_tristate_true));
-        }
+  /* Open lists once: LOG_ENTRY and LOG_ENTRY->CHANGED_PATHS. */
+  if (!b->started)
+    {
+      SVN_ERR(svn_ra_svn__start_list(conn, scratch_pool));
+      SVN_ERR(svn_ra_svn__start_list(conn, scratch_pool));
     }
-  SVN_ERR(svn_ra_svn__end_list(conn, pool));
+
+  /* Close LOG_ENTRY->CHANGED_PATHS. */
+  SVN_ERR(svn_ra_svn__end_list(conn, scratch_pool));
+  b->started = FALSE;
 
   /* send LOG_ENTRY main members */
-  SVN_ERR(svn_ra_svn__write_data_log_entry(conn, pool,
+  SVN_ERR(svn_ra_svn__write_data_log_entry(conn, scratch_pool,
                                            log_entry->revision,
                                            author, date, message,
                                            log_entry->has_children,
                                            invalid_revnum, revprop_count));
 
   /* send LOG_ENTRY->REVPROPS */
-  SVN_ERR(svn_ra_svn__start_list(conn, pool));
+  SVN_ERR(svn_ra_svn__start_list(conn, scratch_pool));
   if (revprop_count)
-    SVN_ERR(svn_ra_svn__write_proplist(conn, pool, log_entry->revprops));
-  SVN_ERR(svn_ra_svn__end_list(conn, pool));
+    SVN_ERR(svn_ra_svn__write_proplist(conn, scratch_pool,
+                                       log_entry->revprops));
+  SVN_ERR(svn_ra_svn__end_list(conn, scratch_pool));
 
   /* send LOG_ENTRY members that were added in later SVN releases */
-  SVN_ERR(svn_ra_svn__write_boolean(conn, pool, log_entry->subtractive_merge));
-  SVN_ERR(svn_ra_svn__end_list(conn, pool));
+  SVN_ERR(svn_ra_svn__write_boolean(conn, scratch_pool,
+                                    log_entry->subtractive_merge));
+  SVN_ERR(svn_ra_svn__end_list(conn, scratch_pool));
 
   if (log_entry->has_children)
     b->stack_depth++;
@@ -2273,7 +2338,7 @@ log_cmd(svn_ra_svn_conn_t *conn,
   ab.server = b;
   ab.conn = conn;
 
-  SVN_ERR(svn_ra_svn__parse_tuple(params, pool, "l(?r)(?r)bb?n?Bwl", &paths,
+  SVN_ERR(svn_ra_svn__parse_tuple(params, "l(?r)(?r)bb?n?Bwl", &paths,
                                   &start_rev, &end_rev, &send_changed_paths,
                                   &strict_node, &limit,
                                   &include_merged_revs_param,
@@ -2340,11 +2405,14 @@ log_cmd(svn_ra_svn_conn_t *conn,
   lb.fs_path = b->repository->fs_path->data;
   lb.conn = conn;
   lb.stack_depth = 0;
-  err = svn_repos_get_logs4(b->repository->repos, full_paths, start_rev,
-                            end_rev, (int) limit, send_changed_paths,
+  lb.started = FALSE;
+  err = svn_repos_get_logs5(b->repository->repos, full_paths, start_rev,
+                            end_rev, (int) limit,
                             strict_node, include_merged_revisions,
                             revprops, authz_check_access_cb_func(b), &ab,
-                            log_receiver, &lb, pool);
+                            send_changed_paths ? path_change_receiver : NULL,
+                            send_changed_paths ? &lb : NULL,
+                            revision_receiver, &lb, pool);
 
   write_err = svn_ra_svn__write_word(conn, pool, "done");
   if (write_err)
@@ -2369,7 +2437,7 @@ check_path(svn_ra_svn_conn_t *conn,
   svn_fs_root_t *root;
   svn_node_kind_t kind;
 
-  SVN_ERR(svn_ra_svn__parse_tuple(params, pool, "c(?r)", &path, &rev));
+  SVN_ERR(svn_ra_svn__parse_tuple(params, "c(?r)", &path, &rev));
   full_path = svn_fspath__join(b->repository->fs_path->data,
                                svn_relpath_canonicalize(path, pool), pool);
 
@@ -2402,7 +2470,7 @@ stat_cmd(svn_ra_svn_conn_t *conn,
   svn_fs_root_t *root;
   svn_dirent_t *dirent;
 
-  SVN_ERR(svn_ra_svn__parse_tuple(params, pool, "c(?r)", &path, &rev));
+  SVN_ERR(svn_ra_svn__parse_tuple(params, "c(?r)", &path, &rev));
   full_path = svn_fspath__join(b->repository->fs_path->data,
                                svn_relpath_canonicalize(path, pool), pool);
 
@@ -2463,7 +2531,7 @@ get_locations(svn_ra_svn_conn_t *conn,
   ab.conn = conn;
 
   /* Parse the arguments. */
-  SVN_ERR(svn_ra_svn__parse_tuple(params, pool, "crl", &relative_path,
+  SVN_ERR(svn_ra_svn__parse_tuple(params, "crl", &relative_path,
                                   &peg_revision,
                                   &loc_revs_proto));
   relative_path = svn_relpath_canonicalize(relative_path, pool);
@@ -2560,7 +2628,7 @@ get_location_segments(svn_ra_svn_conn_t
   ab.conn = conn;
 
   /* Parse the arguments. */
-  SVN_ERR(svn_ra_svn__parse_tuple(params, pool, "c(?r)(?r)(?r)",
+  SVN_ERR(svn_ra_svn__parse_tuple(params, "c(?r)(?r)(?r)",
                                   &relative_path, &peg_revision,
                                   &start_rev, &end_rev));
   relative_path = svn_relpath_canonicalize(relative_path, pool);
@@ -2729,7 +2797,7 @@ get_file_revs(svn_ra_svn_conn_t *conn,
   ab.conn = conn;
 
   /* Parse arguments. */
-  SVN_ERR(svn_ra_svn__parse_tuple(params, pool, "c(?r)(?r)?B",
+  SVN_ERR(svn_ra_svn__parse_tuple(params, "c(?r)(?r)?B",
                                   &path, &start_rev, &end_rev,
                                   &include_merged_revs_param));
   path = svn_relpath_canonicalize(path, pool);
@@ -2779,7 +2847,7 @@ lock(svn_ra_svn_conn_t *conn,
   svn_revnum_t current_rev;
   svn_lock_t *l;
 
-  SVN_ERR(svn_ra_svn__parse_tuple(params, pool, "c(?c)b(?r)", &path, &comment,
+  SVN_ERR(svn_ra_svn__parse_tuple(params, "c(?c)b(?r)", &path, &comment,
                                   &steal_lock, &current_rev));
   full_path = svn_fspath__join(b->repository->fs_path->data,
                                svn_relpath_canonicalize(path, pool), pool);
@@ -2860,7 +2928,7 @@ lock_many(svn_ra_svn_conn_t *conn,
   apr_hash_index_t *hi;
   struct lock_many_baton_t lmb;
 
-  SVN_ERR(svn_ra_svn__parse_tuple(params, pool, "(?c)bl", &comment, &steal_lock,
+  SVN_ERR(svn_ra_svn__parse_tuple(params, "(?c)bl", &comment, &steal_lock,
                                   &path_revs));
 
   subpool = svn_pool_create(pool);
@@ -2885,7 +2953,7 @@ lock_many(svn_ra_svn_conn_t *conn,
         return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
                                 "Lock requests should be list of lists");
 
-      SVN_ERR(svn_ra_svn__parse_tuple(&item->u.list, subpool, "c(?r)", &path,
+      SVN_ERR(svn_ra_svn__parse_tuple(&item->u.list, "c(?r)", &path,
                                       &current_rev));
 
       full_path = svn_fspath__join(b->repository->fs_path->data,
@@ -2944,7 +3012,7 @@ lock_many(svn_ra_svn_conn_t *conn,
 
       svn_pool_clear(subpool);
 
-      write_err = svn_ra_svn__parse_tuple(&item->u.list, subpool, "c(?r)",
+      write_err = svn_ra_svn__parse_tuple(&item->u.list, "c(?r)",
                                           &path, &current_rev);
       if (write_err)
         break;
@@ -3009,7 +3077,7 @@ unlock(svn_ra_svn_conn_t *conn,
   const char *path, *token, *full_path;
   svn_boolean_t break_lock;
 
-  SVN_ERR(svn_ra_svn__parse_tuple(params, pool, "c(?c)b", &path, &token,
+  SVN_ERR(svn_ra_svn__parse_tuple(params, "c(?c)b", &path, &token,
                                  &break_lock));
 
   full_path = svn_fspath__join(b->repository->fs_path->data,
@@ -3046,8 +3114,7 @@ unlock_many(svn_ra_svn_conn_t *conn,
   apr_hash_index_t *hi;
   struct lock_many_baton_t lmb;
 
-  SVN_ERR(svn_ra_svn__parse_tuple(params, pool, "bl", &break_lock,
-                                  &unlock_tokens));
+  SVN_ERR(svn_ra_svn__parse_tuple(params, "bl", &break_lock, &unlock_tokens));
 
   /* Username required unless break_lock was specified. */
   SVN_ERR(must_have_access(conn, pool, b, svn_authz_write, NULL, ! break_lock));
@@ -3066,7 +3133,7 @@ unlock_many(svn_ra_svn_conn_t *conn,
         return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
                                 "Unlock request should be a list of lists");
 
-      SVN_ERR(svn_ra_svn__parse_tuple(&item->u.list, subpool, "c(?c)", &path,
+      SVN_ERR(svn_ra_svn__parse_tuple(&item->u.list, "c(?c)", &path,
                                       &token));
       if (!token)
         token = "";
@@ -3124,7 +3191,7 @@ unlock_many(svn_ra_svn_conn_t *conn,
 
       svn_pool_clear(subpool);
 
-      write_err = svn_ra_svn__parse_tuple(&item->u.list, subpool, "c(?c)",
+      write_err = svn_ra_svn__parse_tuple(&item->u.list, "c(?c)",
                                           &path, &token);
       if (write_err)
         break;
@@ -3183,7 +3250,7 @@ get_lock(svn_ra_svn_conn_t *conn,
   const char *full_path;
   svn_lock_t *l;
 
-  SVN_ERR(svn_ra_svn__parse_tuple(params, pool, "c", &path));
+  SVN_ERR(svn_ra_svn__parse_tuple(params, "c", &path));
 
   full_path = svn_fspath__join(b->repository->fs_path->data,
                                svn_relpath_canonicalize(path, pool), pool);
@@ -3222,7 +3289,7 @@ get_locks(svn_ra_svn_conn_t *conn,
   ab.server = b;
   ab.conn = conn;
 
-  SVN_ERR(svn_ra_svn__parse_tuple(params, pool, "c?(?w)", &path, &depth_word));
+  SVN_ERR(svn_ra_svn__parse_tuple(params, "c?(?w)", &path, &depth_word));
 
   depth = depth_word ? svn_depth_from_word(depth_word) : svn_depth_infinity;
   if ((depth != svn_depth_empty) &&
@@ -3305,7 +3372,7 @@ replay(svn_ra_svn_conn_t *conn,
   svn_boolean_t send_deltas;
   server_baton_t *b = baton;
 
-  SVN_ERR(svn_ra_svn__parse_tuple(params, pool, "rrb", &rev, &low_water_mark,
+  SVN_ERR(svn_ra_svn__parse_tuple(params, "rrb", &rev, &low_water_mark,
                                  &send_deltas));
 
   SVN_ERR(trivial_auth_request(conn, pool, b));
@@ -3333,7 +3400,7 @@ replay_range(svn_ra_svn_conn_t *conn,
   ab.server = b;
   ab.conn = conn;
 
-  SVN_ERR(svn_ra_svn__parse_tuple(params, pool, "rrrb", &start_rev,
+  SVN_ERR(svn_ra_svn__parse_tuple(params, "rrrb", &start_rev,
                                  &end_rev, &low_water_mark,
                                  &send_deltas));
 
@@ -3378,7 +3445,7 @@ get_deleted_rev(svn_ra_svn_conn_t *conn,
   svn_revnum_t end_revision;
   svn_revnum_t revision_deleted;
 
-  SVN_ERR(svn_ra_svn__parse_tuple(params, pool, "crr",
+  SVN_ERR(svn_ra_svn__parse_tuple(params, "crr",
                                  &path, &peg_revision, &end_revision));
   full_path = svn_fspath__join(b->repository->fs_path->data,
                                svn_relpath_canonicalize(path, pool), pool);
@@ -3410,7 +3477,7 @@ get_inherited_props(svn_ra_svn_conn_t *c
   ab.conn = conn;
 
   /* Parse arguments. */
-  SVN_ERR(svn_ra_svn__parse_tuple(params, iterpool, "c(?r)", &path, &rev));
+  SVN_ERR(svn_ra_svn__parse_tuple(params, "c(?r)", &path, &rev));
 
   full_path = svn_fspath__join(b->repository->fs_path->data,
                                svn_relpath_canonicalize(path, iterpool),
@@ -3952,9 +4019,12 @@ construct_server_baton(server_baton_t **
                                                  sizeof(const char *));
     for (i = 0; i < caplist->nelts; i++)
       {
+        static const svn_string_t str_cap_mergeinfo
+          = SVN__STATIC_STRING(SVN_RA_SVN_CAP_MERGEINFO);
+
         item = &SVN_RA_SVN__LIST_ITEM(caplist, i);
         /* ra_svn_set_capabilities() already type-checked for us */
-        if (strcmp(item->u.word, SVN_RA_SVN_CAP_MERGEINFO) == 0)
+        if (svn_string_compare(&item->u.word, &str_cap_mergeinfo))
           {
             APR_ARRAY_PUSH(b->repository->capabilities, const char *)
               = SVN_RA_CAPABILITY_MERGEINFO;
@@ -3962,7 +4032,7 @@ construct_server_baton(server_baton_t **
         /* Save for operational log. */
         if (cap_log->len > 0)
           svn_stringbuf_appendcstr(cap_log, " ");
-        svn_stringbuf_appendcstr(cap_log, item->u.word);
+        svn_stringbuf_appendcstr(cap_log, item->u.word.data);
       }
   }
 
@@ -4100,10 +4170,12 @@ serve_interruptable(svn_boolean_t *termi
 
       /* create the connection, configure ports etc. */
       connection->conn
-        = svn_ra_svn_create_conn4(connection->usock, NULL, NULL,
+        = svn_ra_svn_create_conn5(connection->usock, NULL, NULL,
                                   connection->params->compression_level,
                                   connection->params->zero_copy_limit,
                                   connection->params->error_check_interval,
+                                  connection->params->max_request_size,
+                                  connection->params->max_response_size,
                                   connection->pool);
 
       /* Construct server baton and open the repository for the first time. */

Modified: subversion/branches/authzperf/subversion/svnserve/server.h
URL: http://svn.apache.org/viewvc/subversion/branches/authzperf/subversion/svnserve/server.h?rev=1741682&r1=1741681&r2=1741682&view=diff
==============================================================================
--- subversion/branches/authzperf/subversion/svnserve/server.h (original)
+++ subversion/branches/authzperf/subversion/svnserve/server.h Fri Apr 29 18:38:53 2016
@@ -65,8 +65,10 @@ typedef struct repository_t {
   enum username_case_type username_case; /* Case-normalize the username? */
   svn_boolean_t use_sasl;  /* Use Cyrus SASL for authentication;
                               always false if SVN_HAVE_SASL not defined */
+#ifdef SVN_HAVE_SASL
   unsigned min_ssf;        /* min-encryption SASL parameter */
   unsigned max_ssf;        /* max-encryption SASL parameter */
+#endif
 
   enum access_type auth_access; /* access granted to authenticated users */
   enum access_type anon_access; /* access granted to annonymous users */
@@ -152,6 +154,12 @@ typedef struct serve_params_t {
      coming in from the client. */
   apr_size_t error_check_interval;
 
+  /* If not 0, error out on requests exceeding this value. */
+  apr_uint64_t max_request_size;
+
+  /* If not 0, stop sending a response once it exceeds this value. */
+  apr_uint64_t max_response_size;
+
   /* Use virtual-host-based path to repo. */
   svn_boolean_t vhost;
 } serve_params_t;

Modified: subversion/branches/authzperf/subversion/svnserve/svnserve.c
URL: http://svn.apache.org/viewvc/subversion/branches/authzperf/subversion/svnserve/svnserve.c?rev=1741682&r1=1741681&r2=1741682&view=diff
==============================================================================
--- subversion/branches/authzperf/subversion/svnserve/svnserve.c (original)
+++ subversion/branches/authzperf/subversion/svnserve/svnserve.c Fri Apr 29 18:38:53 2016
@@ -155,6 +155,15 @@ enum run_mode {
  */
 #define ACCEPT_BACKLOG 128
 
+/* Default limit to the client request size in MBytes.  This effectively
+ * limits the size of a paths and individual property values to about
+ * this value.
+ *
+ * Note that (MAX_REQUEST_SIZE + 4M) * THREADPOOL_MAX_SIZE is roughly
+ * the peak memory usage of the RA layer.
+ */
+#define MAX_REQUEST_SIZE 16
+
 #ifdef WIN32
 static apr_os_sock_t winservice_svnserve_accept_socket = INVALID_SOCKET;
 
@@ -210,6 +219,9 @@ void winservice_notify_stop(void)
 #define SVNSERVE_OPT_MIN_THREADS     271
 #define SVNSERVE_OPT_MAX_THREADS     272
 #define SVNSERVE_OPT_BLOCK_READ      273
+#define SVNSERVE_OPT_MAX_REQUEST     274
+#define SVNSERVE_OPT_MAX_RESPONSE    275
+#define SVNSERVE_OPT_CACHE_NODEPROPS 276
 
 /* Text macro because we can't use #ifdef sections inside a N_("...")
    macro expansion. */
@@ -307,6 +319,12 @@ static const apr_getopt_option_t svnserv
         "Default is no.\n"
         "                             "
         "[used for FSFS and FSX repositories only]")},
+    {"cache-nodeprops", SVNSERVE_OPT_CACHE_NODEPROPS, 1,
+     N_("enable or disable caching of node properties\n"
+        "                             "
+        "Default is yes.\n"
+        "                             "
+        "[used for FSFS repositories only]")},
     {"client-speed", SVNSERVE_OPT_CLIENT_SPEED, 1,
      N_("Optimize network handling based on the assumption\n"
         "                             "
@@ -345,6 +363,29 @@ static const apr_getopt_option_t svnserv
         "Default is " APR_STRINGIFY(THREADPOOL_MAX_SIZE) "."
         ONLY_AVAILABLE_WITH_THEADS)},
 #endif
+    {"max-request-size", SVNSERVE_OPT_MAX_REQUEST, 1,
+     N_("Maximum acceptable size of a client request in MB.\n"
+        "                             "
+        "This implicitly limits the length of paths and\n"
+        "                             "
+        "property values that can be sent to the server.\n"
+        "                             "
+        "Also the peak memory usage for protocol handling\n"
+        "                             "
+        "per server thread or sub-process.\n"
+        "                             "
+        "0 disables the size check; default is "
+        APR_STRINGIFY(MAX_REQUEST_SIZE) ".")},
+    {"max-response-size", SVNSERVE_OPT_MAX_RESPONSE, 1,
+     N_("Maximum acceptable server response size in MB.\n"
+        "                             "
+        "Longer responses get truncated and return an\n"
+        "                             "
+        "error.  This limits the server load e.g. when\n"
+        "                             "
+        "checking out at the wrong path level.\n"
+        "                             "
+        "Default is 0 (disabled).")},
     {"foreground",        SVNSERVE_OPT_FOREGROUND, 0,
      N_("run in foreground (useful for debugging)\n"
         "                             "
@@ -680,6 +721,7 @@ sub_main(int *exit_code, int argc, const
   svn_boolean_t is_multi_threaded;
   enum connection_handling_mode handling_mode = CONNECTION_DEFAULT;
   svn_boolean_t cache_fulltexts = TRUE;
+  svn_boolean_t cache_nodeprops = TRUE;
   svn_boolean_t cache_txdeltas = TRUE;
   svn_boolean_t cache_revprops = FALSE;
   svn_boolean_t use_block_read = FALSE;
@@ -728,6 +770,8 @@ sub_main(int *exit_code, int argc, const
   params.memory_cache_size = (apr_uint64_t)-1;
   params.zero_copy_limit = 0;
   params.error_check_interval = 4096;
+  params.max_request_size = MAX_REQUEST_SIZE * 0x100000;
+  params.max_response_size = 0;
 
   while (1)
     {
@@ -870,6 +914,10 @@ sub_main(int *exit_code, int argc, const
           cache_revprops = svn_tristate__from_word(arg) == svn_tristate_true;
           break;
 
+        case SVNSERVE_OPT_CACHE_NODEPROPS:
+          cache_nodeprops = svn_tristate__from_word(arg) == svn_tristate_true;
+          break;
+
         case SVNSERVE_OPT_BLOCK_READ:
           use_block_read = svn_tristate__from_word(arg) == svn_tristate_true;
           break;
@@ -891,6 +939,14 @@ sub_main(int *exit_code, int argc, const
           }
           break;
 
+        case SVNSERVE_OPT_MAX_REQUEST:
+          params.max_request_size = 0x100000 * apr_strtoi64(arg, NULL, 0);
+          break;
+
+        case SVNSERVE_OPT_MAX_RESPONSE:
+          params.max_response_size = 0x100000 * apr_strtoi64(arg, NULL, 0);
+          break;
+
         case SVNSERVE_OPT_MIN_THREADS:
           min_thread_count = (apr_size_t)apr_strtoi64(arg, NULL, 0);
           break;
@@ -980,6 +1036,8 @@ sub_main(int *exit_code, int argc, const
                 cache_txdeltas ? "1" :"0");
   svn_hash_sets(params.fs_config, SVN_FS_CONFIG_FSFS_CACHE_FULLTEXTS,
                 cache_fulltexts ? "1" :"0");
+  svn_hash_sets(params.fs_config, SVN_FS_CONFIG_FSFS_CACHE_NODEPROPS,
+                cache_nodeprops ? "1" :"0");
   svn_hash_sets(params.fs_config, SVN_FS_CONFIG_FSFS_CACHE_REVPROPS,
                 cache_revprops ? "2" :"0");
   svn_hash_sets(params.fs_config, SVN_FS_CONFIG_FSFS_BLOCK_READ,
@@ -1039,10 +1097,12 @@ sub_main(int *exit_code, int argc, const
        * the pool cleanup handlers that call sasl_dispose() (connection_pool)
        * and sasl_done() (pool) are run in the right order. See issue #3664. */
       connection_pool = svn_pool_create(pool);
-      conn = svn_ra_svn_create_conn4(NULL, stdin_stream, stdout_stream,
+      conn = svn_ra_svn_create_conn5(NULL, stdin_stream, stdout_stream,
                                      params.compression_level,
                                      params.zero_copy_limit,
                                      params.error_check_interval,
+                                     params.max_request_size,
+                                     params.max_response_size,
                                      connection_pool);
       err = serve(conn, &params, connection_pool);
       svn_pool_destroy(connection_pool);

Modified: subversion/branches/authzperf/subversion/svnsync/svnsync.c
URL: http://svn.apache.org/viewvc/subversion/branches/authzperf/subversion/svnsync/svnsync.c?rev=1741682&r1=1741681&r2=1741682&view=diff
==============================================================================
--- subversion/branches/authzperf/subversion/svnsync/svnsync.c (original)
+++ subversion/branches/authzperf/subversion/svnsync/svnsync.c Fri Apr 29 18:38:53 2016
@@ -43,7 +43,6 @@
 
 #include "svn_private_config.h"
 
-#include <apr_signal.h>
 #include <apr_uuid.h>
 
 static svn_opt_subcommand_t initialize_cmd,
@@ -324,29 +323,8 @@ typedef struct opt_baton_t {
 /*** Helper functions ***/
 
 
-/* Global record of whether the user has requested cancellation. */
-static volatile sig_atomic_t cancelled = FALSE;
-
-
-/* Callback function for apr_signal(). */
-static void
-signal_handler(int signum)
-{
-  apr_signal(signum, SIG_IGN);
-  cancelled = TRUE;
-}
-
-
 /* Cancellation callback function. */
-static svn_error_t *
-check_cancel(void *baton)
-{
-  if (cancelled)
-    return svn_error_create(SVN_ERR_CANCELLED, NULL, _("Caught signal"));
-  else
-    return SVN_NO_ERROR;
-}
-
+static svn_cancel_func_t check_cancel = 0;
 
 /* Check that the version of libraries in use match what we expect. */
 static svn_error_t *
@@ -1549,7 +1527,7 @@ do_synchronize(svn_ra_session_t *to_sess
   /* Now check to see if there are any revisions to copy. */
   SVN_ERR(svn_ra_get_latest_revnum(from_session, &from_latest, pool));
 
-  if (from_latest < last_merged)
+  if (from_latest <= last_merged)
     return SVN_NO_ERROR;
 
   /* Ok, so there are new revisions, iterate over them copying them
@@ -2363,33 +2341,7 @@ sub_main(int *exit_code, int argc, const
 
   opt_baton.source_prop_encoding = source_prop_encoding;
 
-  apr_signal(SIGINT, signal_handler);
-
-#ifdef SIGBREAK
-  /* SIGBREAK is a Win32 specific signal generated by ctrl-break. */
-  apr_signal(SIGBREAK, signal_handler);
-#endif
-
-#ifdef SIGHUP
-  apr_signal(SIGHUP, signal_handler);
-#endif
-
-#ifdef SIGTERM
-  apr_signal(SIGTERM, signal_handler);
-#endif
-
-#ifdef SIGPIPE
-  /* Disable SIGPIPE generation for the platforms that have it. */
-  apr_signal(SIGPIPE, SIG_IGN);
-#endif
-
-#ifdef SIGXFSZ
-  /* Disable SIGXFSZ generation for the platforms that have it,
-     otherwise working with large files when compiled against an APR
-     that doesn't have large file support will crash the program,
-     which is uncool. */
-  apr_signal(SIGXFSZ, SIG_IGN);
-#endif
+  check_cancel = svn_cmdline__setup_cancellation_handler();
 
   err = svn_cmdline_create_auth_baton2(
           &opt_baton.source_auth_baton,
@@ -2470,5 +2422,8 @@ main(int argc, const char *argv[])
     }
 
   svn_pool_destroy(pool);
+
+  svn_cmdline__cancellation_exit();
+
   return exit_code;
 }

Modified: subversion/branches/authzperf/subversion/tests/cmdline/authz_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/authzperf/subversion/tests/cmdline/authz_tests.py?rev=1741682&r1=1741681&r2=1741682&view=diff
==============================================================================
--- subversion/branches/authzperf/subversion/tests/cmdline/authz_tests.py (original)
+++ subversion/branches/authzperf/subversion/tests/cmdline/authz_tests.py Fri Apr 29 18:38:53 2016
@@ -359,7 +359,7 @@ def authz_write_access(sbox):
 def authz_checkout_test(sbox):
   "test authz for checkout"
 
-  sbox.build(create_wc = False, read_only = True)
+  sbox.build(create_wc = False)
   local_dir = sbox.wc_dir
 
   write_restrictive_svnserve_conf(sbox.repo_dir)
@@ -398,7 +398,7 @@ def authz_checkout_test(sbox):
 def authz_checkout_and_update_test(sbox):
   "test authz for checkout and update"
 
-  sbox.build(create_wc = False, read_only = True)
+  sbox.build(create_wc = False)
   local_dir = sbox.wc_dir
 
   write_restrictive_svnserve_conf(sbox.repo_dir)
@@ -460,7 +460,7 @@ def authz_checkout_and_update_test(sbox)
 def authz_partial_export_test(sbox):
   "test authz for export with unreadable subfolder"
 
-  sbox.build(create_wc = False, read_only = True)
+  sbox.build(create_wc = False)
   local_dir = sbox.wc_dir
 
   # cleanup remains of a previous test run.
@@ -656,7 +656,7 @@ def authz_aliases(sbox):
 def authz_validate(sbox):
   "test the authz validation rules"
 
-  sbox.build(create_wc = False, read_only = True)
+  sbox.build(create_wc = False)
 
   write_restrictive_svnserve_conf(sbox.repo_dir)
 
@@ -782,7 +782,7 @@ def authz_locking(sbox):
                                       sbox.ospath('A/mu'))
 
   if sbox.repo_url.startswith('http'):
-    expected_err = ".*svn: warning: W160039: Unlock.*[Ff]orbidden.*"
+    expected_err = ".*svn: warning: W160039: .*([Aa]uth.*perf|[Ff]orbidden).*"
   else:
     expected_err = ".*svn: warning: W170001: Authorization failed.*"
 
@@ -874,7 +874,7 @@ def authz_svnserve_anon_access_read(sbox
 def authz_switch_to_directory(sbox):
   "switched to directory, no read access on parents"
 
-  sbox.build(read_only = True)
+  sbox.build()
 
   write_authz_file(sbox, {"/": "*=rw", "/A/B": "*=", "/A/B/E": "jrandom = rw"})
 
@@ -1610,6 +1610,57 @@ def authz_log_censor_revprops(sbox):
     args=['--with-revprop', 'svn:author', '--with-revprop', 's',
           '-r1', sbox.repo_url])
 
+@Skip(svntest.main.is_ra_type_file)
+def remove_access_after_commit(sbox):
+  "remove a subdir with authz file"
+
+  sbox.build()
+  wc_dir = sbox.wc_dir
+
+  svntest.main.write_restrictive_svnserve_conf(sbox.repo_dir)
+  svntest.main.write_authz_file(sbox, { "/"      : "*=rw"})
+
+  # Modification in subtree
+  sbox.simple_append('A/B/E/alpha', 'appended\n')
+  sbox.simple_append('A/D/G/rho', 'appended\n')
+  sbox.simple_commit()
+
+  svntest.main.write_authz_file(sbox, { "/"      : "*=rw",
+                                        "/A/B"   : "*=",
+                                        "/A/D"   : "*="})
+
+  # Local modification
+  sbox.simple_append('A/D/G/pi', 'appended\n')
+
+  expected_output = svntest.wc.State(wc_dir, {
+    'A/B'  : Item(status='D '),
+    'A/D'  : Item(status='  ', treeconflict='C'),
+  })
+  expected_disk = svntest.main.greek_state.copy()
+  expected_disk.tweak('A/D/G/rho',
+                      contents="This is the file 'rho'.\nappended\n")
+  expected_disk.tweak('A/D/G/pi',
+                      contents="This is the file 'pi'.\nappended\n")
+  expected_disk.remove('A/B', 'A/B/E', 'A/B/E/alpha', 'A/B/E/beta',
+                       'A/B/F', 'A/B/lambda')
+  expected_status = svntest.actions.get_virginal_state(wc_dir, 2)
+
+  expected_status.tweak('A/D', status='R ',treeconflict='C', )
+  expected_status.tweak('A/D', 'A/D/G', 'A/D/G/pi', 'A/D/G/rho', 'A/D/G/tau',
+                        'A/D/H', 'A/D/H/omega', 'A/D/H/chi', 'A/D/H/psi',
+                        'A/D/gamma', copied='+', wc_rev='-')
+  expected_status.tweak('A/D/G/pi', status='M ')
+  expected_status.remove('A/B', 'A/B/E', 'A/B/E/alpha', 'A/B/E/beta', 'A/B/F',
+                         'A/B/lambda')
+
+  # And expect a mixed rev copy
+  expected_status.tweak('A/D/G/rho', status='A ', entry_status='  ')
+  svntest.actions.run_and_verify_update(wc_dir,
+                                        expected_output,
+                                        expected_disk,
+                                        expected_status,
+                                        [], True)
+
 
 ########################################################################
 # Run the tests
@@ -1646,6 +1697,7 @@ test_list = [ None,
               log_diff_dontdothat,
               authz_file_external_to_authz,
               authz_log_censor_revprops,
+              remove_access_after_commit,
              ]
 serial_only = True
 

Modified: subversion/branches/authzperf/subversion/tests/cmdline/davautocheck.sh
URL: http://svn.apache.org/viewvc/subversion/branches/authzperf/subversion/tests/cmdline/davautocheck.sh?rev=1741682&r1=1741681&r2=1741682&view=diff
==============================================================================
--- subversion/branches/authzperf/subversion/tests/cmdline/davautocheck.sh (original)
+++ subversion/branches/authzperf/subversion/tests/cmdline/davautocheck.sh Fri Apr 29 18:38:53 2016
@@ -163,7 +163,8 @@ get_prog_name() {
 }
 
 # Don't assume sbin is in the PATH.
-# ### Presumably this is used to locate /usr/sbin/apxs or /usr/sbin/apache2
+# This is used to locate apxs when the script is invoked manually; when
+# invoked by 'make davautocheck' the APXS environment variable is set.
 PATH="$PATH:/usr/sbin:/usr/local/sbin"
 
 # Find the source and build directories. The build dir can be found if it is

Modified: subversion/branches/authzperf/subversion/tests/cmdline/diff_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/authzperf/subversion/tests/cmdline/diff_tests.py?rev=1741682&r1=1741681&r2=1741682&view=diff
==============================================================================
--- subversion/branches/authzperf/subversion/tests/cmdline/diff_tests.py (original)
+++ subversion/branches/authzperf/subversion/tests/cmdline/diff_tests.py Fri Apr 29 18:38:53 2016
@@ -5077,6 +5077,7 @@ def diff_symlinks(sbox):
     'Index: %s\n' % sbox.path('to-iota'),
     '===================================================================\n',
     'diff --git a/to-iota b/to-iota\n',
+    'index 3ef26e44..9930f9a0 120644\n',
     '--- a/to-iota\t(revision 2)\n',
     '+++ b/to-iota\t(working copy)\n',
     '@@ -1 +1 @@\n',
@@ -5087,6 +5088,59 @@ def diff_symlinks(sbox):
   ], [], 'diff', wc_dir, '--git')
 
 
+@Issue(4597)
+def diff_peg_resolve(sbox):
+  "peg resolving during diff"
+
+  sbox.build()
+  repo_url = sbox.repo_url
+  wc_dir = sbox.wc_dir
+
+  svntest.actions.run_and_verify_svnmucc(None, [],
+                                         '-U', repo_url, '-m', 'Q',
+                                         'mkdir', 'branches',
+                                         'cp', 1, 'A', 'branches/A1',
+                                         'cp', 1, 'A', 'branches/A2',
+                                         'rm', 'A')
+
+  svntest.actions.run_and_verify_svnmucc(None, [],
+                                         '-U', repo_url, '-m', 'Q2',
+                                         'rm', 'branches/A1')
+
+  svntest.actions.run_and_verify_svn(None, [],
+                                     'diff', repo_url + '/branches/A1@2',
+                                             sbox.wc_dir,
+                                     '--notice-ancestry')
+
+  svntest.actions.run_and_verify_svn(None, [],
+                                     'diff',
+                                     '--old=' + repo_url + '/branches/A1@2',
+                                     '--new=' + sbox.wc_dir,
+                                     '--git')
+
+  svntest.actions.run_and_verify_svn(None, [],
+                                     'diff',
+                                     '--old=' + repo_url + '/branches/A1@2',
+                                     '--new=' + repo_url + '/A@1',
+                                     '--git')
+
+  svntest.actions.run_and_verify_svn(None, '.*E160005: Target path.*A1',
+                                     'diff',
+                                     repo_url + '/branches/A1',
+                                     wc_dir,
+                                     '--summarize')
+
+  svntest.actions.run_and_verify_svn(None, [],
+                                     'diff',
+                                     repo_url + '/branches/A2',
+                                     wc_dir)
+
+  svntest.actions.run_and_verify_svn(None, '.*E200009: .*mix.*',
+                                     'diff',
+                                     repo_url + '/branches/A2',
+                                     wc_dir, '-r1:2')
+
+
 ########################################################################
 #Run the tests
 
@@ -5181,6 +5235,7 @@ test_list = [ None,
               diff_incomplete,
               diff_incomplete_props,
               diff_symlinks,
+              diff_peg_resolve,
               ]
 
 if __name__ == '__main__':

Modified: subversion/branches/authzperf/subversion/tests/cmdline/export_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/authzperf/subversion/tests/cmdline/export_tests.py?rev=1741682&r1=1741681&r2=1741682&view=diff
==============================================================================
--- subversion/branches/authzperf/subversion/tests/cmdline/export_tests.py (original)
+++ subversion/branches/authzperf/subversion/tests/cmdline/export_tests.py Fri Apr 29 18:38:53 2016
@@ -1102,7 +1102,7 @@ test_list = [ None,
               export_file_overwrite_with_force,
               export_custom_keywords,
               export_file_external,
-              export_file_externals2
+              export_file_externals2,
              ]
 
 if __name__ == '__main__':

Modified: subversion/branches/authzperf/subversion/tests/cmdline/externals_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/authzperf/subversion/tests/cmdline/externals_tests.py?rev=1741682&r1=1741681&r2=1741682&view=diff
==============================================================================
--- subversion/branches/authzperf/subversion/tests/cmdline/externals_tests.py (original)
+++ subversion/branches/authzperf/subversion/tests/cmdline/externals_tests.py Fri Apr 29 18:38:53 2016
@@ -3076,6 +3076,7 @@ def list_include_externals(sbox):
     expected_stdout, [], 0, 'ls', '--include-externals', C_url)
 
 @Issue(4293)
+@XFail()
 def move_with_file_externals(sbox):
   "move with file externals"
 
@@ -3252,18 +3253,28 @@ def file_external_unversioned_obstructio
 
   # Update reports a tree-conflict but status doesn't show any such
   # conflict.  I'm no sure whether this is correct.
-  expected_output = svntest.wc.State(wc_dir, {
-      'A'        : Item(status=' U'),
-      'A/mu-ext' : Item(status='  ', treeconflict='A'),
-      })
   expected_disk = svntest.main.greek_state.copy()
   expected_disk.add({
       'A/mu-ext' : Item('unversioned obstruction'),
       })
   expected_status = svntest.actions.get_virginal_state(wc_dir, 2)
+  svntest.actions.run_and_verify_svn(
+                  None,
+                  ".*svn: warning: W155014: The file external '.*mu-ext'"
+                  " can not be created because the node exists.*",
+                  'up', wc_dir)
+  svntest.actions.verify_disk(wc_dir, expected_disk)
+  svntest.actions.run_and_verify_status(wc_dir, expected_status)
+
+  os.remove(sbox.ospath('A/mu-ext'))
+
+  expected_output = svntest.wc.State(wc_dir, {
+      'A/mu-ext' : Item(status='A '),
+      })
   expected_status.add({
-      'A/mu-ext' : Item(status='M ', wc_rev='2', switched='X'),
+      'A/mu-ext' : Item(status='  ', wc_rev='2', switched='X'),
       })
+  expected_disk.tweak('A/mu-ext', contents="This is the file 'mu'.\n")
   svntest.actions.run_and_verify_update(wc_dir,
                                         expected_output, expected_disk,
                                         expected_status)

Modified: subversion/branches/authzperf/subversion/tests/cmdline/lock_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/authzperf/subversion/tests/cmdline/lock_tests.py?rev=1741682&r1=1741681&r2=1741682&view=diff
==============================================================================
--- subversion/branches/authzperf/subversion/tests/cmdline/lock_tests.py (original)
+++ subversion/branches/authzperf/subversion/tests/cmdline/lock_tests.py Fri Apr 29 18:38:53 2016
@@ -1360,11 +1360,8 @@ def unlocked_lock_of_other_user(sbox):
   svntest.actions.run_and_verify_status(wc_dir, expected_status)
 
   # now try to unlock with user jconstant, should fail but exit 0.
-  if sbox.repo_url.startswith("http"):
-    expected_err = "svn: warning: W160039: .*[Uu]nlock of .*403 Forbidden.*"
-  else:
-    expected_err = "svn: warning: W160039: User '%s' is trying to use a lock owned by "\
-                   "'%s'.*" % (svntest.main.wc_author2, svntest.main.wc_author)
+  expected_err = "svn: warning: W160039: User '%s' is trying to use a lock owned by "\
+                 "'%s'.*" % (svntest.main.wc_author2, svntest.main.wc_author)
   svntest.actions.run_and_verify_svn([], expected_err,
                                      'unlock',
                                      '--username', svntest.main.wc_author2,
@@ -2077,25 +2074,6 @@ def dav_lock_timeout(sbox):
   expected_status.tweak('iota', writelocked='K')
   svntest.actions.run_and_verify_status(wc_dir, expected_status)
 
-def http_connection(repo_url):
-
-  import httplib
-  from urlparse import urlparse
-
-  loc = urlparse(repo_url)
-  if loc.scheme == 'http':
-    h = httplib.HTTPConnection(loc.hostname, loc.port)
-  else:
-    try:
-      import ssl # new in python 2.6
-      c = ssl.create_default_context()
-      c.check_hostname = False
-      c.verify_mode = ssl.CERT_NONE
-      h = httplib.HTTPSConnection(loc.hostname, loc.port, context=c)
-    except:
-      h = httplib.HTTPSConnection(loc.hostname, loc.port)
-  return h
-
 @SkipUnless(svntest.main.is_ra_type_dav)
 def create_dav_lock_timeout(sbox):
   "create generic DAV lock with timeout"
@@ -2106,7 +2084,7 @@ def create_dav_lock_timeout(sbox):
   sbox.build()
   wc_dir = sbox.wc_dir
 
-  h = http_connection(sbox.repo_url)
+  h = svntest.main.create_http_connection(sbox.repo_url)
 
   lock_body = '<?xml version="1.0" encoding="utf-8" ?>' \
               '<D:lockinfo xmlns:D="DAV:">' \
@@ -2122,9 +2100,6 @@ def create_dav_lock_timeout(sbox):
     'Timeout': 'Second-86400'
   }
 
-  # Enabling the following line makes this test easier to debug
-  h.set_debuglevel(9)
-
   h.request('LOCK', sbox.repo_url + '/iota', lock_body, lock_headers)
 
   r = h.getresponse()
@@ -2251,7 +2226,7 @@ def dav_lock_refresh(sbox):
                                      sbox.repo_url + '/iota')
 
   # Try to refresh lock using 'If' header
-  h = http_connection(sbox.repo_url)
+  h = svntest.main.create_http_connection(sbox.repo_url)
 
   lock_token = svntest.actions.run_and_parse_info(sbox.repo_url + '/iota')[0]['Lock Token']
 
@@ -2261,9 +2236,6 @@ def dav_lock_refresh(sbox):
     'Timeout': 'Second-7200'
   }
 
-  # Enabling the following line makes this test easier to debug
-  h.set_debuglevel(9)
-
   h.request('LOCK', sbox.repo_url + '/iota', '', lock_headers)
 
   # XFAIL Refreshing of DAV lock fails with error '412 Precondition Failed'
@@ -2365,7 +2337,6 @@ def copy_dir_with_locked_file(sbox):
                                      '-m', '')
 
 @Issue(4557)
-@XFail(svntest.main.is_ra_type_dav)
 def delete_dir_with_lots_of_locked_files(sbox):
   "delete a directory containing lots of locked files"
 
@@ -2394,12 +2365,6 @@ def delete_dir_with_lots_of_locked_files
   #                   always used a special non-standard request)
   sbox.simple_rm("A")
 
-  # But a further replacement never worked
-  sbox.simple_mkdir("A")
-  # And an additional propset didn't work either
-  # (but doesn't require all lock tokens recursively)
-  sbox.simple_propset("k", "v", "A")
-
   # Commit the deletion
   # XFAIL: As of 1.8.10, this commit fails with:
   #  svn: E175002: Unexpected HTTP status 400 'Bad Request' on '<path>'
@@ -2462,7 +2427,49 @@ def delete_locks_on_depth_commit(sbox):
   expected_status.tweak('', 'iota', wc_rev=2)
   svntest.actions.run_and_verify_status(wc_dir, expected_status)
 
+@Issue(4557)
+@XFail(svntest.main.is_ra_type_dav)
+def replace_dir_with_lots_of_locked_files(sbox):
+  "replace directory containing lots of locked files"
+
+  sbox.build()
+  wc_dir = sbox.wc_dir
+
+  # A lot of paths.
+  nfiles = 75 # NOTE: test XPASSES with 50 files!!!
+  locked_paths = []
+  for i in range(nfiles):
+      locked_paths.append(sbox.ospath("A/locked_files/file-%i" % i))
 
+  # Create files at these paths
+  os.mkdir(sbox.ospath("A/locked_files"))
+  for file_path in locked_paths:
+    svntest.main.file_write(file_path, "This is '%s'.\n" % (file_path,))
+  sbox.simple_add("A/locked_files")
+  sbox.simple_commit()
+  sbox.simple_update()
+
+  # lock all the files
+  svntest.actions.run_and_verify_svn(None, [], 'lock',
+                                     '-m', 'All locks',
+                                      *locked_paths)
+  # Locally delete A (regression against earlier versions, which
+  #                   always used a special non-standard request)
+  sbox.simple_rm("A")
+
+  # But a further replacement never worked
+  sbox.simple_mkdir("A")
+  # And an additional propset didn't work either
+  # (but doesn't require all lock tokens recursively)
+  sbox.simple_propset("k", "v", "A")
+
+  # Commit the deletion
+  # XFAIL: As of 1.8.10, this commit fails with:
+  #  svn: E175002: Unexpected HTTP status 400 'Bad Request' on '<path>'
+  # and the following error in the httpd error log:
+  #  request failed: error reading the headers
+  # This problem was introduced on the 1.8.x branch in r1606976.
+  sbox.simple_commit()
 
 ########################################################################
 # Run the tests
@@ -2531,6 +2538,7 @@ test_list = [ None,
               copy_dir_with_locked_file,
               delete_dir_with_lots_of_locked_files,
               delete_locks_on_depth_commit,
+              replace_dir_with_lots_of_locked_files,
             ]
 
 if __name__ == '__main__':

Modified: subversion/branches/authzperf/subversion/tests/cmdline/log_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/authzperf/subversion/tests/cmdline/log_tests.py?rev=1741682&r1=1741681&r2=1741682&view=diff
==============================================================================
--- subversion/branches/authzperf/subversion/tests/cmdline/log_tests.py (original)
+++ subversion/branches/authzperf/subversion/tests/cmdline/log_tests.py Fri Apr 29 18:38:53 2016
@@ -2288,13 +2288,13 @@ def log_search(sbox):
   log_chain = parse_log_output(output)
   check_log_chain(log_chain, [7, 6, 3])
 
-  # search is case-sensitive
+  # search is case-insensitive
   exit_code, output, err = svntest.actions.run_and_verify_svn(
                              None, [], 'log', '--search',
                              'FOR REVISION [367]')
 
   log_chain = parse_log_output(output)
-  check_log_chain(log_chain, [])
+  check_log_chain(log_chain, [7, 6, 3])
 
   # multi-pattern search
   exit_code, output, err = svntest.actions.run_and_verify_svn(

Modified: subversion/branches/authzperf/subversion/tests/cmdline/merge_automatic_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/authzperf/subversion/tests/cmdline/merge_automatic_tests.py?rev=1741682&r1=1741681&r2=1741682&view=diff
==============================================================================
--- subversion/branches/authzperf/subversion/tests/cmdline/merge_automatic_tests.py (original)
+++ subversion/branches/authzperf/subversion/tests/cmdline/merge_automatic_tests.py Fri Apr 29 18:38:53 2016
@@ -1429,7 +1429,7 @@ test_list = [ None,
               effective_sync_results_in_reintegrate,
               reintegrate_subtree_not_updated,
               merge_to_copy_and_add,
-              merge_delete_crlf_file
+              merge_delete_crlf_file,
              ]
 
 if __name__ == '__main__':

Modified: subversion/branches/authzperf/subversion/tests/cmdline/merge_reintegrate_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/authzperf/subversion/tests/cmdline/merge_reintegrate_tests.py?rev=1741682&r1=1741681&r2=1741682&view=diff
==============================================================================
--- subversion/branches/authzperf/subversion/tests/cmdline/merge_reintegrate_tests.py (original)
+++ subversion/branches/authzperf/subversion/tests/cmdline/merge_reintegrate_tests.py Fri Apr 29 18:38:53 2016
@@ -2456,65 +2456,98 @@ def no_source_subtree_mergeinfo(sbox):
 
   svntest.main.file_write(sbox.ospath('A/B/E/alpha'),
                           'AAA\n' +
+                          'X\n' +
                           'BBB\n' +
+                          'Y\n' +
                           'CCC\n')
-  svntest.main.run_svn(None, 'commit', '-m', 'log message', wc_dir)
-  svntest.main.run_svn(None, 'update', wc_dir)
+  sbox.simple_commit()
+  sbox.simple_update()
 
   # Create branch-1
   svntest.main.run_svn(None, 'copy',
                        sbox.ospath('A/B'),
                        sbox.ospath('A/B1'))
-  svntest.main.run_svn(None, 'commit', '-m', 'log message', wc_dir)
+  sbox.simple_commit()
 
   # Create branch-1
   svntest.main.run_svn(None, 'copy',
                        sbox.ospath('A/B'),
                        sbox.ospath('A/B2'))
-  svntest.main.run_svn(None, 'commit', '-m', 'log message', wc_dir)
+  sbox.simple_commit()
 
   # Change on trunk
   svntest.main.file_write(sbox.ospath('A/B/E/alpha'),
                           'AAAxx\n' +
+                          'X\n' +
                           'BBB\n' +
+                          'Y\n' +
                           'CCC\n')
-  svntest.main.run_svn(None, 'commit', '-m', 'log message', wc_dir)
+  sbox.simple_commit()
 
   # Change on branch-1
   svntest.main.file_write(sbox.ospath('A/B1/E/alpha'),
                           'AAA\n' +
+                          'X\n' +
                           'BBBxx\n' +
+                          'Y\n' +
                           'CCC\n')
-  svntest.main.run_svn(None, 'commit', '-m', 'log message', wc_dir)
+  sbox.simple_commit()
 
   # Change on branch-2
   svntest.main.file_write(sbox.ospath('A/B2/E/alpha'),
                           'AAA\n' +
+                          'X\n' +
                           'BBB\n' +
+                          'Y\n' +
                           'CCCxx\n')
-  svntest.main.run_svn(None, 'commit', '-m', 'log message', wc_dir)
-  svntest.main.run_svn(None, 'update', wc_dir)
+  sbox.simple_commit()
+  sbox.simple_update()
 
   # Merge trunk to branch-1
-  svntest.main.run_svn(None, 'merge', '^/A/B', sbox.ospath('A/B1'))
-  svntest.main.run_svn(None, 'commit', '-m', 'log message', wc_dir)
-  svntest.main.run_svn(None, 'update', wc_dir)
+  # svntest.main.run_svn(None, 'merge', '^/A/B', sbox.ospath('A/B1'))
+  A_B1 = sbox.ospath('A/B1')
+  expected_output = wc.State(A_B1, {
+    'E/alpha'           : Item(status='U '),
+  })
+  expected_skip = wc.State(A_B1, { })
+  svntest.actions.run_and_verify_merge(A_B1, None, None, '^/A/B', None,
+                                       expected_output, None, None, None, None,
+                                       expected_skip, [])
+  sbox.simple_commit()
+  sbox.simple_update()
 
   # Reintegrate branch-1 subtree to trunk subtree
   run_reintegrate('^/A/B1/E', sbox.ospath('A/B/E'))
-  svntest.main.run_svn(None, 'commit', '-m', 'log message', wc_dir)
-  svntest.main.run_svn(None, 'update', wc_dir)
+  sbox.simple_commit()
+  sbox.simple_update()
 
   # Merge trunk to branch-2
-  svntest.main.run_svn(None, 'merge', '^/A/B', sbox.ospath('A/B2'))
-  svntest.main.run_svn(None, 'commit', '-m', 'log message', wc_dir)
+  #svntest.main.run_svn(None, 'merge', '^/A/B', sbox.ospath('A/B2'))
+  A_B2 = sbox.ospath('A/B2')
+  expected_output = wc.State(A_B2, {
+    'E'                 : Item(status=' U'),
+    'E/alpha'           : Item(status='U '),
+  })
+  expected_skip = wc.State(A_B1, { })
+  svntest.actions.run_and_verify_merge(A_B2, None, None, '^/A/B', None,
+                                       expected_output, None, None, None, None,
+                                       expected_skip, [])
+  sbox.simple_commit()
   svntest.main.run_svn(None, 'update', wc_dir)
 
   # Reverse merge branch-1 subtree to branch-2 subtree, this removes
   # the subtree mergeinfo from branch 2
-  svntest.main.run_svn(None, 'merge', '-r8:2',
-                       '^/A/B1/E', sbox.ospath('A/B2/E'))
-  svntest.main.run_svn(None, 'commit', '-m', 'log message', wc_dir)
+  #svntest.main.run_svn(None, 'merge', '-r8:2',
+  #                     '^/A/B1/E', sbox.ospath('A/B2/E'))
+  A_B2_E = sbox.ospath('A/B2/E')
+  expected_output = wc.State(A_B2_E, {
+    'alpha'             : Item(status='U '),
+  })
+  expected_skip = wc.State(A_B2_E, { })
+  svntest.actions.run_and_verify_merge(A_B2_E, 8, 2, '^/A/B1/E', None,
+                                       expected_output, None, None, None, None,
+                                       expected_skip, [])
+  sbox.simple_commit()
   svntest.main.run_svn(None, 'update', wc_dir)
 
   # Verify that merge results in no subtree mergeinfo
@@ -2525,8 +2558,8 @@ def no_source_subtree_mergeinfo(sbox):
 
   # Merge trunk to branch-2
   svntest.main.run_svn(None, 'merge', '^/A/B', sbox.ospath('A/B2'))
-  svntest.main.run_svn(None, 'commit', '-m', 'log message', wc_dir)
-  svntest.main.run_svn(None, 'update', wc_dir)
+  sbox.simple_commit()
+  sbox.simple_update()
 
   # Verify that there is still no subtree mergeinfo
   svntest.actions.run_and_verify_svn([], expected_stderr,
@@ -2550,7 +2583,9 @@ def no_source_subtree_mergeinfo(sbox):
       ''        : Item(props={SVN_PROP_MERGEINFO : '/A/B2:4-12'}),
       'E'       : Item(),
       'E/alpha' : Item("AAA\n" +
+                       "X\n" +
                        "BBB\n" +
+                       "Y\n" +
                        "CCCxx\n"),
       'E/beta'  : Item("This is the file 'beta'.\n"),
       'F'       : Item(),

Modified: subversion/branches/authzperf/subversion/tests/cmdline/merge_tree_conflict_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/authzperf/subversion/tests/cmdline/merge_tree_conflict_tests.py?rev=1741682&r1=1741681&r2=1741682&view=diff
==============================================================================
--- subversion/branches/authzperf/subversion/tests/cmdline/merge_tree_conflict_tests.py (original)
+++ subversion/branches/authzperf/subversion/tests/cmdline/merge_tree_conflict_tests.py Fri Apr 29 18:38:53 2016
@@ -2192,6 +2192,112 @@ def merge_obstruction_recording(sbox):
 
   # A resolver action could be smarter though...
 
+def added_revision_recording_in_tree_conflict(sbox):
+  "tree conflict stores added revision for victim"
+
+  sbox.build(empty=True)
+  wc_dir = sbox.wc_dir
+
+  sbox.simple_mkdir('trunk')
+  sbox.simple_commit() #r1
+
+  # Create a branch
+  svntest.actions.run_and_verify_svn(None, [],
+                                     'copy', sbox.repo_url + '/trunk',
+                                     sbox.repo_url + '/branch',
+                                     '-mcopy') # r2
+
+  sbox.simple_add_text('The file on trunk\n', 'trunk/foo')
+  sbox.simple_commit() #r3
+
+  sbox.simple_update()
+
+  # Merge ^/trunk into ^/branch
+  expected_output = svntest.wc.State(sbox.ospath('branch'), {
+    'foo'          : Item(status='A '),
+  })
+  expected_mergeinfo_output = wc.State(sbox.ospath('branch'), {
+    ''                  : Item(status=' U')
+  })
+  expected_elision_output = wc.State(wc_dir, {
+  })
+  expected_disk = wc.State('', {
+    'foo'              : Item(contents="The file on trunk\n"),
+    '.'                 : Item(props={u'svn:mergeinfo': u'/trunk:2-3'}),
+  })
+  expected_status = wc.State(sbox.ospath('branch'), {
+    ''                  : Item(status=' M', wc_rev='3'),
+    'foo'              : Item(status='A ', copied='+', wc_rev='-'),
+  })
+  expected_skip = wc.State('', {
+  })
+  svntest.actions.run_and_verify_merge(sbox.ospath('branch'), None, None,
+                                       sbox.repo_url + '/trunk',
+                                       None,
+                                       expected_output,
+                                       expected_mergeinfo_output,
+                                       expected_elision_output,
+                                       expected_disk,
+                                       expected_status,
+                                       expected_skip,
+                                       check_props=True)
+
+  sbox.simple_commit() #r4
+
+  # Edit the file on the branch
+  sbox.simple_append('branch/foo', 'The file on the branch\n')
+  sbox.simple_commit() #r5
+
+  # Replace file with a directory on trunk
+  sbox.simple_rm('trunk/foo')
+  sbox.simple_mkdir('trunk/foo')
+  sbox.simple_commit() #r6
+
+  sbox.simple_update()
+
+  # Merge ^/trunk into ^/branch
+  expected_output = svntest.wc.State(sbox.ospath('branch'), {
+    'foo'               : Item(status='  ', treeconflict='C')
+  })
+  expected_mergeinfo_output = wc.State(sbox.ospath('branch'), {
+    ''                  : Item(status=' U'),
+  })
+  expected_elision_output = wc.State(wc_dir, {
+  })
+  expected_disk = wc.State('', {
+    'foo'     : Item(contents="The file on trunk\nThe file on the branch\n"),
+      '.'     : Item(props={u'svn:mergeinfo': u'/trunk:2-6'}),
+  })
+  expected_status = wc.State(sbox.ospath('branch'), {
+    ''                  : Item(status=' M', wc_rev='6'),
+    'foo'               : Item(status='  ', treeconflict='C', wc_rev='6'),
+  })
+  expected_skip = wc.State('', {
+  })
+  svntest.actions.run_and_verify_merge(sbox.ospath('branch'), None, None,
+                                       sbox.repo_url + '/trunk',
+                                       None,
+                                       expected_output,
+                                       expected_mergeinfo_output,
+                                       expected_elision_output,
+                                       expected_disk,
+                                       expected_status,
+                                       expected_skip,
+                                       check_props=True)
+
+  # Ensure that revisions in tree conflict info match what we expect.
+  # We used to record source left as ^/trunk/foo@1 instead of ^/trunk/foo@3.
+  # Note that foo was first added in r3.
+  expected_info = [
+    {
+      "Path" : re.escape(sbox.ospath('branch/foo')),
+      "Tree conflict": re.escape(
+        'local file edit, incoming replace with dir upon merge' +
+        ' Source  left: (file) ^/trunk/foo@3' +
+        ' Source right: (dir) ^/trunk/foo@6'),
+    },
+  ]
+  svntest.actions.run_and_verify_info(expected_info, sbox.ospath('branch/foo'))
 
 ########################################################################
 # Run the tests
@@ -2225,6 +2331,7 @@ test_list = [ None,
               merge_replace_on_del_fails,
               merge_conflict_details,
               merge_obstruction_recording,
+              added_revision_recording_in_tree_conflict,
              ]
 
 if __name__ == '__main__':