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

svn commit: r1717223 [42/50] - in /subversion/branches/ra-git: ./ build/ build/ac-macros/ build/generator/ build/generator/templates/ contrib/hook-scripts/ notes/ notes/api-errata/1.9/ notes/move-tracking/ subversion/ subversion/bindings/ctypes-python/...

Modified: subversion/branches/ra-git/subversion/svnserve/serve.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/svnserve/serve.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/svnserve/serve.c (original)
+++ subversion/branches/ra-git/subversion/svnserve/serve.c Mon Nov 30 10:24:16 2015
@@ -627,11 +627,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 +641,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 +652,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 +660,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 +678,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;
 }
 
@@ -830,7 +838,7 @@ static svn_error_t *must_have_access(svn
  */
 
 static svn_error_t *set_path(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
-                             apr_array_header_t *params, void *baton)
+                             svn_ra_svn__list_t *params, void *baton)
 {
   report_driver_baton_t *b = baton;
   const char *path, *lock_token, *depth_word;
@@ -839,9 +847,9 @@ 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",
-                                 &path, &rev, &start_empty, &lock_token,
-                                 &depth_word));
+  SVN_ERR(svn_ra_svn__parse_tuple(params, "crb?(?c)?w",
+                                  &path, &rev, &start_empty, &lock_token,
+                                  &depth_word));
   if (depth_word)
     depth = svn_depth_from_word(depth_word);
   path = svn_relpath_canonicalize(path, pool);
@@ -857,12 +865,12 @@ static svn_error_t *set_path(svn_ra_svn_
 }
 
 static svn_error_t *delete_path(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
-                                apr_array_header_t *params, void *baton)
+                                svn_ra_svn__list_t *params, void *baton)
 {
   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);
@@ -870,7 +878,7 @@ static svn_error_t *delete_path(svn_ra_s
 }
 
 static svn_error_t *link_path(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
-                              apr_array_header_t *params, void *baton)
+                              svn_ra_svn__list_t *params, void *baton)
 {
   report_driver_baton_t *b = baton;
   const char *path, *url, *lock_token, *fs_path, *depth_word;
@@ -879,7 +887,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));
 
