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 [27/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/libsvn_ra_serf/serf.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_ra_serf/serf.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_ra_serf/serf.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_ra_serf/serf.c Mon Nov 30 10:24:16 2015
@@ -64,7 +64,7 @@ ra_serf_version(void)
 
 #define RA_SERF_DESCRIPTION_VER \
     N_("Module for accessing a repository via WebDAV protocol using serf.\n" \
-       "  - using serf %d.%d.%d")
+       "  - using serf %d.%d.%d (compiled with %d.%d.%d)")
 
 /* Implements svn_ra__vtable_t.get_description(). */
 static const char *
@@ -73,7 +73,12 @@ ra_serf_get_description(apr_pool_t *pool
   int major, minor, patch;
 
   serf_lib_version(&major, &minor, &patch);
-  return apr_psprintf(pool, _(RA_SERF_DESCRIPTION_VER), major, minor, patch);
+  return apr_psprintf(pool, _(RA_SERF_DESCRIPTION_VER),
+                      major, minor, patch,
+                      SERF_MAJOR_VERSION,
+                      SERF_MINOR_VERSION,
+                      SERF_PATCH_VERSION
+                      );
 }
 
 /* Implements svn_ra__vtable_t.get_schemes(). */
@@ -148,7 +153,8 @@ load_http_auth_types(apr_pool_t *pool, s
 static svn_error_t *
 load_config(svn_ra_serf__session_t *session,
             apr_hash_t *config_hash,
-            apr_pool_t *pool)
+            apr_pool_t *result_pool,
+            apr_pool_t *scratch_pool)
 {
   svn_config_t *config, *config_client;
   const char *server_group;
@@ -180,17 +186,17 @@ load_config(svn_ra_serf__session_t *sess
   svn_config_get(config, &timeout_str, SVN_CONFIG_SECTION_GLOBAL,
                  SVN_CONFIG_OPTION_HTTP_TIMEOUT, NULL);
 
-  if (session->wc_callbacks->auth_baton)
+  if (session->auth_baton)
     {
       if (config_client)
         {
-          svn_auth_set_parameter(session->wc_callbacks->auth_baton,
+          svn_auth_set_parameter(session->auth_baton,
                                  SVN_AUTH_PARAM_CONFIG_CATEGORY_CONFIG,
                                  config_client);
         }
       if (config)
         {
-          svn_auth_set_parameter(session->wc_callbacks->auth_baton,
+          svn_auth_set_parameter(session->auth_baton,
                                  SVN_AUTH_PARAM_CONFIG_CATEGORY_SERVERS,
                                  config);
         }
@@ -202,7 +208,7 @@ load_config(svn_ra_serf__session_t *sess
                  SVN_CONFIG_OPTION_HTTP_PROXY_EXCEPTIONS, "");
   if (! svn_cstring_match_glob_list(session->session_url.hostname,
                                     svn_cstring_split(exceptions, ",",
-                                                      TRUE, pool)))
+                                                      TRUE, scratch_pool)))
     {
       svn_config_get(config, &proxy_host, SVN_CONFIG_SECTION_GLOBAL,
                      SVN_CONFIG_OPTION_HTTP_PROXY_HOST, NULL);
@@ -255,7 +261,7 @@ load_config(svn_ra_serf__session_t *sess
                                SERF_LOG_INFO));
 #endif
 
-  server_group = svn_auth_get_parameter(session->wc_callbacks->auth_baton,
+  server_group = svn_auth_get_parameter(session->auth_baton,
                                         SVN_AUTH_PARAM_SERVER_GROUP);
 
   if (server_group)
@@ -335,7 +341,7 @@ load_config(svn_ra_serf__session_t *sess
                                                  (apr_uint32_t)log_components,
                                                  SERF_LOG_DEFAULT_LAYOUT,
                                                  stderr,
-                                                 pool);
+                                                 result_pool);
 
       if (!status)
           serf_logging_add_output(session->context, output);
@@ -354,19 +360,16 @@ load_config(svn_ra_serf__session_t *sess
   session->timeout = apr_time_from_sec(DEFAULT_HTTP_TIMEOUT);
   if (timeout_str)
     {
-      char *endstr;
-      const long int timeout = strtol(timeout_str, &endstr, 10);
-
-      if (*endstr)
-        return svn_error_create(SVN_ERR_BAD_CONFIG_VALUE, NULL,
-                                _("Invalid config: illegal character in "
-                                  "timeout value"));
-      if (timeout < 0)
-        return svn_error_create(SVN_ERR_BAD_CONFIG_VALUE, NULL,
-                                _("Invalid config: negative timeout value"));
+      apr_int64_t timeout;
+      svn_error_t *err;
+      
+      err = svn_cstring_strtoi64(&timeout, timeout_str, 0, APR_INT64_MAX, 10);
+      if (err)
+        return svn_error_createf(SVN_ERR_BAD_CONFIG_VALUE, err,
+                                _("invalid config: bad value for '%s' option"),
+                                SVN_CONFIG_OPTION_HTTP_TIMEOUT);
       session->timeout = apr_time_from_sec(timeout);
     }
-  SVN_ERR_ASSERT(session->timeout >= 0);
 
   /* Convert the proxy port value, if any. */
   if (port_str)
@@ -433,7 +436,7 @@ load_config(svn_ra_serf__session_t *sess
     }
 
   /* Setup authentication. */
-  SVN_ERR(load_http_auth_types(pool, config, server_group,
+  SVN_ERR(load_http_auth_types(result_pool, config, server_group,
                                &session->authn_types));
   serf_config_authn_types(session->context, session->authn_types);
   serf_config_credentials_callback(session->context,
@@ -444,12 +447,13 @@ load_config(svn_ra_serf__session_t *sess
 #undef DEFAULT_HTTP_TIMEOUT
 
 static void
-svn_ra_serf__progress(void *progress_baton, apr_off_t read, apr_off_t written)
+svn_ra_serf__progress(void *progress_baton, apr_off_t bytes_read,
+                      apr_off_t bytes_written)
 {
   const svn_ra_serf__session_t *serf_sess = progress_baton;
   if (serf_sess->progress_func)
     {
-      serf_sess->progress_func(read + written, -1,
+      serf_sess->progress_func(bytes_read + bytes_written, -1,
                                serf_sess->progress_baton,
                                serf_sess->pool);
     }
@@ -474,27 +478,29 @@ svn_ra_serf__open(svn_ra_session_t *sess
                   const char *session_URL,
                   const svn_ra_callbacks2_t *callbacks,
                   void *callback_baton,
+                  svn_auth_baton_t *auth_baton,
                   apr_hash_t *config,
-                  apr_pool_t *pool)
+                  apr_pool_t *result_pool,
+                  apr_pool_t *scratch_pool)
 {
   apr_status_t status;
   svn_ra_serf__session_t *serf_sess;
   apr_uri_t url;
   const char *client_string = NULL;
   svn_error_t *err;
-  apr_pool_t *subpool;
 
   if (corrected_url)
     *corrected_url = NULL;
 
-  serf_sess = apr_pcalloc(pool, sizeof(*serf_sess));
-  serf_sess->pool = svn_pool_create(pool);
+  serf_sess = apr_pcalloc(result_pool, sizeof(*serf_sess));
+  serf_sess->pool = result_pool;
   if (config)
-    SVN_ERR(svn_config_copy_config(&serf_sess->config, config, pool));
+    SVN_ERR(svn_config_copy_config(&serf_sess->config, config, result_pool));
   else
     serf_sess->config = NULL;
   serf_sess->wc_callbacks = callbacks;
   serf_sess->wc_callback_baton = callback_baton;
+  serf_sess->auth_baton = auth_baton;
   serf_sess->progress_func = callbacks->progress_func;
   serf_sess->progress_baton = callbacks->progress_baton;
   serf_sess->cancel_func = callbacks->cancel_func;
@@ -507,19 +513,8 @@ svn_ra_serf__open(svn_ra_session_t *sess
                                        serf_sess->pool));
 
 
-  status = apr_uri_parse(serf_sess->pool, session_URL, &url);
-  if (status)
-    {
-      return svn_error_createf(SVN_ERR_RA_ILLEGAL_URL, NULL,
-                               _("Illegal URL '%s'"),
-                               session_URL);
-    }
-  /* Depending the version of apr-util in use, for root paths url.path
-     will be NULL or "", where serf requires "/". */
-  if (url.path == NULL || url.path[0] == '\0')
-    {
-      url.path = apr_pstrdup(serf_sess->pool, "/");
-    }
+  SVN_ERR(svn_ra_serf__uri_parse(&url, session_URL, serf_sess->pool));
+
   if (!url.port)
     {
       url.port = apr_uri_port_of_scheme(url.scheme);
@@ -535,12 +530,13 @@ svn_ra_serf__open(svn_ra_session_t *sess
   /* We have to assume that the server only supports HTTP/1.0. Once it's clear
      HTTP/1.1 is supported, we can upgrade. */
   serf_sess->http10 = TRUE;
+  serf_sess->http20 = FALSE;
 
   /* If we switch to HTTP/1.1, then we will use chunked requests. We may disable
      this, if we find an intervening proxy does not support chunked requests.  */
   serf_sess->using_chunked_requests = TRUE;
 
-  SVN_ERR(load_config(serf_sess, config, serf_sess->pool));
+  SVN_ERR(load_config(serf_sess, config, serf_sess->pool, scratch_pool));
 
   serf_sess->conns[0] = apr_pcalloc(serf_sess->pool,
                                     sizeof(*serf_sess->conns[0]));
@@ -551,13 +547,16 @@ svn_ra_serf__open(svn_ra_session_t *sess
 
   /* create the user agent string */
   if (callbacks->get_client_string)
-    SVN_ERR(callbacks->get_client_string(callback_baton, &client_string, pool));
+    SVN_ERR(callbacks->get_client_string(callback_baton, &client_string,
+                                         scratch_pool));
 
   if (client_string)
-    serf_sess->useragent = apr_pstrcat(pool, get_user_agent_string(pool), " ",
+    serf_sess->useragent = apr_pstrcat(result_pool,
+                                       get_user_agent_string(scratch_pool),
+                                       " ",
                                        client_string, SVN_VA_NULL);
   else
-    serf_sess->useragent = get_user_agent_string(pool);
+    serf_sess->useragent = get_user_agent_string(result_pool);
 
   /* go ahead and tell serf about the connection. */
   status =
@@ -578,24 +577,29 @@ svn_ra_serf__open(svn_ra_session_t *sess
 
   session->priv = serf_sess;
 
-  /* This subpool not only avoids having a lot of temporary state in the long
-     living session pool, but it also works around a bug in serf
-     <= r2319 / 1.3.4 where serf doesn't report the request as failed/cancelled
-     when the authorization request handler fails to handle the request.
-
-     In this specific case the serf connection is cleaned up by the pool
-     handlers before our handler is cleaned up (via subpools). Using a
-     subpool here cleans up our handler before the connection is cleaned. */
-  subpool = svn_pool_create(pool);
+  /* The following code explicitly works around a bug in serf <= r2319 / 1.3.8
+     where serf doesn't report the request as failed/cancelled when the
+     authorization request handler fails to handle the request.
+
+     As long as we allocate the request in a subpool of the serf connection
+     pool, we know that the handler is always cleaned before the connection.
+
+     Luckily our caller now passes us two pools which handle this case.
+   */
+#if defined(SVN_DEBUG) && !SERF_VERSION_AT_LEAST(1,4,0)
+  /* Currently ensured by svn_ra_open4().
+     If failing causes segfault in basic_tests.py 48, "basic auth test" */
+  SVN_ERR_ASSERT((serf_sess->pool != scratch_pool)
+                 && apr_pool_is_ancestor(serf_sess->pool, scratch_pool));
+#endif
 
   err = svn_ra_serf__exchange_capabilities(serf_sess, corrected_url,
-                                           pool, subpool);
+                                           result_pool, scratch_pool);
 
   /* serf should produce a usable error code instead of APR_EGENERAL */
   if (err && err->apr_err == APR_EGENERAL)
     err = svn_error_createf(SVN_ERR_RA_DAV_REQUEST_FAILED, err,
                             _("Connection to '%s' failed"), session_URL);
-  svn_pool_clear(subpool);
   SVN_ERR(err);
 
   /* We have set up a useful connection (that doesn't indication a redirect).
@@ -604,9 +608,7 @@ svn_ra_serf__open(svn_ra_session_t *sess
      problems in any proxy.  */
   if ((corrected_url == NULL || *corrected_url == NULL)
       && serf_sess->detect_chunking && !serf_sess->http10)
-    SVN_ERR(svn_ra_serf__probe_proxy(serf_sess, subpool));
-
-  svn_pool_destroy(subpool);
+    SVN_ERR(svn_ra_serf__probe_proxy(serf_sess, scratch_pool));
 
   return SVN_NO_ERROR;
 }
@@ -635,6 +637,7 @@ ra_serf_dup_session(svn_ra_session_t *ne
   /* using_ssl */
   /* using_compression */
   /* http10 */
+  /* http20 */
   /* using_chunked_requests */
   /* detect_chunking */
 
@@ -733,25 +736,24 @@ ra_serf_dup_session(svn_ra_session_t *ne
 
   new_sess->repos_root_str = apr_pstrdup(result_pool,
                                          new_sess->repos_root_str);
-  status = apr_uri_parse(result_pool, new_sess->repos_root_str,
-                         &new_sess->repos_root);
-  if (status)
-    return svn_ra_serf__wrap_err(status, NULL);
+  SVN_ERR(svn_ra_serf__uri_parse(&new_sess->repos_root,
+                                 new_sess->repos_root_str,
+                                 result_pool));
 
   new_sess->session_url_str = apr_pstrdup(result_pool, new_session_url);
 
-  status = apr_uri_parse(result_pool, new_sess->session_url_str,
-                         &new_sess->session_url);
-
-  if (status)
-    return svn_ra_serf__wrap_err(status, NULL);
+  SVN_ERR(svn_ra_serf__uri_parse(&new_sess->session_url,
+                                 new_sess->session_url_str,
+                                 result_pool));
 
   /* svn_boolean_t supports_inline_props */
   /* supports_rev_rsrc_replay */
+  /* supports_svndiff1 */
 
   new_sess->context = serf_context_create(result_pool);
 
-  SVN_ERR(load_config(new_sess, old_sess->config, result_pool));
+  SVN_ERR(load_config(new_sess, old_sess->config,
+                      result_pool, scratch_pool));
 
   new_sess->conns[0] = apr_pcalloc(result_pool,
                                    sizeof(*new_sess->conns[0]));
@@ -791,7 +793,6 @@ svn_ra_serf__reparent(svn_ra_session_t *
 {
   svn_ra_serf__session_t *session = ra_session->priv;
   apr_uri_t new_url;
-  apr_status_t status;
 
   /* If it's the URL we already have, wave our hands and do nothing. */
   if (strcmp(session->session_url_str, url) == 0)
@@ -813,25 +814,11 @@ svn_ra_serf__reparent(svn_ra_session_t *
             "URL '%s'"), url, session->repos_root_str);
     }
 
-  status = apr_uri_parse(pool, url, &new_url);
-  if (status)
-    {
-      return svn_error_createf(SVN_ERR_RA_ILLEGAL_URL, NULL,
-                               _("Illegal repository URL '%s'"), url);
-    }
+  SVN_ERR(svn_ra_serf__uri_parse(&new_url, url, pool));
 
-  /* Depending the version of apr-util in use, for root paths url.path
-     will be NULL or "", where serf requires "/". */
   /* ### Maybe we should use a string buffer for these strings so we
      ### don't allocate memory in the session on every reparent? */
-  if (new_url.path == NULL || new_url.path[0] == '\0')
-    {
-      session->session_url.path = apr_pstrdup(session->pool, "/");
-    }
-  else
-    {
-      session->session_url.path = apr_pstrdup(session->pool, new_url.path);
-    }
+  session->session_url.path = apr_pstrdup(session->pool, new_url.path);
   session->session_url_str = apr_pstrdup(session->pool, url);
 
   return SVN_NO_ERROR;

Modified: subversion/branches/ra-git/subversion/libsvn_ra_serf/stat.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_ra_serf/stat.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_ra_serf/stat.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_ra_serf/stat.c Mon Nov 30 10:24:16 2015
@@ -193,6 +193,9 @@ fill_dirent_propfunc(void *baton,
         {
           if (*val->data)
             {
+              /* Note: 1.8.x and earlier servers send the count proper; 1.9.0
+               * and newer send "1" if there are properties and "0" otherwise.
+               */
               apr_int64_t deadprop_count;
               SVN_ERR(svn_cstring_atoi64(&deadprop_count, val->data));
               fdb->entry->has_props = deadprop_count > 0;
@@ -472,6 +475,7 @@ svn_ra_serf__get_dir(svn_ra_session_t *r
   svn_ra_serf__handler_t *props_handler = NULL;
   const char *path;
   struct get_dir_baton_t gdb;
+  svn_error_t *err = SVN_NO_ERROR;
 
   gdb.result_pool = result_pool;
   gdb.is_directory = FALSE;
@@ -542,10 +546,17 @@ svn_ra_serf__get_dir(svn_ra_session_t *r
 
   if (dirent_handler)
     {
-      SVN_ERR(svn_ra_serf__context_run_wait(&dirent_handler->done,
+      err = svn_error_trace(
+              svn_ra_serf__context_run_wait(&dirent_handler->done,
                                             session,
                                             scratch_pool));
 
+      if (err)
+        {
+          svn_pool_clear(scratch_pool); /* Unregisters outstanding requests */
+          return err;
+        }
+
       if (gdb.supports_deadprop_count == svn_tristate_false
           && session->supports_deadprop_count == svn_tristate_unknown
           && dirent_fields & SVN_DIRENT_HAS_PROPS)
@@ -571,23 +582,27 @@ svn_ra_serf__get_dir(svn_ra_session_t *r
 
   if (props_handler)
     {
-      SVN_ERR(svn_ra_serf__context_run_wait(&props_handler->done,
+      err = svn_error_trace(
+              svn_ra_serf__context_run_wait(&props_handler->done,
                                             session,
                                             scratch_pool));
     }
 
   /* And dirent again for the case when we had to send the request again */
-  if (dirent_handler)
+  if (! err && dirent_handler)
     {
-      SVN_ERR(svn_ra_serf__context_run_wait(&dirent_handler->done,
+      err = svn_error_trace(
+              svn_ra_serf__context_run_wait(&dirent_handler->done,
                                             session,
                                             scratch_pool));
     }
 
-  if (gdb.supports_deadprop_count != svn_tristate_unknown)
+  if (!err && gdb.supports_deadprop_count != svn_tristate_unknown)
     session->supports_deadprop_count = gdb.supports_deadprop_count;
 
-  svn_pool_destroy(scratch_pool);
+  svn_pool_destroy(scratch_pool); /* Unregisters outstanding requests */
+
+  SVN_ERR(err);
 
   if (!gdb.is_directory)
     return svn_error_create(SVN_ERR_FS_NOT_DIRECTORY, NULL,

Modified: subversion/branches/ra-git/subversion/libsvn_ra_serf/update.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_ra_serf/update.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_ra_serf/update.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_ra_serf/update.c Mon Nov 30 10:24:16 2015
@@ -941,8 +941,17 @@ headers_fetch(serf_bucket_t *headers,
     {
       serf_bucket_headers_setn(headers, SVN_DAV_DELTA_BASE_HEADER,
                                fetch_ctx->delta_base);
-      serf_bucket_headers_setn(headers, "Accept-Encoding",
-                               "svndiff1;q=0.9,svndiff;q=0.8");
+      if (fetch_ctx->using_compression)
+        {
+          serf_bucket_headers_setn(headers, "Accept-Encoding",
+                                   "svndiff1;q=0.9,svndiff;q=0.8");
+        }
+      else
+        {
+          /* Do not advertise svndiff1 support if we're not interested in
+             compression. */
+          serf_bucket_headers_setn(headers, "Accept-Encoding", "svndiff");
+        }
     }
   else if (fetch_ctx->using_compression)
     {
@@ -1129,7 +1138,15 @@ handle_fetch(serf_request_t *request,
           /* Validate the delta base claimed by the server matches
              what we asked for! */
           val = serf_bucket_headers_get(hdrs, SVN_DAV_DELTA_BASE_HEADER);
-          if (val && (strcmp(val, fetch_ctx->delta_base) != 0))
+          if (val && fetch_ctx->delta_base == NULL)
+            {
+              /* We recieved response with delta base header while we didn't
+                 requested it -- report it as error. */
+              return svn_error_createf(SVN_ERR_RA_DAV_REQUEST_FAILED, NULL,
+                                       _("GET request returned unexpected "
+                                         "delta base: %s"), val);
+            }
+          else if (val && (strcmp(val, fetch_ctx->delta_base) != 0))
             {
               return svn_error_createf(SVN_ERR_RA_DAV_REQUEST_FAILED, NULL,
                                        _("GET request returned unexpected "
@@ -2343,8 +2360,9 @@ setup_update_report_headers(serf_bucket_
     }
   else
     {
-      serf_bucket_headers_setn(headers, "Accept-Encoding",
-                               "svndiff1;q=0.9,svndiff;q=0.8");
+      /* Do not advertise svndiff1 support if we're not interested in
+         compression. */
+      serf_bucket_headers_setn(headers, "Accept-Encoding", "svndiff");
     }
 
   return SVN_NO_ERROR;
@@ -2759,7 +2777,7 @@ make_update_reporter(svn_ra_session_t *r
                                             update_editor,
                                             update_baton,
                                             depth, has_target,
-                                            sess->pool));
+                                            result_pool));
       update_editor = filter_editor;
       update_baton = filter_baton;
     }

Modified: subversion/branches/ra-git/subversion/libsvn_ra_serf/util.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_ra_serf/util.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_ra_serf/util.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_ra_serf/util.c Mon Nov 30 10:24:16 2015
@@ -65,7 +65,9 @@ ssl_convert_serf_failures(int failures)
   apr_uint32_t svn_failures = 0;
   apr_size_t i;
 
-  for (i = 0; i < sizeof(serf_failure_map) / (2 * sizeof(apr_uint32_t)); ++i)
+  for (i = 0;
+       i < sizeof(serf_failure_map) / (sizeof(serf_failure_map[0]));
+       ++i)
     {
       if (failures & serf_failure_map[i][0])
         {
@@ -313,11 +315,11 @@ ssl_server_cert(void *baton, int failure
     {
       svn_error_t *err;
 
-      svn_auth_set_parameter(conn->session->wc_callbacks->auth_baton,
+      svn_auth_set_parameter(conn->session->auth_baton,
                              SVN_AUTH_PARAM_SSL_SERVER_CERT_INFO,
                              &cert_info);
 
-      svn_auth_set_parameter(conn->session->wc_callbacks->auth_baton,
+      svn_auth_set_parameter(conn->session->auth_baton,
                              SVN_AUTH_PARAM_SSL_SERVER_FAILURES,
                              &svn_failures);
 
@@ -327,13 +329,13 @@ ssl_server_cert(void *baton, int failure
       err = svn_auth_first_credentials(&creds, &state,
                                        SVN_AUTH_CRED_SSL_SERVER_AUTHORITY,
                                        realmstring,
-                                       conn->session->wc_callbacks->auth_baton,
+                                       conn->session->auth_baton,
                                        scratch_pool);
 
-      svn_auth_set_parameter(conn->session->wc_callbacks->auth_baton,
+      svn_auth_set_parameter(conn->session->auth_baton,
                              SVN_AUTH_PARAM_SSL_SERVER_CERT_INFO, NULL);
 
-      svn_auth_set_parameter(conn->session->wc_callbacks->auth_baton,
+      svn_auth_set_parameter(conn->session->auth_baton,
                              SVN_AUTH_PARAM_SSL_SERVER_FAILURES, NULL);
 
       if (err)
@@ -360,11 +362,11 @@ ssl_server_cert(void *baton, int failure
       return APR_SUCCESS;
     }
 
-  svn_auth_set_parameter(conn->session->wc_callbacks->auth_baton,
+  svn_auth_set_parameter(conn->session->auth_baton,
                          SVN_AUTH_PARAM_SSL_SERVER_FAILURES,
                          &svn_failures);
 
-  svn_auth_set_parameter(conn->session->wc_callbacks->auth_baton,
+  svn_auth_set_parameter(conn->session->auth_baton,
                          SVN_AUTH_PARAM_SSL_SERVER_CERT_INFO,
                          &cert_info);
 
@@ -373,7 +375,7 @@ ssl_server_cert(void *baton, int failure
   SVN_ERR(svn_auth_first_credentials(&creds, &state,
                                      SVN_AUTH_CRED_SSL_SERVER_TRUST,
                                      realmstring,
-                                     conn->session->wc_callbacks->auth_baton,
+                                     conn->session->auth_baton,
                                      scratch_pool));
   if (creds)
     {
@@ -394,7 +396,7 @@ ssl_server_cert(void *baton, int failure
         }
     }
 
-  svn_auth_set_parameter(conn->session->wc_callbacks->auth_baton,
+  svn_auth_set_parameter(conn->session->auth_baton,
                          SVN_AUTH_PARAM_SSL_SERVER_CERT_INFO, NULL);
 
   /* Are there non accepted failures left? */
@@ -478,6 +480,38 @@ load_authorities(svn_ra_serf__connection
   return SVN_NO_ERROR;
 }
 
+#if SERF_VERSION_AT_LEAST(1, 4, 0) && defined(SVN__SERF_TEST_HTTP2)
+/* Implements serf_ssl_protocol_result_cb_t */
+static apr_status_t
+conn_negotiate_protocol(void *data,
+                        const char *protocol)
+{
+  svn_ra_serf__connection_t *conn = data;
+
+  if (!strcmp(protocol, "h2"))
+    {
+      serf_connection_set_framing_type(
+            conn->conn,
+            SERF_CONNECTION_FRAMING_TYPE_HTTP2);
+
+      /* Disable generating content-length headers. */
+      conn->session->http10 = FALSE;
+      conn->session->http20 = TRUE;
+      conn->session->using_chunked_requests = TRUE;
+      conn->session->detect_chunking = FALSE;
+    }
+  else
+    {
+      /* protocol should be "" or "http/1.1" */
+      serf_connection_set_framing_type(
+            conn->conn,
+            SERF_CONNECTION_FRAMING_TYPE_HTTP1);
+    }
+
+  return APR_SUCCESS;
+}
+#endif
+
 static svn_error_t *
 conn_setup(apr_socket_t *sock,
            serf_bucket_t **read_bkt,
@@ -523,6 +557,16 @@ conn_setup(apr_socket_t *sock,
               SVN_ERR(load_authorities(conn, conn->session->ssl_authorities,
                                        conn->session->pool));
             }
+#if SERF_VERSION_AT_LEAST(1, 4, 0) && defined(SVN__SERF_TEST_HTTP2)
+          if (APR_SUCCESS ==
+                serf_ssl_negotiate_protocol(conn->ssl_context, "h2,http/1.1",
+                                            conn_negotiate_protocol, conn))
+            {
+                serf_connection_set_framing_type(
+                            conn->conn,
+                            SERF_CONNECTION_FRAMING_TYPE_NONE);
+            }
+#endif
         }
 
       if (write_bkt)
@@ -648,7 +692,7 @@ handle_client_cert(void *data,
                                            &conn->ssl_client_auth_state,
                                            SVN_AUTH_CRED_SSL_CLIENT_CERT,
                                            realm,
-                                           session->wc_callbacks->auth_baton,
+                                           session->auth_baton,
                                            pool));
       }
     else
@@ -700,7 +744,7 @@ handle_client_cert_pw(void *data,
                                            &conn->ssl_client_pw_auth_state,
                                            SVN_AUTH_CRED_SSL_CLIENT_CERT_PW,
                                            cert_path,
-                                           session->wc_callbacks->auth_baton,
+                                           session->auth_baton,
                                            pool));
       }
     else
@@ -947,6 +991,22 @@ svn_ra_serf__context_run_wait(svn_boolea
   return SVN_NO_ERROR;
 }
 
+/* Ensure that a handler is no longer scheduled on the connection.
+
+   Eventually serf will have a reliable way to cancel existing requests,
+   but currently it doesn't even have a way to relyable identify a request
+   after rescheduling, for auth reasons.
+
+   So the only thing we can do today is reset the connection, which
+   will cancel all outstanding requests and prepare the connection
+   for re-use.
+*/
+void
+svn_ra_serf__unschedule_handler(svn_ra_serf__handler_t *handler)
+{
+  serf_connection_reset(handler->conn->conn);
+  handler->scheduled = FALSE;
+}
 
 svn_error_t *
 svn_ra_serf__context_run_one(svn_ra_serf__handler_t *handler,
@@ -960,6 +1020,15 @@ svn_ra_serf__context_run_one(svn_ra_serf
   /* Wait until the response logic marks its DONE status.  */
   err = svn_ra_serf__context_run_wait(&handler->done, handler->session,
                                       scratch_pool);
+
+  if (handler->scheduled)
+    {
+      /* We reset the connection (breaking  pipelining, etc.), as
+         if we didn't the next data would still be handled by this handler,
+         which is done as far as our caller is concerned. */
+      svn_ra_serf__unschedule_handler(handler);
+    }
+
   return svn_error_trace(err);
 }
 
@@ -1082,7 +1151,9 @@ svn_ra_serf__expect_empty_body(serf_requ
 
   hdrs = serf_bucket_response_get_headers(response);
   val = serf_bucket_headers_get(hdrs, "Content-Type");
-  if (val && strncasecmp(val, "text/xml", sizeof("text/xml") - 1) == 0)
+  if (val
+      && (handler->sline.code < 200 || handler->sline.code >= 300)
+      && strncasecmp(val, "text/xml", sizeof("text/xml") - 1) == 0)
     {
       svn_ra_serf__server_error_t *server_err;
 
@@ -1095,7 +1166,7 @@ svn_ra_serf__expect_empty_body(serf_requ
     }
   else
     {
-      /* The body was not text/xml, so we don't know what to do with it.
+      /* The body was not text/xml, or we got a success code.
          Toss anything that arrives.  */
       handler->discard_body = TRUE;
     }
@@ -1132,7 +1203,7 @@ svn_ra_serf__credentials_callback(char *
                                            &session->auth_state,
                                            SVN_AUTH_CRED_SIMPLE,
                                            realm,
-                                           session->wc_callbacks->auth_baton,
+                                           session->auth_baton,
                                            session->pool);
         }
       else
@@ -1266,6 +1337,10 @@ handle_response(serf_request_t *request,
       /* HTTP/1.1? (or later)  */
       if (sl.version != SERF_HTTP_10)
         handler->session->http10 = FALSE;
+
+      if (sl.version >= SERF_HTTP_VERSION(2, 0)) {
+        handler->session->http20 = TRUE;
+      }
     }
 
   /* Keep reading from the network until we've read all the headers.  */
@@ -1453,7 +1528,13 @@ handle_response_cb(serf_request_t *reque
     {
       handler->discard_body = TRUE; /* Discard further data */
       handler->done = TRUE; /* Mark as done */
-      handler->scheduled = FALSE;
+      /* handler->scheduled is still TRUE, as we still expect data.
+         If we would return an error outer-status the connection
+         would have to be restarted. With scheduled still TRUE
+         destroying the handler's pool will still reset the
+         connection, avoiding the posibility of returning
+         an error for this handler when a new request is
+         scheduled. */
       outer_status = APR_EAGAIN; /* Exit context loop */
     }
 
@@ -1762,8 +1843,9 @@ svn_ra_serf__error_on_status(serf_status
         return svn_error_createf(SVN_ERR_FS_NOT_FOUND, NULL,
                                  _("'%s' path not found"), path);
       case 405:
-        return svn_error_createf(SVN_ERR_FS_OUT_OF_DATE, NULL,
-                                 _("'%s' is out of date"), path);
+        return svn_error_createf(SVN_ERR_RA_DAV_METHOD_NOT_ALLOWED, NULL,
+                                 _("HTTP method is not allowed on '%s'"),
+                                 path);
       case 409:
         return svn_error_createf(SVN_ERR_FS_CONFLICT, NULL,
                                  _("'%s' conflicts"), path);
@@ -1802,9 +1884,10 @@ svn_error_t *
 svn_ra_serf__unexpected_status(svn_ra_serf__handler_t *handler)
 {
   /* Is it a standard error status? */
-  SVN_ERR(svn_ra_serf__error_on_status(handler->sline,
-                                       handler->path,
-                                       handler->location));
+  if (handler->sline.code != 405)
+    SVN_ERR(svn_ra_serf__error_on_status(handler->sline,
+                                         handler->path,
+                                         handler->location));
 
   switch (handler->sline.code)
     {
@@ -1817,6 +1900,11 @@ svn_ra_serf__unexpected_status(svn_ra_se
                                  _("Path '%s' already exists"),
                                  handler->path);
 
+      case 405:
+        return svn_error_createf(SVN_ERR_RA_DAV_METHOD_NOT_ALLOWED, NULL,
+                                 _("The HTTP method '%s' is not allowed"
+                                   " on '%s'"),
+                                 handler->method, handler->path);
       default:
         return svn_error_createf(SVN_ERR_RA_DAV_REQUEST_FAILED, NULL,
                                  _("Unexpected HTTP status %d '%s' on '%s' "
@@ -1874,14 +1962,14 @@ response_done(serf_request_t *request,
    handlers registered in no freed memory.
 
    This fallback kills the connection for this case, which will make serf
-   unregister any*/
+   unregister any outstanding requests on it. */
 static apr_status_t
 handler_cleanup(void *baton)
 {
   svn_ra_serf__handler_t *handler = baton;
-  if (handler->scheduled && handler->conn && handler->conn->conn)
+  if (handler->scheduled)
     {
-      serf_connection_reset(handler->conn->conn);
+      svn_ra_serf__unschedule_handler(handler);
     }
 
   return APR_SUCCESS;
@@ -1909,3 +1997,29 @@ svn_ra_serf__create_handler(svn_ra_serf_
   return handler;
 }
 
+svn_error_t *
+svn_ra_serf__uri_parse(apr_uri_t *uri,
+                       const char *url_str,
+                       apr_pool_t *result_pool)
+{
+  apr_status_t status;
+
+  status = apr_uri_parse(result_pool, url_str, uri);
+  if (status)
+    {
+      /* Do not use returned error status in error message because currently
+         apr_uri_parse() returns APR_EGENERAL for all parsing errors. */
+      return svn_error_createf(SVN_ERR_RA_ILLEGAL_URL, NULL,
+                               _("Illegal URL '%s'"),
+                               url_str);
+    }
+
+  /* Depending the version of apr-util in use, for root paths uri.path
+     will be NULL or "", where serf requires "/". */
+  if (uri->path == NULL || uri->path[0] == '\0')
+    {
+      uri->path = apr_pstrdup(result_pool, "/");
+    }
+
+  return SVN_NO_ERROR;
+}

Modified: subversion/branches/ra-git/subversion/libsvn_ra_svn/client.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_ra_svn/client.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_ra_svn/client.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_ra_svn/client.c Mon Nov 30 10:24:16 2015
@@ -50,6 +50,7 @@
 #include "svn_private_config.h"
 
 #include "private/svn_fspath.h"
+#include "private/svn_string_private.h"
 #include "private/svn_subr_private.h"
 
 #include "../libsvn_ra/ra_loader.h"
@@ -187,7 +188,7 @@ static svn_error_t *make_connection(cons
 
 /* Set *DIFFS to an array of svn_prop_t, allocated in POOL, based on the
    property diffs in LIST, received from the server. */
-static svn_error_t *parse_prop_diffs(const apr_array_header_t *list,
+static svn_error_t *parse_prop_diffs(const svn_ra_svn__list_t *list,
                                      apr_pool_t *pool,
                                      apr_array_header_t **diffs)
 {
@@ -198,26 +199,27 @@ static svn_error_t *parse_prop_diffs(con
   for (i = 0; i < list->nelts; i++)
     {
       svn_prop_t *prop;
-      svn_ra_svn_item_t *elt = &APR_ARRAY_IDX(list, i, svn_ra_svn_item_t);
+      svn_ra_svn__item_t *elt = &SVN_RA_SVN__LIST_ITEM(list, i);
 
       if (elt->kind != SVN_RA_SVN_LIST)
         return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
                                 _("Prop diffs element not a list"));
       prop = apr_array_push(*diffs);
-      SVN_ERR(svn_ra_svn__parse_tuple(elt->u.list, pool, "c(?s)", &prop->name,
-                                      &prop->value));
+      SVN_ERR(svn_ra_svn__parse_tuple(&elt->u.list, "c(?s)",
+                                      &prop->name, &prop->value));
     }
   return SVN_NO_ERROR;
 }
 
 /* Parse a lockdesc, provided in LIST as specified by the protocol into
    LOCK, allocated in POOL. */
-static svn_error_t *parse_lock(const apr_array_header_t *list, apr_pool_t *pool,
+static svn_error_t *parse_lock(const svn_ra_svn__list_t *list,
+                               apr_pool_t *pool,
                                svn_lock_t **lock)
 {
   const char *cdate, *edate;
   *lock = svn_lock_create(pool);
-  SVN_ERR(svn_ra_svn__parse_tuple(list, pool, "ccc(?c)c(?c)", &(*lock)->path,
+  SVN_ERR(svn_ra_svn__parse_tuple(list, "ccc(?c)c(?c)", &(*lock)->path,
                                   &(*lock)->token, &(*lock)->owner,
                                   &(*lock)->comment, &cdate, &edate));
   (*lock)->path = svn_fspath__canonicalize((*lock)->path, pool);
@@ -240,7 +242,7 @@ static svn_error_t *handle_auth_request(
                                         apr_pool_t *pool)
 {
   svn_ra_svn_conn_t *conn = sess->conn;
-  apr_array_header_t *mechlist;
+  svn_ra_svn__list_t *mechlist;
   const char *realm;
 
   SVN_ERR(svn_ra_svn__read_cmd_response(conn, pool, "lc", &mechlist, &realm));
@@ -469,9 +471,9 @@ static void handle_child_process_error(a
   in_stream = svn_stream_from_aprfile2(in_file, FALSE, pool);
   out_stream = svn_stream_from_aprfile2(out_file, FALSE, pool);
 
-  conn = svn_ra_svn_create_conn4(NULL, in_stream, out_stream,
+  conn = svn_ra_svn_create_conn5(NULL, in_stream, out_stream,
                                  SVN_DELTA_COMPRESSION_LEVEL_DEFAULT, 0,
-                                 0, pool);
+                                 0, 0, 0, pool);
   err = svn_error_wrap_apr(status, _("Error in child process: %s"), desc);
   svn_error_clear(svn_ra_svn__write_cmd_failure(conn, pool, err));
   svn_error_clear(err);
@@ -540,13 +542,13 @@ static svn_error_t *make_tunnel(const ch
   apr_file_inherit_unset(proc->out);
 
   /* Guard against dotfile output to stdout on the server. */
-  *conn = svn_ra_svn_create_conn4(NULL,
+  *conn = svn_ra_svn_create_conn5(NULL,
                                   svn_stream_from_aprfile2(proc->out, FALSE,
                                                            pool),
                                   svn_stream_from_aprfile2(proc->in, FALSE,
                                                            pool),
                                   SVN_DELTA_COMPRESSION_LEVEL_DEFAULT,
-                                  0, 0, pool);
+                                  0, 0, 0, 0, pool);
   err = svn_ra_svn__skip_leading_garbage(*conn, pool);
   if (err)
     return svn_error_quick_wrap(
@@ -616,14 +618,17 @@ static svn_error_t *open_session(svn_ra_
                                  apr_hash_t *config,
                                  const svn_ra_callbacks2_t *callbacks,
                                  void *callbacks_baton,
-                                 apr_pool_t *pool)
+                                 svn_auth_baton_t *auth_baton,
+                                 apr_pool_t *result_pool,
+                                 apr_pool_t *scratch_pool)
 {
   svn_ra_svn__session_baton_t *sess;
   svn_ra_svn_conn_t *conn;
   apr_socket_t *sock;
   apr_uint64_t minver, maxver;
-  apr_array_header_t *mechlist, *server_caplist, *repos_caplist;
+  svn_ra_svn__list_t *mechlist, *server_caplist, *repos_caplist;
   const char *client_string = NULL;
+  apr_pool_t *pool = result_pool;
 
   sess = apr_palloc(pool, sizeof(*sess));
   sess->pool = pool;
@@ -636,6 +641,7 @@ static svn_error_t *open_session(svn_ra_
   sess->callbacks = callbacks;
   sess->callbacks_baton = callbacks_baton;
   sess->bytes_read = sess->bytes_written = 0;
+  sess->auth_baton = auth_baton;
 
   if (config)
     SVN_ERR(svn_config_copy_config(&sess->config, config, pool));
@@ -668,9 +674,9 @@ static svn_error_t *open_session(svn_ra_
           apr_pool_cleanup_register(pool, td, close_tunnel_cleanup,
                                     apr_pool_cleanup_null);
 
-          conn = svn_ra_svn_create_conn4(NULL, td->response, td->request,
+          conn = svn_ra_svn_create_conn5(NULL, td->response, td->request,
                                          SVN_DELTA_COMPRESSION_LEVEL_DEFAULT,
-                                         0, 0, pool);
+                                         0, 0, 0, 0, pool);
           SVN_ERR(svn_ra_svn__skip_leading_garbage(conn, pool));
         }
     }
@@ -682,9 +688,9 @@ static svn_error_t *open_session(svn_ra_
       SVN_ERR(make_connection(uri->hostname,
                               uri->port ? uri->port : SVN_RA_SVN_PORT,
                               &sock, pool));
-      conn = svn_ra_svn_create_conn4(sock, NULL, NULL,
+      conn = svn_ra_svn_create_conn5(sock, NULL, NULL,
                                      SVN_DELTA_COMPRESSION_LEVEL_DEFAULT,
-                                     0, 0, pool);
+                                     0, 0, 0, 0, pool);
     }
 
   /* Build the useragent string, querying the client for any
@@ -722,7 +728,7 @@ static svn_error_t *open_session(svn_ra_
     return svn_error_createf(SVN_ERR_RA_SVN_BAD_VERSION, NULL,
                              _("Server only supports versions up to %d"),
                              (int) maxver);
-  SVN_ERR(svn_ra_svn_set_capabilities(conn, server_caplist));
+  SVN_ERR(svn_ra_svn__set_capabilities(conn, server_caplist));
 
   /* All released versions of Subversion support edit-pipeline,
    * so we do not support servers that do not. */
@@ -755,7 +761,7 @@ static svn_error_t *open_session(svn_ra_
   SVN_ERR(svn_ra_svn__read_cmd_response(conn, pool, "c?c?l", &conn->uuid,
                                         &conn->repos_root, &repos_caplist));
   if (repos_caplist)
-    SVN_ERR(svn_ra_svn_set_capabilities(conn, repos_caplist));
+    SVN_ERR(svn_ra_svn__set_capabilities(conn, repos_caplist));
 
   if (conn->repos_root)
     {
@@ -804,6 +810,7 @@ static svn_error_t *ra_svn_open(svn_ra_s
                                 const char *url,
                                 const svn_ra_callbacks2_t *callbacks,
                                 void *callback_baton,
+                                svn_auth_baton_t *auth_baton,
                                 apr_hash_t *config,
                                 apr_pool_t *result_pool,
                                 apr_pool_t *scratch_pool)
@@ -839,32 +846,21 @@ static svn_error_t *ra_svn_open(svn_ra_s
                ? svn_hash_gets(config, SVN_CONFIG_CATEGORY_CONFIG)
                : NULL;
   cfg = config ? svn_hash_gets(config, SVN_CONFIG_CATEGORY_SERVERS) : NULL;
-  svn_auth_set_parameter(callbacks->auth_baton,
+  svn_auth_set_parameter(auth_baton,
                          SVN_AUTH_PARAM_CONFIG_CATEGORY_CONFIG, cfg_client);
-  svn_auth_set_parameter(callbacks->auth_baton,
+  svn_auth_set_parameter(auth_baton,
                          SVN_AUTH_PARAM_CONFIG_CATEGORY_SERVERS, cfg);
 
   /* We open the session in a subpool so we can get rid of it if we
      reparent with a server that doesn't support reparenting. */
   SVN_ERR(open_session(&sess, url, &uri, tunnel, tunnel_argv, config,
-                       callbacks, callback_baton, sess_pool));
+                       callbacks, callback_baton,
+                       auth_baton, sess_pool, scratch_pool));
   session->priv = sess;
 
   return SVN_NO_ERROR;
 }
 
-static svn_error_t *ra_svn_open_pool(svn_ra_session_t *session,
-                                     const char **corrected_url,
-                                     const char *url,
-                                     const svn_ra_callbacks2_t *callbacks,
-                                     void *callback_baton,
-                                     apr_hash_t *config,
-                                     apr_pool_t *pool)
-{
-  return ra_svn_open(session, corrected_url, url, callbacks, callback_baton,
-                     config, pool, pool);
-}
-
 static svn_error_t *ra_svn_dup_session(svn_ra_session_t *new_session,
                                        svn_ra_session_t *old_session,
                                        const char *new_session_url,
@@ -875,7 +871,7 @@ static svn_error_t *ra_svn_dup_session(s
 
   SVN_ERR(ra_svn_open(new_session, NULL, new_session_url,
                       old_sess->callbacks, old_sess->callbacks_baton,
-                      old_sess->config,
+                      old_sess->auth_baton, old_sess->config,
                       result_pool, scratch_pool));
 
   return SVN_NO_ERROR;
@@ -912,7 +908,7 @@ static svn_error_t *ra_svn_reparent(svn_
   if (! err)
     err = open_session(&new_sess, url, &uri, sess->tunnel_name, sess->tunnel_argv,
                        sess->config, sess->callbacks, sess->callbacks_baton,
-                       sess_pool);
+                       sess->auth_baton, sess_pool, sess_pool);
   /* We destroy the new session pool on error, since it is allocated in
      the main session pool. */
   if (err)
@@ -1038,7 +1034,7 @@ static svn_error_t *ra_svn_rev_proplist(
 {
   svn_ra_svn__session_baton_t *sess_baton = session->priv;
   svn_ra_svn_conn_t *conn = sess_baton->conn;
-  apr_array_header_t *proplist;
+  svn_ra_svn__list_t *proplist;
 
   SVN_ERR(svn_ra_svn__write_cmd_rev_proplist(conn, pool, rev));
   SVN_ERR(handle_auth_request(sess_baton, pool));
@@ -1185,12 +1181,12 @@ static svn_error_t *ra_svn_commit(svn_ra
   return SVN_NO_ERROR;
 }
 
-/* Parse IPROPLIST, an array of svn_ra_svn_item_t structures, as a list of
+/* Parse IPROPLIST, an array of svn_ra_svn__item_t structures, as a list of
    const char * repos relative paths and properties for those paths, storing
    the result as an array of svn_prop_inherited_item_t *items. */
 static svn_error_t *
 parse_iproplist(apr_array_header_t **inherited_props,
-                const apr_array_header_t *iproplist,
+                const svn_ra_svn__list_t *iproplist,
                 svn_ra_session_t *session,
                 apr_pool_t *result_pool,
                 apr_pool_t *scratch_pool)
@@ -1219,14 +1215,13 @@ parse_iproplist(apr_array_header_t **inh
 
   for (i = 0; i < iproplist->nelts; i++)
     {
-      apr_array_header_t *iprop_list;
+      svn_ra_svn__list_t *iprop_list;
       char *parent_rel_path;
       apr_hash_t *iprops;
       apr_hash_index_t *hi;
       svn_prop_inherited_item_t *new_iprop =
         apr_palloc(result_pool, sizeof(*new_iprop));
-      svn_ra_svn_item_t *elt = &APR_ARRAY_IDX(iproplist, i,
-                                              svn_ra_svn_item_t);
+      svn_ra_svn__item_t *elt = &SVN_RA_SVN__LIST_ITEM(iproplist, i);
       if (elt->kind != SVN_RA_SVN_LIST)
         return svn_error_create(
           SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
@@ -1234,7 +1229,7 @@ parse_iproplist(apr_array_header_t **inh
 
       svn_pool_clear(iterpool);
 
-      SVN_ERR(svn_ra_svn__parse_tuple(elt->u.list, iterpool, "cl",
+      SVN_ERR(svn_ra_svn__parse_tuple(&elt->u.list, "cl",
                                       &parent_rel_path, &iprop_list));
       SVN_ERR(svn_ra_svn__parse_proplist(iprop_list, iterpool, &iprops));
       new_iprop->path_or_url = svn_path_url_add_component2(repos_root_url,
@@ -1266,7 +1261,7 @@ static svn_error_t *ra_svn_get_file(svn_
 {
   svn_ra_svn__session_baton_t *sess_baton = session->priv;
   svn_ra_svn_conn_t *conn = sess_baton->conn;
-  apr_array_header_t *proplist;
+  svn_ra_svn__list_t *proplist;
   const char *expected_digest;
   svn_checksum_t *expected_checksum = NULL;
   svn_checksum_ctx_t *checksum_ctx;
@@ -1299,22 +1294,22 @@ static svn_error_t *ra_svn_get_file(svn_
   iterpool = svn_pool_create(pool);
   while (1)
     {
-      svn_ra_svn_item_t *item;
+      svn_ra_svn__item_t *item;
 
       svn_pool_clear(iterpool);
       SVN_ERR(svn_ra_svn__read_item(conn, iterpool, &item));
       if (item->kind != SVN_RA_SVN_STRING)
         return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
                                 _("Non-string as part of file contents"));
-      if (item->u.string->len == 0)
+      if (item->u.string.len == 0)
         break;
 
       if (expected_checksum)
-        SVN_ERR(svn_checksum_update(checksum_ctx, item->u.string->data,
-                                    item->u.string->len));
+        SVN_ERR(svn_checksum_update(checksum_ctx, item->u.string.data,
+                                    item->u.string.len));
 
-      SVN_ERR(svn_stream_write(stream, item->u.string->data,
-                               &item->u.string->len));
+      SVN_ERR(svn_stream_write(stream, item->u.string.data,
+                               &item->u.string.len));
     }
   svn_pool_destroy(iterpool);
 
@@ -1345,7 +1340,7 @@ static svn_error_t *ra_svn_get_dir(svn_r
 {
   svn_ra_svn__session_baton_t *sess_baton = session->priv;
   svn_ra_svn_conn_t *conn = sess_baton->conn;
-  apr_array_header_t *proplist, *dirlist;
+  svn_ra_svn__list_t *proplist, *dirlist;
   int i;
 
   SVN_ERR(svn_ra_svn__write_tuple(conn, pool, "w(c(?r)bb(!", "get-dir", path,
@@ -1390,12 +1385,12 @@ static svn_error_t *ra_svn_get_dir(svn_r
       svn_dirent_t *dirent;
       apr_uint64_t size;
       svn_revnum_t crev;
-      svn_ra_svn_item_t *elt = &APR_ARRAY_IDX(dirlist, i, svn_ra_svn_item_t);
+      svn_ra_svn__item_t *elt = &SVN_RA_SVN__LIST_ITEM(dirlist, i);
 
       if (elt->kind != SVN_RA_SVN_LIST)
         return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
                                 _("Dirlist element not a list"));
-      SVN_ERR(svn_ra_svn__parse_tuple(elt->u.list, pool, "cwnbr(?c)(?c)",
+      SVN_ERR(svn_ra_svn__parse_tuple(&elt->u.list, "cwnbr(?c)(?c)",
                                       &name, &kind, &size, &has_props,
                                       &crev, &cdate, &cauthor));
 
@@ -1457,8 +1452,8 @@ static svn_error_t *ra_svn_get_mergeinfo
   svn_ra_svn__session_baton_t *sess_baton = session->priv;
   svn_ra_svn_conn_t *conn = sess_baton->conn;
   int i;
-  apr_array_header_t *mergeinfo_tuple;
-  svn_ra_svn_item_t *elt;
+  svn_ra_svn__list_t *mergeinfo_tuple;
+  svn_ra_svn__item_t *elt;
   const char *path;
 
   SVN_ERR(svn_ra_svn__write_tuple(conn, pool, "w((!", "get-mergeinfo"));
@@ -1483,11 +1478,11 @@ static svn_error_t *ra_svn_get_mergeinfo
           svn_mergeinfo_t for_path;
           const char *to_parse;
 
-          elt = &((svn_ra_svn_item_t *) mergeinfo_tuple->elts)[i];
+          elt = &SVN_RA_SVN__LIST_ITEM(mergeinfo_tuple, i);
           if (elt->kind != SVN_RA_SVN_LIST)
             return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
                                     _("Mergeinfo element is not a list"));
-          SVN_ERR(svn_ra_svn__parse_tuple(elt->u.list, pool, "cc",
+          SVN_ERR(svn_ra_svn__parse_tuple(&elt->u.list, "cc",
                                           &path, &to_parse));
           SVN_ERR(svn_mergeinfo_parse(&for_path, to_parse, pool));
           /* Correct for naughty servers that send "relative" paths
@@ -1610,6 +1605,16 @@ static svn_error_t *ra_svn_diff(svn_ra_s
   return SVN_NO_ERROR;
 }
 
+/* Return TRUE if ITEM matches the word "done". */
+static svn_boolean_t
+is_done_response(const svn_ra_svn__item_t *item)
+{
+  static const svn_string_t str_done = SVN__STATIC_STRING("done");
+
+  return (   item->kind == SVN_RA_SVN_WORD
+          && svn_string_compare(&item->u.word, &str_done));
+}
+
 
 static svn_error_t *
 perform_ra_svn_log(svn_error_t **outer_error,
@@ -1690,23 +1695,23 @@ perform_ra_svn_log(svn_error_t **outer_e
       apr_uint64_t has_children_param, invalid_revnum_param;
       apr_uint64_t has_subtractive_merge_param;
       svn_string_t *author, *date, *message;
-      apr_array_header_t *cplist, *rplist;
+      svn_ra_svn__list_t *cplist, *rplist;
       svn_log_entry_t *log_entry;
       svn_boolean_t has_children;
       svn_boolean_t subtractive_merge = FALSE;
       apr_uint64_t revprop_count;
-      svn_ra_svn_item_t *item;
+      svn_ra_svn__item_t *item;
       apr_hash_t *cphash;
       svn_revnum_t rev;
 
       svn_pool_clear(iterpool);
       SVN_ERR(svn_ra_svn__read_item(conn, iterpool, &item));
-      if (item->kind == SVN_RA_SVN_WORD && strcmp(item->u.word, "done") == 0)
+      if (is_done_response(item))
         break;
       if (item->kind != SVN_RA_SVN_LIST)
         return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
                                 _("Log entry not a list"));
-      SVN_ERR(svn_ra_svn__parse_tuple(item->u.list, iterpool,
+      SVN_ERR(svn_ra_svn__parse_tuple(&item->u.list,
                                       "lr(?s)(?s)(?s)?BBnl?B",
                                       &cplist, &rev, &author, &date,
                                       &message, &has_children_param,
@@ -1748,13 +1753,12 @@ perform_ra_svn_log(svn_error_t **outer_e
               const char *copy_path, *action, *kind_str;
               apr_uint64_t text_mods, prop_mods;
               svn_revnum_t copy_rev;
-              svn_ra_svn_item_t *elt = &APR_ARRAY_IDX(cplist, i,
-                                                      svn_ra_svn_item_t);
+              svn_ra_svn__item_t *elt = &SVN_RA_SVN__LIST_ITEM(cplist, i);
 
               if (elt->kind != SVN_RA_SVN_LIST)
                 return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
                                         _("Changed-path entry not a list"));
-              SVN_ERR(svn_ra_svn__read_data_log_changed_entry(elt->u.list,
+              SVN_ERR(svn_ra_svn__read_data_log_changed_entry(&elt->u.list,
                                               &cpath, &action, &copy_path,
                                               &copy_rev, &kind_str,
                                               &text_mods, &prop_mods));
@@ -1784,7 +1788,7 @@ perform_ra_svn_log(svn_error_t **outer_e
           - Except if the server sends more than a >= 1 limit top level items
           - Or when the callback reported a SVN_ERR_CEASE_INVOCATION
             in an earlier invocation. */
-      if (! (limit && (nest_level == 0) && (++nreceived > limit))
+      if (! ((limit > 0) && (nest_level == 0) && (++nreceived > limit))
           && ! *outer_error)
         {
           svn_error_t *err;
@@ -1812,7 +1816,7 @@ perform_ra_svn_log(svn_error_t **outer_e
                           SVN_PROP_REVISION_LOG, message);
 
           err = receiver(receiver_baton, log_entry, iterpool);
-          if (err && err->apr_err == SVN_ERR_CEASE_INVOCATION)
+          if (svn_error_find_cause(err, SVN_ERR_CEASE_INVOCATION))
             {
               *outer_error = svn_error_trace(
                                 svn_error_compose_create(*outer_error, err));
@@ -1903,7 +1907,7 @@ static svn_error_t *ra_svn_stat(svn_ra_s
 {
   svn_ra_svn__session_baton_t *sess_baton = session->priv;
   svn_ra_svn_conn_t *conn = sess_baton->conn;
-  apr_array_header_t *list = NULL;
+  svn_ra_svn__list_t *list = NULL;
   svn_dirent_t *the_dirent;
 
   SVN_ERR(svn_ra_svn__write_cmd_stat(conn, pool, path, rev));
@@ -1922,7 +1926,7 @@ static svn_error_t *ra_svn_stat(svn_ra_s
       svn_revnum_t crev;
       apr_uint64_t size;
 
-      SVN_ERR(svn_ra_svn__parse_tuple(list, pool, "wnbr(?c)(?c)",
+      SVN_ERR(svn_ra_svn__parse_tuple(list, "wnbr(?c)(?c)",
                                       &kind, &size, &has_props,
                                       &crev, &cdate, &cauthor));
 
@@ -1952,6 +1956,7 @@ static svn_error_t *ra_svn_get_locations
   svn_ra_svn_conn_t *conn = sess_baton->conn;
   svn_revnum_t revision;
   svn_boolean_t is_done;
+  apr_pool_t *iterpool;
   int i;
 
   /* Transmit the parameters. */
@@ -1972,21 +1977,25 @@ static svn_error_t *ra_svn_get_locations
   /* Read the hash items. */
   is_done = FALSE;
   *locations = apr_hash_make(pool);
+  iterpool = svn_pool_create(pool);
   while (!is_done)
     {
-      svn_ra_svn_item_t *item;
+      svn_ra_svn__item_t *item;
       const char *ret_path;
 
-      SVN_ERR(svn_ra_svn__read_item(conn, pool, &item));
-      if (item->kind == SVN_RA_SVN_WORD && strcmp(item->u.word, "done") == 0)
+      svn_pool_clear(iterpool);
+      SVN_ERR(svn_ra_svn__read_item(conn, iterpool, &item));
+      if (is_done_response(item))
         is_done = 1;
       else if (item->kind != SVN_RA_SVN_LIST)
         return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
                                 _("Location entry not a list"));
       else
         {
-          SVN_ERR(svn_ra_svn__parse_tuple(item->u.list, pool, "rc",
+          SVN_ERR(svn_ra_svn__parse_tuple(&item->u.list, "rc",
                                           &revision, &ret_path));
+
+          /* This also makes RET_PATH live in POOL rather than ITERPOOL. */
           ret_path = svn_fspath__canonicalize(ret_path, pool);
           apr_hash_set(*locations, apr_pmemdup(pool, &revision,
                                                sizeof(revision)),
@@ -1994,20 +2003,23 @@ static svn_error_t *ra_svn_get_locations
         }
     }
 
+  svn_pool_destroy(iterpool);
+
   /* Read the response. This is so the server would have a chance to
    * report an error. */
   return svn_error_trace(svn_ra_svn__read_cmd_response(conn, pool, ""));
 }
 
 static svn_error_t *
-ra_svn_get_location_segments(svn_ra_session_t *session,
-                             const char *path,
-                             svn_revnum_t peg_revision,
-                             svn_revnum_t start_rev,
-                             svn_revnum_t end_rev,
-                             svn_location_segment_receiver_t receiver,
-                             void *receiver_baton,
-                             apr_pool_t *pool)
+perform_get_location_segments(svn_error_t **outer_error,
+                              svn_ra_session_t *session,
+                              const char *path,
+                              svn_revnum_t peg_revision,
+                              svn_revnum_t start_rev,
+                              svn_revnum_t end_rev,
+                              svn_location_segment_receiver_t receiver,
+                              void *receiver_baton,
+                              apr_pool_t *pool)
 {
   svn_ra_svn__session_baton_t *sess_baton = session->priv;
   svn_ra_svn_conn_t *conn = sess_baton->conn;
@@ -2029,12 +2041,12 @@ ra_svn_get_location_segments(svn_ra_sess
   while (!is_done)
     {
       svn_revnum_t range_start, range_end;
-      svn_ra_svn_item_t *item;
+      svn_ra_svn__item_t *item;
       const char *ret_path;
 
       svn_pool_clear(iterpool);
       SVN_ERR(svn_ra_svn__read_item(conn, iterpool, &item));
-      if (item->kind == SVN_RA_SVN_WORD && strcmp(item->u.word, "done") == 0)
+      if (is_done_response(item))
         is_done = 1;
       else if (item->kind != SVN_RA_SVN_LIST)
         return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
@@ -2043,7 +2055,7 @@ ra_svn_get_location_segments(svn_ra_sess
         {
           svn_location_segment_t *segment = apr_pcalloc(iterpool,
                                                         sizeof(*segment));
-          SVN_ERR(svn_ra_svn__parse_tuple(item->u.list, iterpool, "rr(?c)",
+          SVN_ERR(svn_ra_svn__parse_tuple(&item->u.list, "rr(?c)",
                                           &range_start, &range_end, &ret_path));
           if (! (SVN_IS_VALID_REVNUM(range_start)
                  && SVN_IS_VALID_REVNUM(range_end)))
@@ -2054,7 +2066,17 @@ ra_svn_get_location_segments(svn_ra_sess
           segment->path = ret_path;
           segment->range_start = range_start;
           segment->range_end = range_end;
-          SVN_ERR(receiver(segment, receiver_baton, iterpool));
+
+          if (!*outer_error)
+            {
+              svn_error_t *err = svn_error_trace(receiver(segment, receiver_baton,
+                                                          iterpool));
+
+              if (svn_error_find_cause(err, SVN_ERR_CEASE_INVOCATION))
+                *outer_error = err;
+              else
+                SVN_ERR(err);
+            }
         }
     }
   svn_pool_destroy(iterpool);
@@ -2066,6 +2088,26 @@ ra_svn_get_location_segments(svn_ra_sess
   return SVN_NO_ERROR;
 }
 
+static svn_error_t *
+ra_svn_get_location_segments(svn_ra_session_t *session,
+                             const char *path,
+                             svn_revnum_t peg_revision,
+                             svn_revnum_t start_rev,
+                             svn_revnum_t end_rev,
+                             svn_location_segment_receiver_t receiver,
+                             void *receiver_baton,
+                             apr_pool_t *pool)
+{
+  svn_error_t *outer_err = SVN_NO_ERROR;
+  svn_error_t *err;
+
+  err = svn_error_trace(
+            perform_get_location_segments(&outer_err, session, path,
+                                          peg_revision, start_rev, end_rev,
+                                          receiver, receiver_baton, pool));
+  return svn_error_compose_create(outer_err, err);
+}
+
 static svn_error_t *ra_svn_get_file_revs(svn_ra_session_t *session,
                                          const char *path,
                                          svn_revnum_t start, svn_revnum_t end,
@@ -2093,10 +2135,10 @@ static svn_error_t *ra_svn_get_file_revs
 
   while (1)
     {
-      apr_array_header_t *rev_proplist, *proplist;
+      svn_ra_svn__list_t *rev_proplist, *proplist;
       apr_uint64_t merged_rev_param;
       apr_array_header_t *props;
-      svn_ra_svn_item_t *item;
+      svn_ra_svn__item_t *item;
       apr_hash_t *rev_props;
       svn_revnum_t rev;
       const char *p;
@@ -2107,7 +2149,7 @@ static svn_error_t *ra_svn_get_file_revs
       svn_pool_clear(rev_pool);
       svn_pool_clear(chunk_pool);
       SVN_ERR(svn_ra_svn__read_item(sess_baton->conn, rev_pool, &item));
-      if (item->kind == SVN_RA_SVN_WORD && strcmp(item->u.word, "done") == 0)
+      if (is_done_response(item))
         break;
       /* Either we've got a correct revision or we will error out below. */
       had_revision = TRUE;
@@ -2115,7 +2157,7 @@ static svn_error_t *ra_svn_get_file_revs
         return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
                                 _("Revision entry not a list"));
 
-      SVN_ERR(svn_ra_svn__parse_tuple(item->u.list, rev_pool,
+      SVN_ERR(svn_ra_svn__parse_tuple(&item->u.list,
                                       "crll?B", &p, &rev, &rev_proplist,
                                       &proplist, &merged_rev_param));
       p = svn_fspath__canonicalize(p, rev_pool);
@@ -2131,7 +2173,7 @@ static svn_error_t *ra_svn_get_file_revs
       if (item->kind != SVN_RA_SVN_STRING)
         return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
                                 _("Text delta chunk not a string"));
-      has_txdelta = item->u.string->len > 0;
+      has_txdelta = item->u.string.len > 0;
 
       SVN_ERR(handler(handler_baton, p, rev, rev_props, merged_rev,
                       has_txdelta ? &d_handler : NULL, &d_baton,
@@ -2147,13 +2189,13 @@ static svn_error_t *ra_svn_get_file_revs
                                                rev_pool);
           else
             stream = NULL;
-          while (item->u.string->len > 0)
+          while (item->u.string.len > 0)
             {
               apr_size_t size;
 
-              size = item->u.string->len;
+              size = item->u.string.len;
               if (stream)
-                SVN_ERR(svn_stream_write(stream, item->u.string->data, &size));
+                SVN_ERR(svn_stream_write(stream, item->u.string.data, &size));
               svn_pool_clear(chunk_pool);
 
               SVN_ERR(svn_ra_svn__read_item(sess_baton->conn, chunk_pool,
@@ -2195,7 +2237,7 @@ static svn_error_t *ra_svn_lock_compat(s
 {
   svn_ra_svn__session_baton_t *sess = session->priv;
   svn_ra_svn_conn_t* conn = sess->conn;
-  apr_array_header_t *list;
+  svn_ra_svn__list_t *list;
   apr_hash_index_t *hi;
   apr_pool_t *iterpool = svn_pool_create(pool);
 
@@ -2266,7 +2308,7 @@ static svn_error_t *ra_svn_unlock_compat
       const void *key;
       const char *path;
       void *val;
-      const char *token;
+      const svn_string_t *token;
       svn_error_t *err, *callback_err = NULL;
 
       svn_pool_clear(iterpool);
@@ -2274,7 +2316,7 @@ static svn_error_t *ra_svn_unlock_compat
       apr_hash_this(hi, &key, NULL, &val);
       path = key;
       if (strcmp(val, "") != 0)
-        token = val;
+        token = svn_string_create(val, iterpool);
       else
         token = NULL;
 
@@ -2358,13 +2400,13 @@ static svn_error_t *ra_svn_lock(svn_ra_s
   /* Loop over responses to get lock information. */
   for (hi = apr_hash_first(pool, path_revs); hi; hi = apr_hash_next(hi))
     {
-      svn_ra_svn_item_t *elt;
+      svn_ra_svn__item_t *elt;
       const void *key;
       const char *path;
       svn_error_t *callback_err;
       const char *status;
       svn_lock_t *lock;
-      apr_array_header_t *list;
+      svn_ra_svn__list_t *list;
 
       apr_hash_this(hi, &key, NULL, NULL);
       path = key;
@@ -2376,18 +2418,17 @@ static svn_error_t *ra_svn_lock(svn_ra_s
          the middle of the request list.  If this happens, it will
          transmit "done" to end the lock-info early, and then the
          overall command response will talk about the fatal error. */
-      if (elt->kind == SVN_RA_SVN_WORD && strcmp(elt->u.word, "done") == 0)
+      if (is_done_response(elt))
         break;
 
       if (elt->kind != SVN_RA_SVN_LIST)
         return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
                                 _("Lock response not a list"));
 
-      SVN_ERR(svn_ra_svn__parse_tuple(elt->u.list, iterpool, "wl", &status,
-                                      &list));
+      SVN_ERR(svn_ra_svn__parse_tuple(&elt->u.list, "wl", &status, &list));
 
       if (strcmp(status, "failure") == 0)
-        err = svn_ra_svn__handle_failure_status(list, iterpool);
+        err = svn_ra_svn__handle_failure_status(list);
       else if (strcmp(status, "success") == 0)
         {
           SVN_ERR(parse_lock(list, iterpool, &lock));
@@ -2414,10 +2455,10 @@ static svn_error_t *ra_svn_lock(svn_ra_s
      read the final "done" from the server. */
   if (!hi)
     {
-      svn_ra_svn_item_t *elt;
+      svn_ra_svn__item_t *elt;
 
       SVN_ERR(svn_ra_svn__read_item(conn, pool, &elt));
-      if (elt->kind != SVN_RA_SVN_WORD || strcmp(elt->u.word, "done") != 0)
+      if (!is_done_response(elt))
         return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
                                 _("Didn't receive end marker for lock "
                                   "responses"));
@@ -2487,11 +2528,11 @@ static svn_error_t *ra_svn_unlock(svn_ra
   /* Loop over responses to unlock files. */
   for (hi = apr_hash_first(pool, path_tokens); hi; hi = apr_hash_next(hi))
     {
-      svn_ra_svn_item_t *elt;
+      svn_ra_svn__item_t *elt;
       const void *key;
       svn_error_t *callback_err;
       const char *status;
-      apr_array_header_t *list;
+      svn_ra_svn__list_t *list;
 
       svn_pool_clear(iterpool);
 
@@ -2501,7 +2542,7 @@ static svn_error_t *ra_svn_unlock(svn_ra
          the middle of the request list.  If this happens, it will
          transmit "done" to end the lock-info early, and then the
          overall command response will talk about the fatal error. */
-      if (elt->kind == SVN_RA_SVN_WORD && (strcmp(elt->u.word, "done") == 0))
+      if (is_done_response(elt))
         break;
 
       apr_hash_this(hi, &key, NULL, NULL);
@@ -2511,14 +2552,13 @@ static svn_error_t *ra_svn_unlock(svn_ra
         return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
                                 _("Unlock response not a list"));
 
-      SVN_ERR(svn_ra_svn__parse_tuple(elt->u.list, iterpool, "wl", &status,
-                                      &list));
+      SVN_ERR(svn_ra_svn__parse_tuple(&elt->u.list, "wl", &status, &list));
 
       if (strcmp(status, "failure") == 0)
-        err = svn_ra_svn__handle_failure_status(list, iterpool);
+        err = svn_ra_svn__handle_failure_status(list);
       else if (strcmp(status, "success") == 0)
         {
-          SVN_ERR(svn_ra_svn__parse_tuple(list, iterpool, "c", &path));
+          SVN_ERR(svn_ra_svn__parse_tuple(list, "c", &path));
           err = SVN_NO_ERROR;
         }
       else
@@ -2541,10 +2581,10 @@ static svn_error_t *ra_svn_unlock(svn_ra
      read the final "done" from the server. */
   if (!hi)
     {
-      svn_ra_svn_item_t *elt;
+      svn_ra_svn__item_t *elt;
 
       SVN_ERR(svn_ra_svn__read_item(conn, pool, &elt));
-      if (elt->kind != SVN_RA_SVN_WORD || strcmp(elt->u.word, "done") != 0)
+      if (! is_done_response(elt))
         return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
                                 _("Didn't receive end marker for unlock "
                                   "responses"));
@@ -2564,7 +2604,7 @@ static svn_error_t *ra_svn_get_lock(svn_
 {
   svn_ra_svn__session_baton_t *sess = session->priv;
   svn_ra_svn_conn_t* conn = sess->conn;
-  apr_array_header_t *list;
+  svn_ra_svn__list_t *list;
 
   SVN_ERR(svn_ra_svn__write_cmd_get_lock(conn, pool, path));
 
@@ -2609,7 +2649,7 @@ static svn_error_t *ra_svn_get_locks(svn
 {
   svn_ra_svn__session_baton_t *sess = session->priv;
   svn_ra_svn_conn_t* conn = sess->conn;
-  apr_array_header_t *list;
+  svn_ra_svn__list_t *list;
   const char *full_url, *abs_path;
   int i;
 
@@ -2632,12 +2672,12 @@ static svn_error_t *ra_svn_get_locks(svn
   for (i = 0; i < list->nelts; ++i)
     {
       svn_lock_t *lock;
-      svn_ra_svn_item_t *elt = &APR_ARRAY_IDX(list, i, svn_ra_svn_item_t);
+      svn_ra_svn__item_t *elt = &SVN_RA_SVN__LIST_ITEM(list, i);
 
       if (elt->kind != SVN_RA_SVN_LIST)
         return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
                                 _("Lock element not a list"));
-      SVN_ERR(parse_lock(elt->u.list, pool, &lock));
+      SVN_ERR(parse_lock(&elt->u.list, pool, &lock));
 
       /* Filter out unwanted paths.  Since Subversion only allows
          locks on files, we can treat depth=immediates the same as
@@ -2720,16 +2760,22 @@ ra_svn_replay_range(svn_ra_session_t *se
       void *edit_baton;
       apr_hash_t *rev_props;
       const char *word;
-      apr_array_header_t *list;
+      svn_ra_svn__list_t *list;
 
       svn_pool_clear(iterpool);
 
       SVN_ERR(svn_ra_svn__read_tuple(sess->conn, iterpool,
                                      "wl", &word, &list));
+
       if (strcmp(word, "revprops") != 0)
-        return svn_error_createf(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
-                                 _("Expected 'revprops', found '%s'"),
-                                 word);
+        {
+          if (strcmp(word, "failure") == 0)
+            SVN_ERR(svn_ra_svn__handle_failure_status(list));
+
+          return svn_error_createf(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
+                                   _("Expected 'revprops', found '%s'"),
+                                   word);
+        }
 
       SVN_ERR(svn_ra_svn__parse_proplist(list, iterpool, &rev_props));
 
@@ -2846,7 +2892,7 @@ ra_svn_get_inherited_props(svn_ra_sessio
 {
   svn_ra_svn__session_baton_t *sess_baton = session->priv;
   svn_ra_svn_conn_t *conn = sess_baton->conn;
-  apr_array_header_t *iproplist;
+  svn_ra_svn__list_t *iproplist;
   svn_boolean_t iprop_capable;
 
   SVN_ERR(ra_svn_has_capability(session, &iprop_capable,
@@ -2872,7 +2918,7 @@ static const svn_ra__vtable_t ra_svn_vta
   svn_ra_svn_version,
   ra_svn_get_description,
   ra_svn_get_schemes,
-  ra_svn_open_pool,
+  ra_svn_open,
   ra_svn_dup_session,
   ra_svn_reparent,
   ra_svn_get_session_url,

Modified: subversion/branches/ra-git/subversion/libsvn_ra_svn/cram.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_ra_svn/cram.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_ra_svn/cram.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_ra_svn/cram.c Mon Nov 30 10:24:16 2015
@@ -140,7 +140,7 @@ svn_error_t *svn_ra_svn_cram_server(svn_
   char hostbuf[APRMAXHOSTLEN + 1];
   unsigned char cdigest[APR_MD5_DIGESTSIZE], sdigest[APR_MD5_DIGESTSIZE];
   const char *challenge, *sep, *password;
-  svn_ra_svn_item_t *item;
+  svn_ra_svn__item_t *item;
   svn_string_t *resp;
 
   *success = FALSE;
@@ -160,7 +160,7 @@ svn_error_t *svn_ra_svn_cram_server(svn_
   SVN_ERR(svn_ra_svn__read_item(conn, pool, &item));
   if (item->kind != SVN_RA_SVN_STRING)  /* Very wrong; don't report failure */
     return SVN_NO_ERROR;
-  resp = item->u.string;
+  resp = &item->u.string;
   sep = strrchr(resp->data, ' ');
   if (!sep || resp->len - (sep + 1 - resp->data) != APR_MD5_DIGESTSIZE * 2
       || !hex_decode(cdigest, sep + 1))

Modified: subversion/branches/ra-git/subversion/libsvn_ra_svn/cyrus_auth.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_ra_svn/cyrus_auth.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_ra_svn/cyrus_auth.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_ra_svn/cyrus_auth.c Mon Nov 30 10:24:16 2015
@@ -828,7 +828,7 @@ svn_error_t *svn_ra_svn__get_addresses(c
 
 svn_error_t *
 svn_ra_svn__do_cyrus_auth(svn_ra_svn__session_baton_t *sess,
-                          const apr_array_header_t *mechlist,
+                          const svn_ra_svn__list_t *mechlist,
                           const char *realm, apr_pool_t *pool)
 {
   apr_pool_t *subpool;
@@ -856,18 +856,18 @@ svn_ra_svn__do_cyrus_auth(svn_ra_svn__se
       /* Create a string containing the list of mechanisms, separated by spaces. */
       for (i = 0; i < mechlist->nelts; i++)
         {
-          svn_ra_svn_item_t *elt = &APR_ARRAY_IDX(mechlist, i, svn_ra_svn_item_t);
+          svn_ra_svn__item_t *elt = &SVN_RA_SVN__LIST_ITEM(mechlist, i);
           mechstring = apr_pstrcat(pool,
                                    mechstring,
                                    i == 0 ? "" : " ",
-                                   elt->u.word, SVN_VA_NULL);
+                                   elt->u.word.data, SVN_VA_NULL);
         }
     }
 
   realmstring = apr_psprintf(pool, "%s %s", sess->realm_prefix, realm);
 
   /* Initialize the credential baton. */
-  cred_baton.auth_baton = sess->callbacks->auth_baton;
+  cred_baton.auth_baton = sess->auth_baton;
   cred_baton.realmstring = realmstring;
   cred_baton.pool = pool;
 

Modified: subversion/branches/ra-git/subversion/libsvn_ra_svn/deprecated.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_ra_svn/deprecated.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_ra_svn/deprecated.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_ra_svn/deprecated.c Mon Nov 30 10:24:16 2015
@@ -110,7 +110,12 @@ svn_ra_svn_read_item(svn_ra_svn_conn_t *
                      apr_pool_t *pool,
                      svn_ra_svn_item_t **item)
 {
-  return svn_error_trace(svn_ra_svn__read_item(conn, pool, item));
+  svn_ra_svn__item_t *temp;
+  SVN_ERR(svn_ra_svn__read_item(conn, pool, &temp));
+  *item  = apr_pcalloc(pool, sizeof(**item));
+  svn_ra_svn__to_public_item(*item, temp, pool);
+
+  return SVN_NO_ERROR;
 }
 
 svn_error_t *
@@ -127,9 +132,10 @@ svn_ra_svn_parse_tuple(const apr_array_h
 {
   va_list va;
   svn_error_t *err;
+  svn_ra_svn__list_t *internal = svn_ra_svn__to_private_array(list, pool);
 
   va_start(va, fmt);
-  err = svn_ra_svn__parse_tuple(list, pool, fmt, va);
+  err = svn_ra_svn__parse_tuple(internal, fmt, va);
   va_end(va);
 
   return svn_error_trace(err);
@@ -155,7 +161,9 @@ svn_ra_svn_parse_proplist(const apr_arra
                           apr_pool_t *pool,
                           apr_hash_t **props)
 {
-  return svn_error_trace(svn_ra_svn__parse_proplist(list, pool, props));
+  svn_ra_svn__list_t *internal
+    = svn_ra_svn__to_private_array(list, pool);
+  return svn_error_trace(svn_ra_svn__parse_proplist(internal, pool, props));
 }
 
 svn_error_t *
@@ -180,8 +188,23 @@ svn_ra_svn_handle_commands2(svn_ra_svn_c
                             void *baton,
                             svn_boolean_t error_on_disconnect)
 {
+  apr_size_t i, count = 0;
+  svn_ra_svn__cmd_entry_t *internal;
+
+  while (commands[count].cmdname)
+    count++;
+
+  internal = apr_pcalloc(pool, count * sizeof(*internal));
+  for (i = 0; i < count; ++i)
+    {
+      internal[i].cmdname = commands[i].cmdname;
+      internal[i].handler = NULL;
+      internal[i].deprecated_handler = commands[i].handler;
+      internal[i].terminate = commands[i].terminate;
+    }
+
   return svn_error_trace(svn_ra_svn__handle_commands2(conn, pool,
-                                                      commands, baton,
+                                                      internal, baton,
                                                       error_on_disconnect));
 }
 
@@ -191,9 +214,9 @@ svn_ra_svn_handle_commands(svn_ra_svn_co
                            const svn_ra_svn_cmd_entry_t *commands,
                            void *baton)
 {
-  return svn_error_trace(svn_ra_svn__handle_commands2(conn, pool,
-                                                      commands, baton,
-                                                      FALSE));
+  return svn_error_trace(svn_ra_svn_handle_commands2(conn, pool,
+                                                     commands, baton,
+                                                     FALSE));
 }
 
 svn_error_t *
@@ -239,6 +262,20 @@ svn_ra_svn_write_cmd_failure(svn_ra_svn_
 
 /* From marshal.c */
 svn_ra_svn_conn_t *
+svn_ra_svn_create_conn4(apr_socket_t *sock,
+                        svn_stream_t *in_stream,
+                        svn_stream_t *out_stream,
+                        int compression_level,
+                        apr_size_t zero_copy_limit,
+                        apr_size_t error_check_interval,
+                        apr_pool_t *pool)
+{
+  return svn_ra_svn_create_conn5(sock, in_stream, out_stream,
+                                 compression_level, zero_copy_limit,
+                                 error_check_interval, 0, 0, pool);
+}
+
+svn_ra_svn_conn_t *
 svn_ra_svn_create_conn3(apr_socket_t *sock,
                         apr_file_t *in_file,
                         apr_file_t *out_file,
@@ -256,7 +293,8 @@ svn_ra_svn_create_conn3(apr_socket_t *so
     out_stream = svn_stream_from_aprfile2(out_file, FALSE, pool);
 
   return svn_ra_svn_create_conn4(sock, in_stream, out_stream,
-                                 compression_level, 0, 0, pool);
+                                 compression_level, zero_copy_limit,
+                                 error_check_interval, pool);
 }
 
 svn_ra_svn_conn_t *