@@ -901,7 +909,7 @@ static svn_error_t *link_path(svn_ra_svn
 }
 
 static svn_error_t *finish_report(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
-                                  apr_array_header_t *params, void *baton)
+                                  svn_ra_svn__list_t *params, void *baton)
 {
   report_driver_baton_t *b = baton;
 
@@ -912,8 +920,11 @@ static svn_error_t *finish_report(svn_ra
   return SVN_NO_ERROR;
 }
 
-static svn_error_t *abort_report(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
-                                 apr_array_header_t *params, void *baton)
+static svn_error_t *
+abort_report(svn_ra_svn_conn_t *conn,
+             apr_pool_t *pool,
+             svn_ra_svn__list_t *params,
+             void *baton)
 {
   report_driver_baton_t *b = baton;
 
@@ -922,12 +933,12 @@ static svn_error_t *abort_report(svn_ra_
   return SVN_NO_ERROR;
 }
 
-static const svn_ra_svn_cmd_entry_t report_commands[] = {
+static const svn_ra_svn__cmd_entry_t report_commands[] = {
   { "set-path",      set_path },
   { "delete-path",   delete_path },
   { "link-path",     link_path },
-  { "finish-report", finish_report, TRUE },
-  { "abort-report",  abort_report,  TRUE },
+  { "finish-report", finish_report, NULL, TRUE },
+  { "abort-report",  abort_report,  NULL, TRUE },
   { NULL }
 };
 
@@ -1092,14 +1103,17 @@ get_props(apr_hash_t **props,
 }
 
 /* Set BATON->FS_PATH for the repository URL found in PARAMS. */
-static svn_error_t *reparent(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
-                             apr_array_header_t *params, void *baton)
+static svn_error_t *
+reparent(svn_ra_svn_conn_t *conn,
+         apr_pool_t *pool,
+         svn_ra_svn__list_t *params,
+         void *baton)
 {
   server_baton_t *b = baton;
   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),
@@ -1111,8 +1125,11 @@ static svn_error_t *reparent(svn_ra_svn_
   return SVN_NO_ERROR;
 }
 
-static svn_error_t *get_latest_rev(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
-                                   apr_array_header_t *params, void *baton)
+static svn_error_t *
+get_latest_rev(svn_ra_svn_conn_t *conn,
+               apr_pool_t *pool,
+               svn_ra_svn__list_t *params,
+               void *baton)
 {
   server_baton_t *b = baton;
   svn_revnum_t rev;
@@ -1125,15 +1142,18 @@ static svn_error_t *get_latest_rev(svn_r
   return SVN_NO_ERROR;
 }
 
-static svn_error_t *get_dated_rev(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
-                                  apr_array_header_t *params, void *baton)
+static svn_error_t *
+get_dated_rev(svn_ra_svn_conn_t *conn,
+              apr_pool_t *pool,
+              svn_ra_svn__list_t *params,
+              void *baton)
 {
   server_baton_t *b = baton;
   svn_revnum_t rev;
   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));
@@ -1171,8 +1191,11 @@ static svn_error_t *do_change_rev_prop(s
   return SVN_NO_ERROR;
 }
 
-static svn_error_t *change_rev_prop2(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
-                                     apr_array_header_t *params, void *baton)
+static svn_error_t *
+change_rev_prop2(svn_ra_svn_conn_t *conn,
+                 apr_pool_t *pool,
+                 svn_ra_svn__list_t *params,
+                 void *baton)
 {
   server_baton_t *b = baton;
   svn_revnum_t rev;
@@ -1182,7 +1205,7 @@ static svn_error_t *change_rev_prop2(svn
   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));
 
@@ -1208,8 +1231,11 @@ static svn_error_t *change_rev_prop2(svn
   return SVN_NO_ERROR;
 }
 
-static svn_error_t *change_rev_prop(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
-                                    apr_array_header_t *params, void *baton)
+static svn_error_t *
+change_rev_prop(svn_ra_svn_conn_t *conn,
+                apr_pool_t *pool,
+                svn_ra_svn__list_t *params,
+                void *baton)
 {
   server_baton_t *b = baton;
   svn_revnum_t rev;
@@ -1218,15 +1244,18 @@ static svn_error_t *change_rev_prop(svn_
 
   /* 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));
 
   return SVN_NO_ERROR;
 }
 
-static svn_error_t *rev_proplist(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
-                                 apr_array_header_t *params, void *baton)
+static svn_error_t *
+rev_proplist(svn_ra_svn_conn_t *conn,
+             apr_pool_t *pool,
+             svn_ra_svn__list_t *params,
+             void *baton)
 {
   server_baton_t *b = baton;
   svn_revnum_t rev;
@@ -1236,7 +1265,7 @@ static svn_error_t *rev_proplist(svn_ra_
   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));
@@ -1250,8 +1279,11 @@ static svn_error_t *rev_proplist(svn_ra_
   return SVN_NO_ERROR;
 }
 
-static svn_error_t *rev_prop(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
-                             apr_array_header_t *params, void *baton)
+static svn_error_t *
+rev_prop(svn_ra_svn_conn_t *conn,
+         apr_pool_t *pool,
+         svn_ra_svn__list_t *params,
+         void *baton)
 {
   server_baton_t *b = baton;
   svn_revnum_t rev;
@@ -1262,7 +1294,7 @@ static svn_error_t *rev_prop(svn_ra_svn_
   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)));
 
@@ -1291,14 +1323,15 @@ static svn_error_t *commit_done(const sv
 
 /* Add the LOCK_TOKENS (if any) to the filesystem access context,
  * checking path authorizations using the state in SB as we go.
- * LOCK_TOKENS is an array of svn_ra_svn_item_t structs.  Return a
+ * LOCK_TOKENS is an array of svn_ra_svn__item_t structs.  Return a
  * client error if LOCK_TOKENS is not a list of lists.  If a lock
  * violates the authz configuration, return SVN_ERR_RA_NOT_AUTHORIZED
  * to the client.  Use POOL for temporary allocations only.
  */
-static svn_error_t *add_lock_tokens(const apr_array_header_t *lock_tokens,
-                                    server_baton_t *sb,
-                                    apr_pool_t *pool)
+static svn_error_t *
+add_lock_tokens(const svn_ra_svn__list_t *lock_tokens,
+                server_baton_t *sb,
+                apr_pool_t *pool)
 {
   int i;
   svn_fs_access_t *fs_access;
@@ -1312,24 +1345,23 @@ static svn_error_t *add_lock_tokens(cons
   for (i = 0; i < lock_tokens->nelts; ++i)
     {
       const char *path, *token, *full_path;
-      svn_ra_svn_item_t *path_item, *token_item;
-      svn_ra_svn_item_t *item = &APR_ARRAY_IDX(lock_tokens, i,
-                                               svn_ra_svn_item_t);
+      svn_ra_svn__item_t *path_item, *token_item;
+      svn_ra_svn__item_t *item = &SVN_RA_SVN__LIST_ITEM(lock_tokens, i);
       if (item->kind != SVN_RA_SVN_LIST)
         return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
                                 "Lock tokens aren't a list of lists");
 
-      path_item = &APR_ARRAY_IDX(item->u.list, 0, svn_ra_svn_item_t);
+      path_item = &SVN_RA_SVN__LIST_ITEM(&item->u.list, 0);
       if (path_item->kind != SVN_RA_SVN_STRING)
         return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
                                 "Lock path isn't a string");
 
-      token_item = &APR_ARRAY_IDX(item->u.list, 1, svn_ra_svn_item_t);
+      token_item = &SVN_RA_SVN__LIST_ITEM(&item->u.list, 1);
       if (token_item->kind != SVN_RA_SVN_STRING)
         return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
                                 "Lock token isn't a string");
 
-      path = path_item->u.string->data;
+      path = path_item->u.string.data;
       full_path = svn_fspath__join(sb->repository->fs_path->data,
                                    svn_relpath_canonicalize(path, pool),
                                    pool);
@@ -1338,7 +1370,7 @@ static svn_error_t *add_lock_tokens(cons
         return error_create_and_log(SVN_ERR_RA_NOT_AUTHORIZED, NULL, NULL,
                                     sb);
 
-      token = token_item->u.string->data;
+      token = token_item->u.string.data;
       SVN_ERR(svn_fs_access_add_lock_token2(fs_access, path, token));
     }
 
@@ -1361,10 +1393,11 @@ lock_cb(void *baton,
 }
 
 /* Unlock the paths with lock tokens in LOCK_TOKENS, ignoring any errors.
-   LOCK_TOKENS contains svn_ra_svn_item_t elements, assumed to be lists. */
-static svn_error_t *unlock_paths(const apr_array_header_t *lock_tokens,
-                                 server_baton_t *sb,
-                                 apr_pool_t *pool)
+   LOCK_TOKENS contains svn_ra_svn__item_t elements, assumed to be lists. */
+static svn_error_t *
+unlock_paths(const svn_ra_svn__list_t *lock_tokens,
+             server_baton_t *sb,
+             apr_pool_t *pool)
 {
   int i;
   apr_pool_t *subpool = svn_pool_create(pool);
@@ -1373,18 +1406,18 @@ static svn_error_t *unlock_paths(const a
 
   for (i = 0; i < lock_tokens->nelts; ++i)
     {
-      svn_ra_svn_item_t *item, *path_item, *token_item;
+      svn_ra_svn__item_t *item, *path_item, *token_item;
       const char *path, *token, *full_path;
 
-      item = &APR_ARRAY_IDX(lock_tokens, i, svn_ra_svn_item_t);
-      path_item = &APR_ARRAY_IDX(item->u.list, 0, svn_ra_svn_item_t);
-      token_item = &APR_ARRAY_IDX(item->u.list, 1, svn_ra_svn_item_t);
+      item = &SVN_RA_SVN__LIST_ITEM(lock_tokens, i);
+      path_item = &SVN_RA_SVN__LIST_ITEM(&item->u.list, 0);
+      token_item = &SVN_RA_SVN__LIST_ITEM(&item->u.list, 1);
 
-      path = path_item->u.string->data;
+      path = path_item->u.string.data;
       full_path = svn_fspath__join(sb->repository->fs_path->data,
                                    svn_relpath_canonicalize(path, subpool),
                                    subpool);
-      token = token_item->u.string->data;
+      token = token_item->u.string.data;
       svn_hash_sets(targets, full_path, token);
     }
 
@@ -1401,17 +1434,20 @@ static svn_error_t *unlock_paths(const a
   return SVN_NO_ERROR;
 }
 
-static svn_error_t *commit(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
-                           apr_array_header_t *params, void *baton)
+static svn_error_t *
+commit(svn_ra_svn_conn_t *conn,
+       apr_pool_t *pool,
+       svn_ra_svn__list_t *params,
+       void *baton)
 {
   server_baton_t *b = baton;
   const char *log_msg,
              *date = NULL,
              *author = NULL,
              *post_commit_err = NULL;
-  apr_array_header_t *lock_tokens;
+  svn_ra_svn__list_t *lock_tokens;
   svn_boolean_t keep_locks;
-  apr_array_header_t *revprop_list;
+  svn_ra_svn__list_t *revprop_list;
   apr_hash_t *revprop_table;
   const svn_delta_editor_t *editor;
   void *edit_baton;
@@ -1427,7 +1463,7 @@ static svn_error_t *commit(svn_ra_svn_co
     {
       /* 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;
@@ -1435,7 +1471,7 @@ static svn_error_t *commit(svn_ra_svn_co
   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));
     }
@@ -1513,8 +1549,11 @@ static svn_error_t *commit(svn_ra_svn_co
   return SVN_NO_ERROR;
 }
 
-static svn_error_t *get_file(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
-                             apr_array_header_t *params, void *baton)
+static svn_error_t *
+get_file(svn_ra_svn_conn_t *conn,
+         apr_pool_t *pool,
+         svn_ra_svn__list_t *params,
+         void *baton)
 {
   server_baton_t *b = baton;
   const char *path, *full_path, *hex_digest;
@@ -1537,7 +1576,7 @@ static svn_error_t *get_file(svn_ra_svn_
   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));
 
@@ -1637,9 +1676,25 @@ static svn_error_t *get_file(svn_ra_svn_
   return SVN_NO_ERROR;
 }
 
-static svn_error_t *get_dir(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
-                            apr_array_header_t *params, void *baton)
-{
+static svn_error_t *
+get_dir(svn_ra_svn_conn_t *conn,
+        apr_pool_t *pool,
+        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;
@@ -1651,15 +1706,15 @@ static svn_error_t *get_dir(svn_ra_svn_c
   svn_boolean_t want_props, want_contents;
   apr_uint64_t wants_inherited_props;
   apr_uint64_t dirent_fields;
-  apr_array_header_t *dirent_fields_list = NULL;
-  svn_ra_svn_item_t *elt;
+  svn_ra_svn__list_t *dirent_fields_list = NULL;
+  svn_ra_svn__item_t *elt;
   int i;
   authz_baton_t ab;
 
   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));
@@ -1677,23 +1732,23 @@ static svn_error_t *get_dir(svn_ra_svn_c
 
       for (i = 0; i < dirent_fields_list->nelts; ++i)
         {
-          elt = &APR_ARRAY_IDX(dirent_fields_list, i, svn_ra_svn_item_t);
+          elt = &SVN_RA_SVN__LIST_ITEM(dirent_fields_list, i);
 
           if (elt->kind != SVN_RA_SVN_WORD)
             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;
         }
     }
@@ -1779,12 +1834,9 @@ static svn_error_t *get_dir(svn_ra_svn_c
 
           if (dirent_fields & SVN_DIRENT_HAS_PROPS)
             {
-              apr_hash_t *file_props;
-
               /* has_props */
-              SVN_CMD_ERR(svn_fs_node_proplist(&file_props, root, file_path,
+              SVN_CMD_ERR(svn_fs_node_has_props(&has_props, root, file_path,
                                                subpool));
-              has_props = (apr_hash_count(file_props) > 0);
             }
 
           if ((dirent_fields & SVN_DIRENT_LAST_AUTHOR)
@@ -1841,8 +1893,11 @@ static svn_error_t *get_dir(svn_ra_svn_c
   return svn_ra_svn__write_tuple(conn, pool, "!))");
 }
 
-static svn_error_t *update(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
-                           apr_array_header_t *params, void *baton)
+static svn_error_t *
+update(svn_ra_svn_conn_t *conn,
+       apr_pool_t *pool,
+       svn_ra_svn__list_t *params,
+       void *baton)
 {
   server_baton_t *b = baton;
   svn_revnum_t rev;
@@ -1856,7 +1911,7 @@ static svn_error_t *update(svn_ra_svn_co
   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);
@@ -1896,8 +1951,11 @@ static svn_error_t *update(svn_ra_svn_co
   return SVN_NO_ERROR;
 }
 
-static svn_error_t *switch_cmd(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
-                               apr_array_header_t *params, void *baton)
+static svn_error_t *
+switch_cmd(svn_ra_svn_conn_t *conn,
+           apr_pool_t *pool,
+           svn_ra_svn__list_t *params,
+           void *baton)
 {
   server_baton_t *b = baton;
   svn_revnum_t rev;
@@ -1911,7 +1969,7 @@ static svn_error_t *switch_cmd(svn_ra_sv
   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);
@@ -1946,8 +2004,11 @@ static svn_error_t *switch_cmd(svn_ra_sv
                        (ignore_ancestry != svn_tristate_false));
 }
 
-static svn_error_t *status(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
-                           apr_array_header_t *params, void *baton)
+static svn_error_t *
+status(svn_ra_svn_conn_t *conn,
+       apr_pool_t *pool,
+       svn_ra_svn__list_t *params,
+       void *baton)
 {
   server_baton_t *b = baton;
   svn_revnum_t rev;
@@ -1958,7 +2019,7 @@ static svn_error_t *status(svn_ra_svn_co
   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);
 
@@ -1982,8 +2043,11 @@ static svn_error_t *status(svn_ra_svn_co
                        depth, FALSE, FALSE);
 }
 
-static svn_error_t *diff(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
-                         apr_array_header_t *params, void *baton)
+static svn_error_t *
+diff(svn_ra_svn_conn_t *conn,
+     apr_pool_t *pool,
+     svn_ra_svn__list_t *params,
+     void *baton)
 {
   server_baton_t *b = baton;
   svn_revnum_t rev;
@@ -1998,14 +2062,14 @@ static svn_error_t *diff(svn_ra_svn_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));
@@ -2048,12 +2112,16 @@ static svn_error_t *diff(svn_ra_svn_conn
 
    ASSUMPTION: When performing a 'merge' with two URLs at different
    revisions, the client will call this command more than once. */
-static svn_error_t *get_mergeinfo(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
-                                  apr_array_header_t *params, void *baton)
+static svn_error_t *
+get_mergeinfo(svn_ra_svn_conn_t *conn,
+              apr_pool_t *pool,
+              svn_ra_svn__list_t *params,
+              void *baton)
 {
   server_baton_t *b = baton;
   svn_revnum_t rev;
-  apr_array_header_t *paths, *canonical_paths;
+  svn_ra_svn__list_t *paths;
+  apr_array_header_t *canonical_paths;
   svn_mergeinfo_catalog_t mergeinfo;
   int i;
   apr_hash_index_t *hi;
@@ -2066,7 +2134,7 @@ static svn_error_t *get_mergeinfo(svn_ra
   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);
 
@@ -2074,13 +2142,13 @@ static svn_error_t *get_mergeinfo(svn_ra
   canonical_paths = apr_array_make(pool, paths->nelts, sizeof(const char *));
   for (i = 0; i < paths->nelts; i++)
      {
-        svn_ra_svn_item_t *item = &APR_ARRAY_IDX(paths, i, svn_ra_svn_item_t);
+        svn_ra_svn__item_t *item = &SVN_RA_SVN__LIST_ITEM(paths, i);
         const char *full_path;
 
         if (item->kind != SVN_RA_SVN_STRING)
           return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
                                   _("Path is not a string"));
-        full_path = svn_relpath_canonicalize(item->u.string->data, pool);
+        full_path = svn_relpath_canonicalize(item->u.string.data, pool);
         full_path = svn_fspath__join(b->repository->fs_path->data, full_path, pool);
         APR_ARRAY_PUSH(canonical_paths, const char *) = full_path;
      }
@@ -2203,17 +2271,21 @@ static svn_error_t *log_receiver(void *b
   return SVN_NO_ERROR;
 }
 
-static svn_error_t *log_cmd(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
-                            apr_array_header_t *params, void *baton)
+static svn_error_t *
+log_cmd(svn_ra_svn_conn_t *conn,
+        apr_pool_t *pool,
+        svn_ra_svn__list_t *params,
+        void *baton)
 {
   svn_error_t *err, *write_err;
   server_baton_t *b = baton;
   svn_revnum_t start_rev, end_rev;
   const char *full_path;
   svn_boolean_t send_changed_paths, strict_node, include_merged_revisions;
-  apr_array_header_t *paths, *full_paths, *revprop_items, *revprops;
+  apr_array_header_t *full_paths, *revprops;
+  svn_ra_svn__list_t *paths, *revprop_items;
   char *revprop_word;
-  svn_ra_svn_item_t *elt;
+  svn_ra_svn__item_t *elt;
   int i;
   apr_uint64_t limit, include_merged_revs_param;
   log_baton_t lb;
@@ -2222,7 +2294,7 @@ static svn_error_t *log_cmd(svn_ra_svn_c
   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,
@@ -2246,11 +2318,11 @@ static svn_error_t *log_cmd(svn_ra_svn_c
                                 sizeof(char *));
       for (i = 0; i < revprop_items->nelts; i++)
         {
-          elt = &APR_ARRAY_IDX(revprop_items, i, svn_ra_svn_item_t);
+          elt = &SVN_RA_SVN__LIST_ITEM(revprop_items, i);
           if (elt->kind != SVN_RA_SVN_STRING)
             return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
                                     _("Log revprop entry not a string"));
-          APR_ARRAY_PUSH(revprops, const char *) = elt->u.string->data;
+          APR_ARRAY_PUSH(revprops, const char *) = elt->u.string.data;
         }
     }
   else
@@ -2268,11 +2340,11 @@ static svn_error_t *log_cmd(svn_ra_svn_c
   full_paths = apr_array_make(pool, paths->nelts, sizeof(const char *));
   for (i = 0; i < paths->nelts; i++)
     {
-      elt = &APR_ARRAY_IDX(paths, i, svn_ra_svn_item_t);
+      elt = &SVN_RA_SVN__LIST_ITEM(paths, i);
       if (elt->kind != SVN_RA_SVN_STRING)
         return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
                                 _("Log path entry not a string"));
-      full_path = svn_relpath_canonicalize(elt->u.string->data, pool),
+      full_path = svn_relpath_canonicalize(elt->u.string.data, pool),
       full_path = svn_fspath__join(b->repository->fs_path->data, full_path,
                                    pool);
       APR_ARRAY_PUSH(full_paths, const char *) = full_path;
@@ -2306,8 +2378,11 @@ static svn_error_t *log_cmd(svn_ra_svn_c
   return SVN_NO_ERROR;
 }
 
-static svn_error_t *check_path(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
-                               apr_array_header_t *params, void *baton)
+static svn_error_t *
+check_path(svn_ra_svn_conn_t *conn,
+           apr_pool_t *pool,
+           svn_ra_svn__list_t *params,
+           void *baton)
 {
   server_baton_t *b = baton;
   svn_revnum_t rev;
@@ -2315,7 +2390,7 @@ static svn_error_t *check_path(svn_ra_sv
   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);
 
@@ -2336,8 +2411,11 @@ static svn_error_t *check_path(svn_ra_sv
   return SVN_NO_ERROR;
 }
 
-static svn_error_t *stat_cmd(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
-                             apr_array_header_t *params, void *baton)
+static svn_error_t *
+stat_cmd(svn_ra_svn_conn_t *conn,
+         apr_pool_t *pool,
+         svn_ra_svn__list_t *params,
+         void *baton)
 {
   server_baton_t *b = baton;
   svn_revnum_t rev;
@@ -2345,7 +2423,7 @@ static svn_error_t *stat_cmd(svn_ra_svn_
   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);
 
@@ -2383,14 +2461,18 @@ static svn_error_t *stat_cmd(svn_ra_svn_
   return SVN_NO_ERROR;
 }
 
-static svn_error_t *get_locations(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
-                                  apr_array_header_t *params, void *baton)
+static svn_error_t *
+get_locations(svn_ra_svn_conn_t *conn,
+              apr_pool_t *pool,
+              svn_ra_svn__list_t *params,
+              void *baton)
 {
   svn_error_t *err, *write_err;
   server_baton_t *b = baton;
   svn_revnum_t revision;
-  apr_array_header_t *location_revisions, *loc_revs_proto;
-  svn_ra_svn_item_t *elt;
+  apr_array_header_t *location_revisions;
+  svn_ra_svn__list_t *loc_revs_proto;
+  svn_ra_svn__item_t *elt;
   int i;
   const char *relative_path;
   svn_revnum_t peg_revision;
@@ -2402,7 +2484,7 @@ static svn_error_t *get_locations(svn_ra
   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);
@@ -2414,7 +2496,7 @@ static svn_error_t *get_locations(svn_ra
                                       sizeof(svn_revnum_t));
   for (i = 0; i < loc_revs_proto->nelts; i++)
     {
-      elt = &APR_ARRAY_IDX(loc_revs_proto, i, svn_ra_svn_item_t);
+      elt = &SVN_RA_SVN__LIST_ITEM(loc_revs_proto, i);
       if (elt->kind != SVN_RA_SVN_NUMBER)
         return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
                                 "Get-locations location revisions entry "
@@ -2482,10 +2564,11 @@ static svn_error_t *gls_receiver(svn_loc
                                  segment->path);
 }
 
-static svn_error_t *get_location_segments(svn_ra_svn_conn_t *conn,
-                                          apr_pool_t *pool,
-                                          apr_array_header_t *params,
-                                          void *baton)
+static svn_error_t *
+get_location_segments(svn_ra_svn_conn_t *conn,
+                      apr_pool_t *pool,
+                      svn_ra_svn__list_t *params,
+                      void *baton)
 {
   svn_error_t *err, *write_err;
   server_baton_t *b = baton;
@@ -2498,7 +2581,7 @@ static svn_error_t *get_location_segment
   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);
@@ -2506,32 +2589,56 @@ static svn_error_t *get_location_segment
   abs_path = svn_fspath__join(b->repository->fs_path->data, relative_path,
                               pool);
 
-  if (SVN_IS_VALID_REVNUM(start_rev)
-      && SVN_IS_VALID_REVNUM(end_rev)
-      && (end_rev > start_rev))
+  SVN_ERR(trivial_auth_request(conn, pool, b));
+  SVN_ERR(log_command(baton, conn, pool, "%s",
+                      svn_log__get_location_segments(abs_path, peg_revision,
+                                                     start_rev, end_rev,
+                                                     pool)));
+
+  /* No START_REV or PEG_REVISION?  We'll use HEAD. */
+  if (!SVN_IS_VALID_REVNUM(start_rev) || !SVN_IS_VALID_REVNUM(peg_revision))
     {
-      err = svn_error_createf(SVN_ERR_INCORRECT_PARAMS, NULL,
+      svn_revnum_t youngest;
+
+      err = svn_fs_youngest_rev(&youngest, b->repository->fs, pool);
+
+      if (err)
+        {
+          err = svn_error_compose_create(
+                    svn_ra_svn__write_word(conn, pool, "done"),
+                    err);
+
+          return log_fail_and_flush(err, b, conn, pool);
+        }
+
+      if (!SVN_IS_VALID_REVNUM(start_rev))
+        start_rev = youngest;
+      if (!SVN_IS_VALID_REVNUM(peg_revision))
+        peg_revision = youngest;
+    }
+
+  /* No END_REV?  We'll use 0. */
+  if (!SVN_IS_VALID_REVNUM(end_rev))
+    end_rev = 0;
+
+  if (end_rev > start_rev)
+    {
+      err = svn_ra_svn__write_word(conn, pool, "done");
+      err = svn_error_createf(SVN_ERR_FS_NO_SUCH_REVISION, err,
                               "Get-location-segments end revision must not be "
                               "younger than start revision");
       return log_fail_and_flush(err, b, conn, pool);
     }
 
-  if (SVN_IS_VALID_REVNUM(peg_revision)
-      && SVN_IS_VALID_REVNUM(start_rev)
-      && (start_rev > peg_revision))
+  if (start_rev > peg_revision)
     {
-      err = svn_error_createf(SVN_ERR_INCORRECT_PARAMS, NULL,
+      err = svn_ra_svn__write_word(conn, pool, "done");
+      err = svn_error_createf(SVN_ERR_FS_NO_SUCH_REVISION, err,
                               "Get-location-segments start revision must not "
                               "be younger than peg revision");
       return log_fail_and_flush(err, b, conn, pool);
     }
 
-  SVN_ERR(trivial_auth_request(conn, pool, b));
-  SVN_ERR(log_command(baton, conn, pool, "%s",
-                      svn_log__get_location_segments(abs_path, peg_revision,
-                                                     start_rev, end_rev,
-                                                     pool)));
-
   /* All the parameters are fine - let's perform the query against the
    * repository. */
 
@@ -2546,8 +2653,7 @@ static svn_error_t *get_location_segment
   write_err = svn_ra_svn__write_word(conn, pool, "done");
   if (write_err)
     {
-      svn_error_clear(err);
-      return write_err;
+      return svn_error_compose_create(write_err, err);
     }
   SVN_CMD_ERR(err);
 
@@ -2624,8 +2730,11 @@ static svn_error_t *file_rev_handler(voi
   return SVN_NO_ERROR;
 }
 
-static svn_error_t *get_file_revs(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
-                                  apr_array_header_t *params, void *baton)
+static svn_error_t *
+get_file_revs(svn_ra_svn_conn_t *conn,
+              apr_pool_t *pool,
+              svn_ra_svn__list_t *params,
+              void *baton)
 {
   server_baton_t *b = baton;
   svn_error_t *err, *write_err;
@@ -2641,7 +2750,7 @@ static svn_error_t *get_file_revs(svn_ra
   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);
@@ -2677,8 +2786,11 @@ static svn_error_t *get_file_revs(svn_ra
   return SVN_NO_ERROR;
 }
 
-static svn_error_t *lock(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
-                         apr_array_header_t *params, void *baton)
+static svn_error_t *
+lock(svn_ra_svn_conn_t *conn,
+     apr_pool_t *pool,
+     svn_ra_svn__list_t *params,
+     void *baton)
 {
   server_baton_t *b = baton;
   const char *path;
@@ -2688,7 +2800,7 @@ static svn_error_t *lock(svn_ra_svn_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);
@@ -2751,11 +2863,14 @@ clear_lock_result_hash(apr_hash_t *resul
     }
 }
 
-static svn_error_t *lock_many(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
-                              apr_array_header_t *params, void *baton)
+static svn_error_t *
+lock_many(svn_ra_svn_conn_t *conn,
+          apr_pool_t *pool,
+          svn_ra_svn__list_t *params,
+          void *baton)
 {
   server_baton_t *b = baton;
-  apr_array_header_t *path_revs;
+  svn_ra_svn__list_t *path_revs;
   const char *comment;
   svn_boolean_t steal_lock;
   int i;
@@ -2766,7 +2881,7 @@ static svn_error_t *lock_many(svn_ra_svn
   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);
@@ -2782,8 +2897,7 @@ static svn_error_t *lock_many(svn_ra_svn
     {
       const char *path, *full_path;
       svn_revnum_t current_rev;
-      svn_ra_svn_item_t *item = &APR_ARRAY_IDX(path_revs, i,
-                                               svn_ra_svn_item_t);
+      svn_ra_svn__item_t *item = &SVN_RA_SVN__LIST_ITEM(path_revs, i);
       svn_fs_lock_target_t *target;
 
       svn_pool_clear(subpool);
@@ -2792,7 +2906,7 @@ static svn_error_t *lock_many(svn_ra_svn
         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,
@@ -2846,14 +2960,13 @@ static svn_error_t *lock_many(svn_ra_svn
     {
       const char *path, *full_path;
       svn_revnum_t current_rev;
-      svn_ra_svn_item_t *item = &APR_ARRAY_IDX(path_revs, i,
-                                               svn_ra_svn_item_t);
+      svn_ra_svn__item_t *item = &SVN_RA_SVN__LIST_ITEM(path_revs, i);
       struct lock_result_t *result;
 
       svn_pool_clear(subpool);
 
-      write_err = svn_ra_svn__parse_tuple(item->u.list, subpool, "c(?r)", &path,
-                                          &current_rev);
+      write_err = svn_ra_svn__parse_tuple(&item->u.list, "c(?r)",
+                                          &path, &current_rev);
       if (write_err)
         break;
 
@@ -2907,14 +3020,17 @@ static svn_error_t *lock_many(svn_ra_svn
   return SVN_NO_ERROR;
 }
 
-static svn_error_t *unlock(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
-                           apr_array_header_t *params, void *baton)
+static svn_error_t *
+unlock(svn_ra_svn_conn_t *conn,
+       apr_pool_t *pool,
+       svn_ra_svn__list_t *params,
+       void *baton)
 {
   server_baton_t *b = baton;
   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,
@@ -2934,12 +3050,15 @@ static svn_error_t *unlock(svn_ra_svn_co
   return SVN_NO_ERROR;
 }
 
-static svn_error_t *unlock_many(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
-                                apr_array_header_t *params, void *baton)
+static svn_error_t *
+unlock_many(svn_ra_svn_conn_t *conn,
+            apr_pool_t *pool,
+            svn_ra_svn__list_t *params,
+            void *baton)
 {
   server_baton_t *b = baton;
   svn_boolean_t break_lock;
-  apr_array_header_t *unlock_tokens;
+  svn_ra_svn__list_t *unlock_tokens;
   int i;
   apr_pool_t *subpool;
   svn_error_t *err = SVN_NO_ERROR, *write_err = SVN_NO_ERROR;
@@ -2948,8 +3067,7 @@ static svn_error_t *unlock_many(svn_ra_s
   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));
@@ -2959,8 +3077,7 @@ static svn_error_t *unlock_many(svn_ra_s
   /* Parse the unlock requests from PATH_REVS into TARGETS. */
   for (i = 0; i < unlock_tokens->nelts; i++)
     {
-      svn_ra_svn_item_t *item = &APR_ARRAY_IDX(unlock_tokens, i,
-                                               svn_ra_svn_item_t);
+      svn_ra_svn__item_t *item = &SVN_RA_SVN__LIST_ITEM(unlock_tokens, i);
       const char *path, *full_path, *token;
 
       svn_pool_clear(subpool);
@@ -2969,7 +3086,7 @@ static svn_error_t *unlock_many(svn_ra_s
         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 = "";
@@ -3022,14 +3139,13 @@ static svn_error_t *unlock_many(svn_ra_s
   for (i = 0; i < unlock_tokens->nelts; ++i)
     {
       const char *path, *token, *full_path;
-      svn_ra_svn_item_t *item = &APR_ARRAY_IDX(unlock_tokens, i,
-                                               svn_ra_svn_item_t);
+      svn_ra_svn__item_t *item = &SVN_RA_SVN__LIST_ITEM(unlock_tokens, i);
       struct lock_result_t *result;
 
       svn_pool_clear(subpool);
 
-      write_err = svn_ra_svn__parse_tuple(item->u.list, subpool, "c(?c)", &path,
-                                          &token);
+      write_err = svn_ra_svn__parse_tuple(&item->u.list, "c(?c)",
+                                          &path, &token);
       if (write_err)
         break;
 
@@ -3076,15 +3192,18 @@ static svn_error_t *unlock_many(svn_ra_s
   return SVN_NO_ERROR;
 }
 
-static svn_error_t *get_lock(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
-                             apr_array_header_t *params, void *baton)
+static svn_error_t *
+get_lock(svn_ra_svn_conn_t *conn,
+         apr_pool_t *pool,
+         svn_ra_svn__list_t *params,
+         void *baton)
 {
   server_baton_t *b = baton;
   const char *path;
   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);
@@ -3104,8 +3223,11 @@ static svn_error_t *get_lock(svn_ra_svn_
   return SVN_NO_ERROR;
 }
 
-static svn_error_t *get_locks(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
-                              apr_array_header_t *params, void *baton)
+static svn_error_t *
+get_locks(svn_ra_svn_conn_t *conn,
+          apr_pool_t *pool,
+          svn_ra_svn__list_t *params,
+          void *baton)
 {
   server_baton_t *b = baton;
   const char *path;
@@ -3120,7 +3242,7 @@ static svn_error_t *get_locks(svn_ra_svn
   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) &&
@@ -3193,14 +3315,17 @@ static svn_error_t *replay_one_revision(
   return svn_ra_svn__write_cmd_finish_replay(conn, pool);
 }
 
-static svn_error_t *replay(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
-                           apr_array_header_t *params, void *baton)
+static svn_error_t *
+replay(svn_ra_svn_conn_t *conn,
+       apr_pool_t *pool,
+       svn_ra_svn__list_t *params,
+       void *baton)
 {
   svn_revnum_t rev, low_water_mark;
   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));
@@ -3213,8 +3338,11 @@ static svn_error_t *replay(svn_ra_svn_co
   return SVN_NO_ERROR;
 }
 
-static svn_error_t *replay_range(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
-                                 apr_array_header_t *params, void *baton)
+static svn_error_t *
+replay_range(svn_ra_svn_conn_t *conn,
+             apr_pool_t *pool,
+             svn_ra_svn__list_t *params,
+             void *baton)
 {
   svn_revnum_t start_rev, end_rev, rev, low_water_mark;
   svn_boolean_t send_deltas;
@@ -3225,7 +3353,7 @@ static svn_error_t *replay_range(svn_ra_
   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));
 
@@ -3261,7 +3389,7 @@ static svn_error_t *replay_range(svn_ra_
 static svn_error_t *
 get_deleted_rev(svn_ra_svn_conn_t *conn,
                 apr_pool_t *pool,
-                apr_array_header_t *params,
+                svn_ra_svn__list_t *params,
                 void *baton)
 {
   server_baton_t *b = baton;
@@ -3270,7 +3398,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);
@@ -3285,7 +3413,7 @@ get_deleted_rev(svn_ra_svn_conn_t *conn,
 static svn_error_t *
 get_inherited_props(svn_ra_svn_conn_t *conn,
                     apr_pool_t *pool,
-                    apr_array_header_t *params,
+                    svn_ra_svn__list_t *params,
                     void *baton)
 {
   server_baton_t *b = baton;
@@ -3296,12 +3424,13 @@ get_inherited_props(svn_ra_svn_conn_t *c
   int i;
   apr_pool_t *iterpool = svn_pool_create(pool);
   authz_baton_t ab;
+  svn_node_kind_t node_kind;
 
   ab.server = b;
   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),
@@ -3311,15 +3440,18 @@ get_inherited_props(svn_ra_svn_conn_t *c
   SVN_ERR(must_have_access(conn, iterpool, b, svn_authz_read,
                            full_path, FALSE));
 
-  if (!SVN_IS_VALID_REVNUM(rev))
-    SVN_CMD_ERR(svn_fs_youngest_rev(&rev, b->repository->fs, pool));
-
   SVN_ERR(log_command(b, conn, pool, "%s",
                       svn_log__get_inherited_props(full_path, rev,
                                                    iterpool)));
 
   /* Fetch the properties and a stream for the contents. */
   SVN_CMD_ERR(svn_fs_revision_root(&root, b->repository->fs, rev, iterpool));
+  SVN_CMD_ERR(svn_fs_check_path(&node_kind, root, full_path, pool));
+  if (node_kind == svn_node_none)
+    {
+      SVN_CMD_ERR(svn_error_createf(SVN_ERR_FS_NOT_FOUND, NULL,
+                                    _("'%s' path not found"), full_path));
+    }
   SVN_CMD_ERR(get_props(NULL, &inherited_props, &ab, root, full_path, pool));
 
   /* Send successful command response with revision and props. */
@@ -3345,7 +3477,7 @@ get_inherited_props(svn_ra_svn_conn_t *c
   return SVN_NO_ERROR;
 }
 
-static const svn_ra_svn_cmd_entry_t main_commands[] = {
+static const svn_ra_svn__cmd_entry_t main_commands[] = {
   { "reparent",        reparent },
   { "get-latest-rev",  get_latest_rev },
   { "get-dated-rev",   get_dated_rev },
@@ -3750,7 +3882,7 @@ construct_server_baton(server_baton_t **
   svn_error_t *err, *io_err;
   apr_uint64_t ver;
   const char *client_url, *ra_client_string, *client_string;
-  apr_array_header_t *caplist;
+  svn_ra_svn__list_t *caplist;
   apr_pool_t *conn_pool = svn_ra_svn__get_pool(conn);
   server_baton_t *b = apr_pcalloc(conn_pool, sizeof(*b));
   fs_warning_baton_t *warn_baton;
@@ -3816,7 +3948,7 @@ construct_server_baton(server_baton_t **
     return SVN_NO_ERROR;
 
   client_url = svn_uri_canonicalize(client_url, conn_pool);
-  SVN_ERR(svn_ra_svn_set_capabilities(conn, caplist));
+  SVN_ERR(svn_ra_svn__set_capabilities(conn, caplist));
 
   /* All released versions of Subversion support edit-pipeline,
    * so we do not accept connections from clients that do not. */
@@ -3827,22 +3959,25 @@ construct_server_baton(server_baton_t **
      they get handed to the start-commit hook).  While we could add a
      new interface to re-retrieve them from conn and convert the
      result to a list, it's simpler to just convert caplist by hand
-     here, since we already have it and turning 'svn_ra_svn_item_t's
+     here, since we already have it and turning 'svn_ra_svn__item_t's
      into 'const char *'s is pretty easy.
 
      We only record capabilities we care about.  The client may report
      more (because it doesn't know what the server cares about). */
   {
     int i;
-    svn_ra_svn_item_t *item;
+    svn_ra_svn__item_t *item;
 
     b->repository->capabilities = apr_array_make(conn_pool, 1,
                                                  sizeof(const char *));
     for (i = 0; i < caplist->nelts; i++)
       {
-        item = &APR_ARRAY_IDX(caplist, i, svn_ra_svn_item_t);
+        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;
@@ -3850,7 +3985,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);
       }
   }
 
@@ -3959,7 +4094,7 @@ serve_interruptable(svn_boolean_t *termi
 {
   svn_boolean_t terminate = FALSE;
   svn_error_t *err = NULL;
-  const svn_ra_svn_cmd_entry_t *command;
+  const svn_ra_svn__cmd_entry_t *command;
   apr_pool_t *iterpool = svn_pool_create(pool);
 
   /* Prepare command parser. */
@@ -3988,10 +4123,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/ra-git/subversion/svnserve/server.h
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/svnserve/server.h?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/svnserve/server.h (original)
+++ subversion/branches/ra-git/subversion/svnserve/server.h Mon Nov 30 10:24:16 2015
@@ -152,6 +152,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/ra-git/subversion/svnserve/svnserve.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/svnserve/svnserve.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/svnserve/svnserve.c (original)
+++ subversion/branches/ra-git/subversion/svnserve/svnserve.c Mon Nov 30 10:24:16 2015
@@ -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,19 @@ 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
+
+/* Text macro because we can't use #ifdef sections inside a N_("...")
+   macro expansion. */
+#ifdef CONNECTION_HAVE_THREAD_OPTION
+#define ONLY_AVAILABLE_WITH_THEADS \
+        "\n" \
+        "                             "\
+        "[used only with --threads]"
+#else
+#define ONLY_AVAILABLE_WITH_THEADS ""
+#endif
 
 static const apr_getopt_option_t svnserve__options[] =
   {
@@ -317,34 +339,46 @@ static const apr_getopt_option_t svnserv
      * ### this option never exists when --service exists. */
     {"threads",          'T', 0, N_("use threads instead of fork "
                                     "[mode: daemon]")},
+#endif
+#if APR_HAS_THREADS
     {"min-threads",      SVNSERVE_OPT_MIN_THREADS, 1,
      N_("Minimum number of server threads, even if idle.\n"
         "                             "
-        "Caped to max-threads; minimum value is 0.\n"
-        "                             "
-        "Default is 1.\n"
+        "Capped to max-threads; minimum value is 0.\n"
         "                             "
-        "[used only with --threads]")},
-#if (APR_SIZEOF_VOIDP <= 4)
+        "Default is 1."
+        ONLY_AVAILABLE_WITH_THEADS)},
     {"max-threads",      SVNSERVE_OPT_MAX_THREADS, 1,
      N_("Maximum number of server threads, even if there\n"
         "                             "
         "are more connections.  Minimum value is 1.\n"
         "                             "
-        "Default is 64.\n"
+        "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"
         "                             "
-        "[used only with --threads]")},
-#else
-    {"max-threads",      SVNSERVE_OPT_MAX_THREADS, 1,
-     N_("Maximum number of server threads, even if there\n"
+        "This implicitly limits the length of paths and\n"
         "                             "
-        "are more connections.  Minimum value is 1.\n"
+        "property values that can be sent to the server.\n"
         "                             "
-        "Default is 256.\n"
+        "Also the peak memory usage for protocol handling\n"
         "                             "
-        "[used only with --threads]")},
-#endif
-#endif
+        "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"
         "                             "
@@ -728,6 +762,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)
     {
@@ -891,6 +927,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;
@@ -1030,17 +1074,21 @@ sub_main(int *exit_code, int argc, const
       apr_pool_cleanup_register(pool, pool, apr_pool_cleanup_null,
                                 redirect_stdout);
 
-      SVN_ERR(svn_stream_for_stdin(&stdin_stream, pool));
+      /* We are an interactive server, i.e. can't use APR buffering on
+       * stdin. */
+      SVN_ERR(svn_stream_for_stdin2(&stdin_stream, FALSE, pool));
       SVN_ERR(svn_stream_for_stdout(&stdout_stream, pool));
 
       /* Use a subpool for the connection to ensure that if SASL is used
        * 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/ra-git/subversion/svnsync/svnsync.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/svnsync/svnsync.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/svnsync/svnsync.c (original)
+++ subversion/branches/ra-git/subversion/svnsync/svnsync.c Mon Nov 30 10:24:16 2015
@@ -68,12 +68,10 @@ enum svnsync__opt {
   svnsync_opt_disable_locking,
   svnsync_opt_version,
   svnsync_opt_trust_server_cert,
-  svnsync_opt_trust_server_cert_unknown_ca,
-  svnsync_opt_trust_server_cert_cn_mismatch,
-  svnsync_opt_trust_server_cert_expired,
-  svnsync_opt_trust_server_cert_not_yet_valid,
-  svnsync_opt_trust_server_cert_other_failure,
+  svnsync_opt_trust_server_cert_failures_src,
+  svnsync_opt_trust_server_cert_failures_dst,
   svnsync_opt_allow_non_empty,
+  svnsync_opt_skip_unchanged,
   svnsync_opt_steal_lock
 };
 
@@ -83,11 +81,8 @@ enum svnsync__opt {
                              svnsync_opt_auth_username, \
                              svnsync_opt_auth_password, \
                              svnsync_opt_trust_server_cert, \
-                             svnsync_opt_trust_server_cert_unknown_ca, \
-                             svnsync_opt_trust_server_cert_cn_mismatch, \
-                             svnsync_opt_trust_server_cert_expired, \
-                             svnsync_opt_trust_server_cert_not_yet_valid, \
-                             svnsync_opt_trust_server_cert_other_failure, \
+                             svnsync_opt_trust_server_cert_failures_src, \
+                             svnsync_opt_trust_server_cert_failures_dst, \
                              svnsync_opt_source_username, \
                              svnsync_opt_source_password, \
                              svnsync_opt_sync_username, \
@@ -154,9 +149,14 @@ static const svn_opt_subcommand_desc2_t
          "if untrusted users/administrators may have write access to the\n"
          "DEST_URL repository.\n"
          "\n"
+         "Unless you need to trigger the destination repositoy's revprop\n"
+         "change hooks for all revision properties, it is recommended to use\n"
+         "the --skip-unchanged option for best performance.\n"
+         "\n"
          "Form 2 is deprecated syntax, equivalent to specifying \"-rREV[:REV2]\".\n"),
       { SVNSYNC_OPTS_DEFAULT, svnsync_opt_source_prop_encoding, 'q', 'r',
-        svnsync_opt_disable_locking, svnsync_opt_steal_lock, 'M' } },
+        svnsync_opt_disable_locking, svnsync_opt_steal_lock,
+        svnsync_opt_skip_unchanged, 'M' } },
     { "info", info_cmd, { 0 },
       N_("usage: svnsync info DEST_URL\n"
          "\n"
@@ -185,6 +185,8 @@ static const apr_getopt_option_t svnsync
                           "    'HEAD'       latest in repository") },
     {"allow-non-empty", svnsync_opt_allow_non_empty, 0,
                        N_("allow a non-empty destination repository") },
+    {"skip-unchanged", svnsync_opt_skip_unchanged, 0,
+                       N_("don't copy unchanged revision properties") },
     {"non-interactive", svnsync_opt_non_interactive, 0,
                        N_("do no interactive prompting (default is to prompt\n"
                           "                             "
@@ -204,29 +206,37 @@ static const apr_getopt_option_t svnsync
                           "                             "
                           "see --source-password and --sync-password)") },
     {"trust-server-cert", svnsync_opt_trust_server_cert, 0,
-                      N_("deprecated; same as --trust-unknown-ca")},
-    {"trust-unknown-ca", svnsync_opt_trust_server_cert_unknown_ca, 0,
-                      N_("with --non-interactive, accept SSL server\n"
+                      N_("deprecated; same as\n"
+                         "                             "
+                         "--source-trust-server-cert-failures=unknown-ca\n"
+                         "                             "
+                         "--sync-trust-server-cert-failures=unknown-ca")},
+    {"source-trust-server-cert-failures", svnsync_opt_trust_server_cert_failures_src, 1,
+                      N_("with --non-interactive, accept SSL\n"
                          "                             "
-                         "certificates from unknown certificate authorities")},
-    {"trust-cn-mismatch", svnsync_opt_trust_server_cert_cn_mismatch, 0,
-                      N_("with --non-interactive, accept SSL server\n"
+                         "server certificates with failures.\n"
                          "                             "
-                         "certificates even if the server hostname does not\n"
+                         "ARG is a comma-separated list of:\n"
                          "                             "
-                         "match the certificate's common name attribute")},
-    {"trust-expired", svnsync_opt_trust_server_cert_expired, 0,
-                      N_("with --non-interactive, accept expired SSL server\n"
+                         "- 'unknown-ca' (Unknown Authority)\n"
                          "                             "
-                         "certificates")},
-    {"trust-not-yet-valid", svnsync_opt_trust_server_cert_not_yet_valid, 0,
-                      N_("with --non-interactive, accept SSL server\n"
+                         "- 'cn-mismatch' (Hostname mismatch)\n"
                          "                             "
-                         "certificates from the future")},
-    {"trust-other-failure", svnsync_opt_trust_server_cert_other_failure, 0,
-                      N_("with --non-interactive, accept SSL server\n"
+                         "- 'expired' (Expired certificate)\n"
                          "                             "
-                         "certificates with failures other than the above")},
+                         "- 'not-yet-valid' (Not yet valid certificate)\n"
+                         "                             "
+                         "- 'other' (all other not separately classified\n"
+                         "                             "
+                         "  certificate errors).\n"
+                         "                             "
+                         "Applied to the source URL.")},
+    {"sync-trust-server-cert-failures", svnsync_opt_trust_server_cert_failures_dst, 1,
+                       N_("Like\n"
+                          "                             "
+                          "--source-trust-server-cert-failures,\n"
+                          "                             "
+                          "but applied to the destination URL.")},
     {"source-username", svnsync_opt_source_username, 1,
                        N_("connect to source repository with username ARG") },
     {"source-password", svnsync_opt_source_password, 1,
@@ -280,11 +290,13 @@ static const apr_getopt_option_t svnsync
 
 typedef struct opt_baton_t {
   svn_boolean_t non_interactive;
-  svn_boolean_t trust_server_cert_unknown_ca;
-  svn_boolean_t trust_server_cert_cn_mismatch;
-  svn_boolean_t trust_server_cert_expired;
-  svn_boolean_t trust_server_cert_not_yet_valid;
-  svn_boolean_t trust_server_cert_other_failure;
+  struct { 
+    svn_boolean_t trust_server_cert_unknown_ca;
+    svn_boolean_t trust_server_cert_cn_mismatch;
+    svn_boolean_t trust_server_cert_expired;
+    svn_boolean_t trust_server_cert_not_yet_valid;
+    svn_boolean_t trust_server_cert_other_failure;
+  } src_trust, dst_trust;
   svn_boolean_t no_auth_cache;
   svn_auth_baton_t *source_auth_baton;
   svn_auth_baton_t *sync_auth_baton;
@@ -299,6 +311,7 @@ typedef struct opt_baton_t {
   svn_boolean_t steal_lock;
   svn_boolean_t quiet;
   svn_boolean_t allow_non_empty;
+  svn_boolean_t skip_unchanged;
   svn_boolean_t version;
   svn_boolean_t help;
   svn_opt_revision_t start_rev;
@@ -418,6 +431,7 @@ typedef struct subcommand_baton_t {
   svn_ra_callbacks2_t sync_callbacks;
   svn_boolean_t quiet;
   svn_boolean_t allow_non_empty;
+  svn_boolean_t skip_unchanged; /* Enable optimization for revprop changes. */
   const char *to_url;
 
   /* initialize, synchronize, and copy-revprops only */
@@ -588,6 +602,10 @@ filter_props(int *filtered_count, apr_ha
  * and set *FILTERED_COUNT to the number of properties thus omitted.
  * REV_PROPS is a hash mapping (char *)propname to (svn_string_t *)propval.
  *
+ * If OLD_REV_PROPS is not NULL, skip all properties that did not change.
+ * Note that this implies that hook scripts won't be triggered anymore for
+ * those revprops that did not change.
+ *
  * All allocations will be done in a subpool of POOL.
  */
 static svn_error_t *
@@ -595,6 +613,7 @@ write_revprops(int *filtered_count,
                svn_ra_session_t *session,
                svn_revnum_t rev,
                apr_hash_t *rev_props,
+               apr_hash_t *old_rev_props,
                apr_pool_t *pool)
 {
   apr_pool_t *subpool = svn_pool_create(pool);
@@ -612,6 +631,17 @@ write_revprops(int *filtered_count,
       if (strncmp(propname, SVNSYNC_PROP_PREFIX,
                   sizeof(SVNSYNC_PROP_PREFIX) - 1) != 0)
         {
+          if (old_rev_props)
+            {
+              /* Skip the RA call for any no-op propset. */
+              const svn_string_t *old_value = svn_hash_gets(old_rev_props,
+                                                            propname);
+              if ((!old_value && !propval)
+                  || (old_value && propval
+                      && svn_string_compare(old_value, propval)))
+                continue;
+            }
+
           SVN_ERR(svn_ra_change_rev_prop2(session, rev, propname, NULL,
                                           propval, subpool));
         }
@@ -673,6 +703,10 @@ log_properties_normalized(int normalized
  * If SYNC is TRUE, then properties on the destination revision that
  * do not exist on the source revision will be removed.
  *
+ * If SKIP_UNCHANGED is TRUE, skip any no-op revprop changes. This also
+ * prevents hook scripts from firing for those unchanged revprops.  Has
+ * no effect if SYNC is FALSE.
+ *
  * If QUIET is FALSE, then log_properties_copied() is called to log that
  * properties were copied for revision REV.
  *
@@ -685,6 +719,7 @@ copy_revprops(svn_ra_session_t *from_ses
               svn_ra_session_t *to_session,
               svn_revnum_t rev,
               svn_boolean_t sync,
+              svn_boolean_t skip_unchanged,
               svn_boolean_t quiet,
               const char *source_prop_encoding,
               int *normalized_count,
@@ -710,7 +745,8 @@ copy_revprops(svn_ra_session_t *from_ses
                                      source_prop_encoding, pool));
 
   /* Copy all but the svn:svnsync properties. */
-  SVN_ERR(write_revprops(&filtered_count, to_session, rev, rev_props, pool));
+  SVN_ERR(write_revprops(&filtered_count, to_session, rev, rev_props,
+                         skip_unchanged ? existing_props : NULL, pool));
 
   /* Delete those properties that were in TARGET but not in SOURCE */
   if (sync)
@@ -746,6 +782,7 @@ make_subcommand_baton(opt_baton_t *opt_b
   b->sync_callbacks.open_tmp_file = open_tmp_file;
   b->sync_callbacks.auth_baton = opt_baton->sync_auth_baton;
   b->quiet = opt_baton->quiet;
+  b->skip_unchanged = opt_baton->skip_unchanged;
   b->allow_non_empty = opt_baton->allow_non_empty;
   b->to_url = to_url;
   b->source_prop_encoding = opt_baton->source_prop_encoding;
@@ -855,9 +892,9 @@ do_initialize(svn_ra_session_t *to_sessi
      LATEST is not 0, this really serves merely aesthetic and
      informational purposes, keeping the output of this command
      consistent while allowing folks to see what the latest revision is.  */
-  SVN_ERR(copy_revprops(from_session, to_session, latest, FALSE, baton->quiet,
-                        baton->source_prop_encoding, &normalized_rev_props_count,
-                        pool));
+  SVN_ERR(copy_revprops(from_session, to_session, latest, FALSE, FALSE,
+                        baton->quiet, baton->source_prop_encoding,
+                        &normalized_rev_props_count, pool));
 
   SVN_ERR(log_properties_normalized(normalized_rev_props_count, 0, pool));
 
@@ -1368,7 +1405,7 @@ replay_rev_finished(svn_revnum_t revisio
   rb->normalized_rev_props_count += normalized_count;
 
   SVN_ERR(write_revprops(&filtered_count, rb->to_session, revision, filtered,
-                         subpool));
+                         NULL, subpool));
 
   /* Remove all extra properties in TARGET. */
   SVN_ERR(remove_props_not_in_source(rb->to_session, revision,
@@ -1474,7 +1511,8 @@ do_synchronize(svn_ra_session_t *to_sess
           if (copying > last_merged)
             {
               SVN_ERR(copy_revprops(from_session, to_session, to_latest, TRUE,
-                                    baton->quiet, baton->source_prop_encoding,
+                                    baton->skip_unchanged, baton->quiet,
+                                    baton->source_prop_encoding,
                                     &normalized_rev_props_count, pool));
               last_merged = copying;
               last_merged_rev = svn_string_create
@@ -1645,7 +1683,8 @@ do_copy_revprops(svn_ra_session_t *to_se
     {
       int normalized_count;
       SVN_ERR(check_cancel(NULL));
-      SVN_ERR(copy_revprops(from_session, to_session, i, TRUE, baton->quiet,
+      SVN_ERR(copy_revprops(from_session, to_session, i, TRUE,
+                            baton->skip_unchanged, baton->quiet,
                             baton->source_prop_encoding, &normalized_count,
                             pool));
       normalized_rev_props_count += normalized_count;
@@ -2008,24 +2047,30 @@ sub_main(int *exit_code, int argc, const
             break;
 
           case svnsync_opt_trust_server_cert: /* backwards compat */
-          case svnsync_opt_trust_server_cert_unknown_ca:
-            opt_baton.trust_server_cert_unknown_ca = TRUE;
-            break;
-
-          case svnsync_opt_trust_server_cert_cn_mismatch:
-            opt_baton.trust_server_cert_cn_mismatch = TRUE;
-            break;
-
-          case svnsync_opt_trust_server_cert_expired:
-            opt_baton.trust_server_cert_expired = TRUE;
+            opt_baton.src_trust.trust_server_cert_unknown_ca = TRUE;
+            opt_baton.dst_trust.trust_server_cert_unknown_ca = TRUE;
             break;
 
-          case svnsync_opt_trust_server_cert_not_yet_valid:
-            opt_baton.trust_server_cert_not_yet_valid = TRUE;
+          case svnsync_opt_trust_server_cert_failures_src:
+            SVN_ERR(svn_utf_cstring_to_utf8(&opt_arg, opt_arg, pool));
+            SVN_ERR(svn_cmdline__parse_trust_options(
+                      &opt_baton.src_trust.trust_server_cert_unknown_ca,
+                      &opt_baton.src_trust.trust_server_cert_cn_mismatch,
+                      &opt_baton.src_trust.trust_server_cert_expired,
+                      &opt_baton.src_trust.trust_server_cert_not_yet_valid,
+                      &opt_baton.src_trust.trust_server_cert_other_failure,
+                      opt_arg, pool));
             break;
 
-          case svnsync_opt_trust_server_cert_other_failure:
-            opt_baton.trust_server_cert_other_failure = TRUE;
+          case svnsync_opt_trust_server_cert_failures_dst:
+            SVN_ERR(svn_utf_cstring_to_utf8(&opt_arg, opt_arg, pool));
+            SVN_ERR(svn_cmdline__parse_trust_options(
+                      &opt_baton.dst_trust.trust_server_cert_unknown_ca,
+                      &opt_baton.dst_trust.trust_server_cert_cn_mismatch,
+                      &opt_baton.dst_trust.trust_server_cert_expired,
+                      &opt_baton.dst_trust.trust_server_cert_not_yet_valid,
+                      &opt_baton.dst_trust.trust_server_cert_other_failure,
+                      opt_arg, pool));
             break;
 
           case svnsync_opt_no_auth_cache:
@@ -2073,7 +2118,8 @@ sub_main(int *exit_code, int argc, const
 
             SVN_ERR(svn_utf_cstring_to_utf8(&opt_arg, opt_arg, pool));
             SVN_ERR(svn_cmdline__parse_config_option(config_options,
-                                                     opt_arg, pool));
+                                                     opt_arg, "svnsync: ",
+                                                     pool));
             break;
 
           case svnsync_opt_source_prop_encoding:
@@ -2097,6 +2143,10 @@ sub_main(int *exit_code, int argc, const
             opt_baton.allow_non_empty = TRUE;
             break;
 
+          case svnsync_opt_skip_unchanged:
+            opt_baton.skip_unchanged = TRUE;
+            break;
+
           case 'q':
             opt_baton.quiet = TRUE;
             break;
@@ -2139,6 +2189,7 @@ sub_main(int *exit_code, int argc, const
                       apr_psprintf(pool,
                                    "config:miscellany:memory-cache-size=%s",
                                    opt_arg),
+                      NULL /* won't be used */,
                       pool));
             break;
 
@@ -2214,25 +2265,20 @@ sub_main(int *exit_code, int argc, const
   /* --trust-* can only be used with --non-interactive */
   if (!opt_baton.non_interactive)
     {
-      if (opt_baton.trust_server_cert_unknown_ca)
-        return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
-                                _("--trust-unknown-ca requires "
-                                  "--non-interactive"));
-      if (opt_baton.trust_server_cert_cn_mismatch)
-        return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
-                                _("--trust-cn-mismatch requires "
-                                  "--non-interactive"));
-      if (opt_baton.trust_server_cert_expired)
-        return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
-                                _("--trust-expired requires "
-                                  "--non-interactive"));
-      if (opt_baton.trust_server_cert_not_yet_valid)
-        return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
-                                _("--trust-not-yet-valid requires "
-                                  "--non-interactive"));
-      if (opt_baton.trust_server_cert_other_failure)
+      if (opt_baton.src_trust.trust_server_cert_unknown_ca
+          || opt_baton.src_trust.trust_server_cert_cn_mismatch
+          || opt_baton.src_trust.trust_server_cert_expired
+          || opt_baton.src_trust.trust_server_cert_not_yet_valid
+          || opt_baton.src_trust.trust_server_cert_other_failure
+          || opt_baton.dst_trust.trust_server_cert_unknown_ca
+          || opt_baton.dst_trust.trust_server_cert_cn_mismatch
+          || opt_baton.dst_trust.trust_server_cert_expired
+          || opt_baton.dst_trust.trust_server_cert_not_yet_valid
+          || opt_baton.dst_trust.trust_server_cert_other_failure)
         return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
-                                _("--trust-other-failure requires "
+                                _("--source-trust-server-cert-failures "
+                                  "and "
+                                  "--sync-trust-server-cert-failures require "
                                   "--non-interactive"));
     }
 
@@ -2352,11 +2398,11 @@ sub_main(int *exit_code, int argc, const
           opt_baton.source_password,
           opt_baton.config_dir,
           opt_baton.no_auth_cache,
-          opt_baton.trust_server_cert_unknown_ca,
-          opt_baton.trust_server_cert_cn_mismatch,
-          opt_baton.trust_server_cert_expired,
-          opt_baton.trust_server_cert_not_yet_valid,
-          opt_baton.trust_server_cert_other_failure,
+          opt_baton.src_trust.trust_server_cert_unknown_ca,
+          opt_baton.src_trust.trust_server_cert_cn_mismatch,
+          opt_baton.src_trust.trust_server_cert_expired,
+          opt_baton.src_trust.trust_server_cert_not_yet_valid,
+          opt_baton.src_trust.trust_server_cert_other_failure,
           config,
           check_cancel, NULL,
           pool);
@@ -2368,11 +2414,11 @@ sub_main(int *exit_code, int argc, const
             opt_baton.sync_password,
             opt_baton.config_dir,
             opt_baton.no_auth_cache,
-            opt_baton.trust_server_cert_unknown_ca,
-            opt_baton.trust_server_cert_cn_mismatch,
-            opt_baton.trust_server_cert_expired,
-            opt_baton.trust_server_cert_not_yet_valid,
-            opt_baton.trust_server_cert_other_failure,
+            opt_baton.dst_trust.trust_server_cert_unknown_ca,
+            opt_baton.dst_trust.trust_server_cert_cn_mismatch,
+            opt_baton.dst_trust.trust_server_cert_expired,
+            opt_baton.dst_trust.trust_server_cert_not_yet_valid,
+            opt_baton.dst_trust.trust_server_cert_other_failure,
             config,
             check_cancel, NULL,
             pool);