You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by st...@apache.org on 2015/01/27 11:51:53 UTC

svn commit: r1655005 [2/3] - in /subversion/branches/pin-externals: ./ subversion/libsvn_fs_fs/ subversion/libsvn_ra_serf/ subversion/libsvn_repos/ subversion/libsvn_subr/ subversion/libsvn_wc/ subversion/mod_dav_svn/ subversion/svnrdump/ subversion/te...

Modified: subversion/branches/pin-externals/subversion/libsvn_ra_serf/ra_serf.h
URL: http://svn.apache.org/viewvc/subversion/branches/pin-externals/subversion/libsvn_ra_serf/ra_serf.h?rev=1655005&r1=1655004&r2=1655005&view=diff
==============================================================================
--- subversion/branches/pin-externals/subversion/libsvn_ra_serf/ra_serf.h (original)
+++ subversion/branches/pin-externals/subversion/libsvn_ra_serf/ra_serf.h Tue Jan 27 10:51:52 2015
@@ -378,7 +378,7 @@ typedef svn_error_t *
 /* Callback when the request is done */
 typedef svn_error_t *
 (*svn_ra_serf__response_done_delegate_t)(serf_request_t *request,
-                                         void *handler_baton,
+                                         void *done_baton,
                                          apr_pool_t *scratch_pool);
 
 /* Callback for when a request body is needed. */
@@ -639,9 +639,11 @@ typedef struct svn_ra_serf__xml_transiti
 
 } svn_ra_serf__xml_transition_t;
 
-/* Constructor for */
+/* Constructor for svn_ra_serf__handler_t. Initializes a new handler
+   with default settings for SESSION. */
 svn_ra_serf__handler_t *
-svn_ra_serf__create_handler(apr_pool_t *result_pool);
+svn_ra_serf__create_handler(svn_ra_serf__session_t *session,
+                            apr_pool_t *result_pool);
 
 /* Construct an XML parsing context, based on the TTABLE transition table.
    As content is parsed, the CLOSED_CB callback will be invoked according
@@ -685,7 +687,8 @@ svn_ra_serf__xml_context_done(svn_ra_ser
 
    This also initializes HANDLER_POOL to the given RESULT_POOL.  */
 svn_ra_serf__handler_t *
-svn_ra_serf__create_expat_handler(svn_ra_serf__xml_context_t *xmlctx,
+svn_ra_serf__create_expat_handler(svn_ra_serf__session_t *session,
+                                  svn_ra_serf__xml_context_t *xmlctx,
                                   const int *expected_status,
                                   apr_pool_t *result_pool);
 
@@ -924,15 +927,15 @@ svn_ra_serf__keep_only_regular_props(apr
 
 /* Callback used via svn_ra_serf__deliver_props2 */
 typedef svn_error_t *
-(*svn_ra_serf__prop_func)(void *baton,
-                          const char *path,
-                          const char *ns,
-                          const char *name,
-                          const svn_string_t *value,
-                          apr_pool_t *scratch_pool);
+(*svn_ra_serf__prop_func_t)(void *baton,
+                            const char *path,
+                            const char *ns,
+                            const char *name,
+                            const svn_string_t *value,
+                            apr_pool_t *scratch_pool);
 
 /*
- * Implementation of svn_ra_serf__prop_func that just delivers svn compatible
+ * Implementation of svn_ra_serf__prop_func_t that just delivers svn compatible
  * properties  in the apr_hash_t * that is used as baton.
  */
 svn_error_t *
@@ -944,48 +947,23 @@ svn_ra_serf__deliver_svn_props(void *bat
                                apr_pool_t *scratch_pool);
 
 /*
- * Implementation of svn_ra_serf__prop_func that delivers all DAV properties
- * in (const char * -> apr_hash_t *) on Namespace pointing to a second hash
- *    (const char * -> svn_string_t *) to the values.
- */
-svn_error_t *
-svn_ra_serf__deliver_node_props(void *baton,
-                                const char *path,
-                                const char *ns,
-                                const char *name,
-                                const svn_string_t *value,
-                                apr_pool_t *scratch_pool);
+ * This function will create a handler for a PROPFIND request, which will deliver
+ * properties to PROP_FUNC() with PROP_BATON for the properties listed in LOOKUP_PROPS
+ * at URL for DEPTH ("0","1","infinity").
+ */
+svn_error_t *
+svn_ra_serf__create_propfind_handler(svn_ra_serf__handler_t **handler,
+                                     svn_ra_serf__session_t *session,
+                                     const char *path,
+                                     svn_revnum_t rev,
+                                     const char *depth,
+                                     const svn_ra_serf__dav_props_t *find_props,
+                                     svn_ra_serf__prop_func_t prop_func,
+                                     void *prop_func_baton,
+                                     apr_pool_t *result_pool);
 
 
-/*
- * This function will deliver a PROP_CTX PROPFIND request in the SESS
- * serf context for the properties listed in LOOKUP_PROPS at URL for
- * DEPTH ("0","1","infinity").
- *
- * This function will not block waiting for the response. Callers are
- * expected to call svn_ra_serf__wait_for_props().
- */
-svn_error_t *
-svn_ra_serf__deliver_props2(svn_ra_serf__handler_t **propfind_handler,
-                            svn_ra_serf__session_t *sess,
-                            svn_ra_serf__connection_t *conn,
-                            const char *path,
-                            svn_revnum_t rev,
-                            const char *depth,
-                            const svn_ra_serf__dav_props_t *find_props,
-                            svn_ra_serf__prop_func prop_func,
-                            void *prop_func_baton,
-                            apr_pool_t *pool);
-/*
- * This helper function will block until PROPFIND_HANDLER indicates that is
- * done or another error is returned.
- */
-svn_error_t *
-svn_ra_serf__wait_for_props(svn_ra_serf__handler_t *handler,
-                            apr_pool_t *scratch_pool);
-
-
-/* Using CONN, fetch the properties specified by WHICH_PROPS using CONN
+/* Using SESSION, fetch the properties specified by WHICH_PROPS using CONN
    for URL at REVISION. The resulting properties are placed into a 2-level
    hash in RESULTS, mapping NAMESPACE -> hash<PROPNAME, PROPVALUE>, which
    is allocated in RESULT_POOL.
@@ -998,7 +976,7 @@ svn_ra_serf__wait_for_props(svn_ra_serf_
    Temporary allocations are made in SCRATCH_POOL.  */
 svn_error_t *
 svn_ra_serf__fetch_node_props(apr_hash_t **results,
-                              svn_ra_serf__connection_t *conn,
+                              svn_ra_serf__session_t *session,
                               const char *url,
                               svn_revnum_t revision,
                               const svn_ra_serf__dav_props_t *which_props,
@@ -1006,7 +984,7 @@ svn_ra_serf__fetch_node_props(apr_hash_t
                               apr_pool_t *scratch_pool);
 
 
-/* Using CONN, fetch a DAV: property from the resource identified by URL
+/* Using SESSION, fetch a DAV: property from the resource identified by URL
    within REVISION. The PROPNAME may be one of:
 
      "checked-in"
@@ -1020,31 +998,13 @@ svn_ra_serf__fetch_node_props(apr_hash_t
    Temporary allocations are made in SCRATCH_POOL.  */
 svn_error_t *
 svn_ra_serf__fetch_dav_prop(const char **value,
-                            svn_ra_serf__connection_t *conn,
+                            svn_ra_serf__session_t *session,
                             const char *url,
                             svn_revnum_t revision,
                             const char *propname,
                             apr_pool_t *result_pool,
                             apr_pool_t *scratch_pool);
 
-
-/** Property walker functions **/
-
-typedef svn_error_t *
-(*svn_ra_serf__walker_visitor_t)(void *baton,
-                                 const char *ns,
-                                 const char *name,
-                                 const svn_string_t *val,
-                                 apr_pool_t *pool);
-
-/* Like walk_all_props(), but a 2-level hash.  */
-svn_error_t *
-svn_ra_serf__walk_node_props(apr_hash_t *props,
-                             svn_ra_serf__walker_visitor_t walker,
-                             void *baton,
-                             apr_pool_t *scratch_pool);
-
-
 /* Map a property name, as passed over the wire, into its corresponding
    Subversion-internal name. The returned name will be a static value,
    or allocated within RESULT_POOL.
@@ -1056,30 +1016,6 @@ svn_ra_serf__svnname_from_wirename(const
                                    const char *name,
                                    apr_pool_t *result_pool);
 
-
-/* PROPS is nested hash tables mapping NS -> NAME -> VALUE.
-   This function takes the NS:NAME:VALUE hashes and flattens them into a set of
-   names to VALUE. The names are composed of NS:NAME, with specific
-   rewrite from wire names (DAV) to SVN names. This mapping is managed
-   by the svn_ra_serf__set_baton_props() function.
-
-   FLAT_PROPS is allocated in RESULT_POOL.
-   ### right now, we do a shallow copy from PROPS to FLAT_PROPS. therefore,
-   ### the names and values in PROPS must be in the proper pool.
-
-   Temporary allocations are made in SCRATCH_POOL.  */
-svn_error_t *
-svn_ra_serf__flatten_props(apr_hash_t **flat_props,
-                           apr_hash_t *props,
-                           apr_pool_t *result_pool,
-                           apr_pool_t *scratch_pool);
-
-
-svn_error_t *
-svn_ra_serf__get_resource_type(svn_node_kind_t *kind,
-                               apr_hash_t *props);
-
-
 /** MERGE-related functions **/
 
 /* Create an MERGE request aimed at the SESSION url, requesting the
@@ -1090,7 +1026,6 @@ svn_ra_serf__get_resource_type(svn_node_
 svn_error_t *
 svn_ra_serf__run_merge(const svn_commit_info_t **commit_info,
                        svn_ra_serf__session_t *session,
-                       svn_ra_serf__connection_t *conn,
                        const char *merge_resource_url,
                        apr_hash_t *lock_tokens,
                        svn_boolean_t keep_locks,
@@ -1118,7 +1053,7 @@ svn_ra_serf__probe_proxy(svn_ra_serf__se
    All temporary allocations will be made in SCRATCH_POOL.  */
 svn_error_t *
 svn_ra_serf__v2_get_youngest_revnum(svn_revnum_t *youngest,
-                                    svn_ra_serf__connection_t *conn,
+                                    svn_ra_serf__session_t *session,
                                     apr_pool_t *scratch_pool);
 
 
@@ -1133,35 +1068,29 @@ svn_ra_serf__v2_get_youngest_revnum(svn_
    All temporary allocations will be made in SCRATCH_POOL.  */
 svn_error_t *
 svn_ra_serf__v1_get_activity_collection(const char **activity_url,
-                                        svn_ra_serf__connection_t *conn,
+                                        svn_ra_serf__session_t *session,
                                         apr_pool_t *result_pool,
                                         apr_pool_t *scratch_pool);
 
 
 /* Set @a VCC_URL to the default VCC for our repository based on @a
  * ORIG_PATH for the session @a SESSION, ensuring that the VCC URL and
- * repository root URLs are cached in @a SESSION.  Use @a CONN for any
- * required network communications if it is non-NULL; otherwise use the
- * default connection.
+ * repository root URLs are cached in @a SESSION. 
  *
- * All temporary allocations will be made in @a POOL. */
+ * All temporary allocations will be made in @a SCRATCH_POOL. */
 svn_error_t *
 svn_ra_serf__discover_vcc(const char **vcc_url,
                           svn_ra_serf__session_t *session,
-                          svn_ra_serf__connection_t *conn,
-                          apr_pool_t *pool);
+                          apr_pool_t *scratch_pool);
 
 /* Set @a REPORT_TARGET to the URI of the resource at which generic
- * (path-agnostic) REPORTs should be aimed for @a SESSION.  Use @a
- * CONN for any required network communications if it is non-NULL;
- * otherwise use the default connection.
+ * (path-agnostic) REPORTs should be aimed for @a SESSION.
  *
  * All temporary allocations will be made in @a POOL.
  */
 svn_error_t *
 svn_ra_serf__report_resource(const char **report_target,
                              svn_ra_serf__session_t *session,
-                             svn_ra_serf__connection_t *conn,
                              apr_pool_t *pool);
 
 /* Set @a REL_PATH to a path (not URI-encoded) relative to the root of
@@ -1173,7 +1102,6 @@ svn_error_t *
 svn_ra_serf__get_relative_path(const char **rel_path,
                                const char *orig_path,
                                svn_ra_serf__session_t *session,
-                               svn_ra_serf__connection_t *conn,
                                apr_pool_t *pool);
 
 
@@ -1200,11 +1128,9 @@ svn_ra_serf__get_youngest_revnum(svn_rev
    The DAV RA provider(s) solve this by generating a URL that is specific
    to a revision by using a URL into a "baseline collection".
 
-   For a specified SESSION, with an optional CONN (if NULL, then the
-   session's default connection will be used; specifically SESSION->conns[0]),
-   generate a revision-stable URL for URL at REVISION. If REVISION is
-   SVN_INVALID_REVNUM, then the stable URL will refer to the youngest
-   revision at the time this function was called.
+   For a specified SESSION, generate a revision-stable URL for URL at
+   REVISION. If REVISION is    SVN_INVALID_REVNUM, then the stable URL will
+   refer to the youngest revision at the time this function was called.
 
    If URL is NULL, then the session root will be used.
 
@@ -1223,7 +1149,6 @@ svn_error_t *
 svn_ra_serf__get_stable_url(const char **stable_url,
                             svn_revnum_t *latest_revnum,
                             svn_ra_serf__session_t *session,
-                            svn_ra_serf__connection_t *conn,
                             const char *url,
                             svn_revnum_t revision,
                             apr_pool_t *result_pool,

Modified: subversion/branches/pin-externals/subversion/libsvn_ra_serf/replay.c
URL: http://svn.apache.org/viewvc/subversion/branches/pin-externals/subversion/libsvn_ra_serf/replay.c?rev=1655005&r1=1655004&r2=1655005&view=diff
==============================================================================
--- subversion/branches/pin-externals/subversion/libsvn_ra_serf/replay.c (original)
+++ subversion/branches/pin-externals/subversion/libsvn_ra_serf/replay.c Tue Jan 27 10:51:52 2015
@@ -112,14 +112,6 @@ static const svn_ra_serf__xml_transition
   { 0 }
 };
 
-/*
- * An incredibly simple list.
- */
-typedef struct ra_serf_list_t {
-  void *data;
-  struct ra_serf_list_t *next;
-} svn_ra_serf__list_t;
-
 /* Per directory/file state */
 typedef struct replay_node_t {
   apr_pool_t *pool; /* pool allocating this node's data */
@@ -141,8 +133,7 @@ typedef struct revision_report_t {
   /* Are we done fetching this file?
      Handles book-keeping in multi-report case */
   svn_boolean_t *done;
-  svn_ra_serf__list_t **done_list;
-  svn_ra_serf__list_t done_item;
+  int *replay_reports; /* NULL or number of outstanding reports */
 
   /* callback to get an editor */
   svn_ra_replay_revstart_callback_t revstart_func;
@@ -173,7 +164,7 @@ typedef struct revision_report_t {
 
   /* Handlers for the PROPFIND and REPORT for the current revision. */
   svn_ra_serf__handler_t *propfind_handler;
-  svn_ra_serf__handler_t *report_handler;
+  svn_ra_serf__handler_t *report_handler; /* For done handler */
 
 } revision_report_t;
 
@@ -478,29 +469,6 @@ replay_cdata(svn_ra_serf__xml_estate_t *
   return SVN_NO_ERROR;
 }
 
-/* Conforms to svn_ra_serf__response_done_delegate_t  */
-static svn_error_t *
-replay_done(serf_request_t *request,
-            void *baton,
-            apr_pool_t *scratch_pool)
-{
-  struct revision_report_t *ctx = baton;
-  svn_ra_serf__handler_t *handler = ctx->report_handler;
-
-  if (handler->server_error)
-    return svn_ra_serf__server_error_create(handler, scratch_pool);
-  else if (handler->sline.code != 200)
-    return svn_error_trace(svn_ra_serf__unexpected_status(handler));
-
-  *ctx->done = TRUE; /* Breaks out svn_ra_serf__context_run_wait */
-
-  ctx->done_item.data = ctx;
-  ctx->done_item.next = *ctx->done_list;
-  *ctx->done_list = &ctx->done_item;
-
-  return SVN_NO_ERROR;
-}
-
 /* Implements svn_ra_serf__request_body_delegate_t */
 static svn_error_t *
 create_replay_body(serf_bucket_t **bkt,
@@ -566,7 +534,7 @@ svn_ra_serf__replay(svn_ra_session_t *ra
   svn_ra_serf__xml_context_t *xmlctx;
   const char *report_target;
 
-  SVN_ERR(svn_ra_serf__report_resource(&report_target, session, NULL,
+  SVN_ERR(svn_ra_serf__report_resource(&report_target, session,
                                        scratch_pool));
 
   ctx.pool = svn_pool_create(scratch_pool);
@@ -584,20 +552,17 @@ svn_ra_serf__replay(svn_ra_session_t *ra
                                            &ctx,
                                            scratch_pool);
 
-  handler = svn_ra_serf__create_expat_handler(xmlctx, NULL, scratch_pool);
+  handler = svn_ra_serf__create_expat_handler(session, xmlctx, NULL,
+                                              scratch_pool);
 
   handler->method = "REPORT";
   handler->path = session->session_url.path;
   handler->body_delegate = create_replay_body;
   handler->body_delegate_baton = &ctx;
   handler->body_type = "text/xml";
-  handler->conn = session->conns[0];
-  handler->session = session;
 
   /* Not setting up done handler as we don't use a global context */
 
-  ctx.report_handler = handler; /* unused */
-
   SVN_ERR(svn_ra_serf__context_run_one(handler, scratch_pool));
 
   return svn_error_trace(
@@ -637,6 +602,33 @@ svn_ra_serf__replay(svn_ra_session_t *ra
  */
 #define MAX_OUTSTANDING_REQUESTS 50
 
+/* Implements svn_ra_serf__response_done_delegate_t for svn_ra_serf__replay_range */
+static svn_error_t *
+replay_done(serf_request_t *request,
+            void *baton,
+            apr_pool_t *scratch_pool)
+{
+  struct revision_report_t *ctx = baton;
+  svn_ra_serf__handler_t *handler = ctx->report_handler;
+
+  if (handler->server_error)
+    return svn_ra_serf__server_error_create(handler, scratch_pool);
+  else if (handler->sline.code != 200)
+    return svn_error_trace(svn_ra_serf__unexpected_status(handler));
+
+  *ctx->done = TRUE; /* Breaks out svn_ra_serf__context_run_wait */
+
+  /* Are re replaying multiple revisions? */
+  if (ctx->replay_reports)
+    {
+      (*ctx->replay_reports)--;
+    }
+
+  svn_pool_destroy(ctx->pool); /* Destroys handler and request! */
+
+  return SVN_NO_ERROR;
+}
+
 svn_error_t *
 svn_ra_serf__replay_range(svn_ra_session_t *ra_session,
                           svn_revnum_t start_revision,
@@ -646,7 +638,7 @@ svn_ra_serf__replay_range(svn_ra_session
                           svn_ra_replay_revstart_callback_t revstart_func,
                           svn_ra_replay_revfinish_callback_t revfinish_func,
                           void *replay_baton,
-                          apr_pool_t *pool)
+                          apr_pool_t *scratch_pool)
 {
   svn_ra_serf__session_t *session = ra_session->priv;
   svn_revnum_t rev = start_revision;
@@ -654,9 +646,9 @@ svn_ra_serf__replay_range(svn_ra_session
   int active_reports = 0;
   const char *include_path;
   svn_boolean_t done;
-  svn_ra_serf__list_t *done_reports = NULL;
 
-  SVN_ERR(svn_ra_serf__report_resource(&report_target, session, NULL, pool));
+  SVN_ERR(svn_ra_serf__report_resource(&report_target, session,
+                                       scratch_pool));
 
   /* Prior to 1.8, mod_dav_svn expect to get replay REPORT requests
      aimed at the session URL.  But that's incorrect -- these reports
@@ -679,8 +671,7 @@ svn_ra_serf__replay_range(svn_ra_session
     {
       SVN_ERR(svn_ra_serf__get_relative_path(&include_path,
                                              session->session_url.path,
-                                             session, session->conns[0],
-                                             pool));
+                                             session, scratch_pool));
     }
   else
     {
@@ -698,30 +689,29 @@ svn_ra_serf__replay_range(svn_ra_session
         {
           struct revision_report_t *rev_ctx;
           svn_ra_serf__handler_t *handler;
-          apr_pool_t *ctx_pool = svn_pool_create(pool);
+          apr_pool_t *rev_pool = svn_pool_create(scratch_pool);
           svn_ra_serf__xml_context_t *xmlctx;
           const char *replay_target;
 
-          rev_ctx = apr_pcalloc(ctx_pool, sizeof(*rev_ctx));
-          rev_ctx->pool = ctx_pool;
+          rev_ctx = apr_pcalloc(rev_pool, sizeof(*rev_ctx));
+          rev_ctx->pool = rev_pool;
           rev_ctx->revstart_func = revstart_func;
           rev_ctx->revfinish_func = revfinish_func;
           rev_ctx->replay_baton = replay_baton;
           rev_ctx->done = &done;
-          rev_ctx->done_list = &done_reports;
+          rev_ctx->replay_reports = &active_reports;
           rev_ctx->include_path = include_path;
           rev_ctx->revision = rev;
           rev_ctx->low_water_mark = low_water_mark;
           rev_ctx->send_deltas = send_deltas;
-          rev_ctx->done_item.data = rev_ctx;
 
           /* Request all properties of a certain revision. */
           rev_ctx->rev_props = apr_hash_make(rev_ctx->pool);
 
           if (SVN_RA_SERF__HAVE_HTTPV2_SUPPORT(session))
             {
-              rev_ctx->revprop_target = apr_psprintf(pool, "%s/%ld",
-                                                        session->rev_stub, rev);
+              rev_ctx->revprop_target = apr_psprintf(rev_pool, "%s/%ld",
+                                                     session->rev_stub, rev);
               rev_ctx->revprop_rev = SVN_INVALID_REVNUM;
             }
           else
@@ -730,14 +720,15 @@ svn_ra_serf__replay_range(svn_ra_session
               rev_ctx->revprop_rev = rev;
             }
 
-          SVN_ERR(svn_ra_serf__deliver_props2(&rev_ctx->propfind_handler,
-                                              session, session->conns[0],
+          SVN_ERR(svn_ra_serf__create_propfind_handler(
+                                              &rev_ctx->propfind_handler,
+                                              session,
                                               rev_ctx->revprop_target,
                                               rev_ctx->revprop_rev,
                                               "0", all_props,
                                               svn_ra_serf__deliver_svn_props,
                                               rev_ctx->rev_props,
-                                              rev_ctx->pool));
+                                              rev_pool));
 
           /* Spin up the serf request for the PROPFIND.  */
           svn_ra_serf__request_create(rev_ctx->propfind_handler);
@@ -745,7 +736,7 @@ svn_ra_serf__replay_range(svn_ra_session
           /* Send the replay REPORT request. */
           if (session->supports_rev_rsrc_replay)
             {
-              replay_target = apr_psprintf(pool, "%s/%ld",
+              replay_target = apr_psprintf(rev_pool, "%s/%ld",
                                            session->rev_stub, rev);
             }
           else
@@ -756,16 +747,15 @@ svn_ra_serf__replay_range(svn_ra_session
           xmlctx = svn_ra_serf__xml_context_create(replay_ttable,
                                            replay_opened, replay_closed,
                                            replay_cdata, rev_ctx,
-                                           ctx_pool);
+                                           rev_pool);
 
-          handler = svn_ra_serf__create_expat_handler(xmlctx, NULL, ctx_pool);
+          handler = svn_ra_serf__create_expat_handler(session, xmlctx, NULL,
+                                                      rev_pool);
 
           handler->method = "REPORT";
           handler->path = replay_target;
           handler->body_delegate = create_replay_body;
           handler->body_delegate_baton = rev_ctx;
-          handler->conn = session->conns[0];
-          handler->session = session;
 
           handler->done_delegate = replay_done;
           handler->done_delegate_baton = rev_ctx;
@@ -779,31 +769,11 @@ svn_ra_serf__replay_range(svn_ra_session
 
       /* Run the serf loop. */
       done = FALSE;
-      SVN_ERR(svn_ra_serf__context_run_wait(&done, session, pool));
+      SVN_ERR(svn_ra_serf__context_run_wait(&done, session, scratch_pool));
 
-      /* Substract the number of completely handled responses from our
-         total nr. of open requests', so we'll know when to stop this loop.
-         Since the message is completely handled, we can destroy its pool. */
-      {
-        svn_ra_serf__list_t *done_list;
-
-        done_list = done_reports;
-
-        done_reports = NULL;
-
-        while (done_list)
-          {
-            revision_report_t *ctx = (revision_report_t *)done_list->data;
-            svn_ra_serf__handler_t *done_handler = ctx->report_handler;
-
-            done_list = done_list->next;
-            SVN_ERR(svn_ra_serf__error_on_status(done_handler->sline,
-                                                 done_handler->path,
-                                                 done_handler->location));
-            svn_pool_clear(ctx->pool);
-            active_reports--;
-          }
-      }
+      /* The done handler of reports decrements active_reports when a report
+         is done. This same handler reports (fatal) report errors, so we can
+         just loop here. */
     }
 
   return SVN_NO_ERROR;

Modified: subversion/branches/pin-externals/subversion/libsvn_ra_serf/serf.c
URL: http://svn.apache.org/viewvc/subversion/branches/pin-externals/subversion/libsvn_ra_serf/serf.c?rev=1655005&r1=1655004&r2=1655005&view=diff
==============================================================================
--- subversion/branches/pin-externals/subversion/libsvn_ra_serf/serf.c (original)
+++ subversion/branches/pin-externals/subversion/libsvn_ra_serf/serf.c Tue Jan 27 10:51:52 2015
@@ -801,7 +801,7 @@ svn_ra_serf__reparent(svn_ra_session_t *
   if (!session->repos_root_str)
     {
       const char *vcc_url;
-      SVN_ERR(svn_ra_serf__discover_vcc(&vcc_url, session, NULL, pool));
+      SVN_ERR(svn_ra_serf__discover_vcc(&vcc_url, session, pool));
     }
 
   if (!svn_uri__is_ancestor(session->repos_root_str, url))
@@ -887,16 +887,19 @@ serf__rev_proplist(svn_ra_session_t *ra_
   else
     {
       /* Use the VCC as the propfind target path. */
-      SVN_ERR(svn_ra_serf__discover_vcc(&propfind_path, session, NULL,
+      SVN_ERR(svn_ra_serf__discover_vcc(&propfind_path, session,
                                         scratch_pool));
     }
 
   props = apr_hash_make(result_pool);
-  SVN_ERR(svn_ra_serf__deliver_props2(&handler, session, session->conns[0],
-                                      propfind_path, rev, "0", fetch_props,
-                                      svn_ra_serf__deliver_svn_props, props,
-                                      scratch_pool));
-  SVN_ERR(svn_ra_serf__wait_for_props(handler, scratch_pool));
+  SVN_ERR(svn_ra_serf__create_propfind_handler(&handler, session,
+                                               propfind_path, rev, "0",
+                                               fetch_props,
+                                               svn_ra_serf__deliver_svn_props,
+                                               props,
+                                               scratch_pool));
+
+  SVN_ERR(svn_ra_serf__context_run_one(handler, scratch_pool));
 
   svn_ra_serf__keep_only_regular_props(props, scratch_pool);
 
@@ -971,7 +974,7 @@ svn_ra_serf__get_repos_root(svn_ra_sessi
   if (!session->repos_root_str)
     {
       const char *vcc_url;
-      SVN_ERR(svn_ra_serf__discover_vcc(&vcc_url, session, NULL, pool));
+      SVN_ERR(svn_ra_serf__discover_vcc(&vcc_url, session, pool));
     }
 
   *url = session->repos_root_str;
@@ -1007,7 +1010,7 @@ svn_ra_serf__get_uuid(svn_ra_session_t *
 
       /* We're not interested in vcc_url and relative_url, but this call also
          stores the repository's uuid in the session. */
-      SVN_ERR(svn_ra_serf__discover_vcc(&vcc_url, session, NULL, pool));
+      SVN_ERR(svn_ra_serf__discover_vcc(&vcc_url, session, pool));
       if (!session->uuid)
         {
           return svn_error_create(SVN_ERR_RA_DAV_RESPONSE_HEADER_BADNESS, NULL,

Modified: subversion/branches/pin-externals/subversion/libsvn_ra_serf/stat.c
URL: http://svn.apache.org/viewvc/subversion/branches/pin-externals/subversion/libsvn_ra_serf/stat.c?rev=1655005&r1=1655004&r2=1655005&view=diff
==============================================================================
--- subversion/branches/pin-externals/subversion/libsvn_ra_serf/stat.c (original)
+++ subversion/branches/pin-externals/subversion/libsvn_ra_serf/stat.c Tue Jan 27 10:51:52 2015
@@ -48,57 +48,41 @@
 
 
 
-static svn_error_t *
-fetch_path_props(apr_hash_t **props,
-                 svn_ra_serf__session_t *session,
-                 const char *session_relpath,
-                 svn_revnum_t revision,
-                 const svn_ra_serf__dav_props_t *desired_props,
-                 apr_pool_t *result_pool,
-                 apr_pool_t *scratch_pool)
+/* Implements svn_ra__vtable_t.check_path(). */
+svn_error_t *
+svn_ra_serf__check_path(svn_ra_session_t *ra_session,
+                        const char *relpath,
+                        svn_revnum_t revision,
+                        svn_node_kind_t *kind,
+                        apr_pool_t *scratch_pool)
 {
+  svn_ra_serf__session_t *session = ra_session->priv;
+  apr_hash_t *props;
+  svn_error_t *err;
   const char *url;
 
   url = session->session_url.path;
 
   /* If we have a relative path, append it. */
-  if (session_relpath)
-    url = svn_path_url_add_component2(url, session_relpath, scratch_pool);
+  if (relpath)
+    url = svn_path_url_add_component2(url, relpath, scratch_pool);
 
   /* If we were given a specific revision, get a URL that refers to that
      specific revision (rather than floating with HEAD).  */
   if (SVN_IS_VALID_REVNUM(revision))
     {
       SVN_ERR(svn_ra_serf__get_stable_url(&url, NULL /* latest_revnum */,
-                                          session, NULL /* conn */,
+                                          session,
                                           url, revision,
                                           scratch_pool, scratch_pool));
     }
 
   /* URL is stable, so we use SVN_INVALID_REVNUM since it is now irrelevant.
      Or we started with SVN_INVALID_REVNUM and URL may be floating.  */
-  SVN_ERR(svn_ra_serf__fetch_node_props(props, session->conns[0],
-                                        url, SVN_INVALID_REVNUM,
-                                        desired_props,
-                                        result_pool, scratch_pool));
-
-  return SVN_NO_ERROR;
-}
-
-/* Implements svn_ra__vtable_t.check_path(). */
-svn_error_t *
-svn_ra_serf__check_path(svn_ra_session_t *ra_session,
-                        const char *rel_path,
-                        svn_revnum_t revision,
-                        svn_node_kind_t *kind,
-                        apr_pool_t *pool)
-{
-  svn_ra_serf__session_t *session = ra_session->priv;
-  apr_hash_t *props;
-
-  svn_error_t *err = fetch_path_props(&props, session, rel_path,
-                                      revision, check_path_props,
-                                      pool, pool);
+  err = svn_ra_serf__fetch_node_props(&props, session,
+                                      url, SVN_INVALID_REVNUM,
+                                      check_path_props,
+                                      scratch_pool, scratch_pool);
 
   if (err && err->apr_err == SVN_ERR_FS_NOT_FOUND)
     {
@@ -107,18 +91,35 @@ svn_ra_serf__check_path(svn_ra_session_t
     }
   else
     {
+      apr_hash_t *dav_props;
+      const char *res_type;
+
       /* Any other error, raise to caller. */
-      if (err)
-        return svn_error_trace(err);
+      SVN_ERR(err);
 
-      SVN_ERR(svn_ra_serf__get_resource_type(kind, props));
+      dav_props = apr_hash_get(props, "DAV:", 4);
+      res_type = svn_prop_get_value(dav_props, "resourcetype");
+      if (!res_type)
+        {
+          /* How did this happen? */
+          return svn_error_create(SVN_ERR_RA_DAV_PROPS_NOT_FOUND, NULL,
+                                 _("The PROPFIND response did not include the "
+                                   "requested resourcetype value"));
+        }
+
+      if (strcmp(res_type, "collection") == 0)
+        *kind = svn_node_dir;
+      else
+        *kind = svn_node_file;
     }
 
   return SVN_NO_ERROR;
 }
 
 
-struct dirent_walker_baton_t {
+/* Baton for fill_dirent_propfunc() */
+struct fill_dirent_baton_t
+{
   /* Update the fields in this entry.  */
   svn_dirent_t *entry;
 
@@ -128,76 +129,78 @@ struct dirent_walker_baton_t {
   apr_pool_t *result_pool;
 };
 
+/* Implements svn_ra_serf__prop_func_t */
 static svn_error_t *
-dirent_walker(void *baton,
-              const char *ns,
-              const char *name,
-              const svn_string_t *val,
-              apr_pool_t *scratch_pool)
+fill_dirent_propfunc(void *baton,
+                     const char *path,
+                     const char *ns,
+                     const char *name,
+                     const svn_string_t *val,
+                     apr_pool_t *scratch_pool)
 {
-  struct dirent_walker_baton_t *dwb = baton;
+  struct fill_dirent_baton_t *fdb = baton;
 
-  if (strcmp(ns, SVN_DAV_PROP_NS_CUSTOM) == 0)
-    {
-      dwb->entry->has_props = TRUE;
-    }
-  else if (strcmp(ns, SVN_DAV_PROP_NS_SVN) == 0)
-    {
-      dwb->entry->has_props = TRUE;
-    }
-  else if (strcmp(ns, SVN_DAV_PROP_NS_DAV) == 0)
-    {
-      if(strcmp(name, "deadprop-count") == 0)
-        {
-          if (*val->data)
-            {
-              apr_int64_t deadprop_count;
-              SVN_ERR(svn_cstring_atoi64(&deadprop_count, val->data));
-              dwb->entry->has_props = deadprop_count > 0;
-              if (dwb->supports_deadprop_count)
-                *dwb->supports_deadprop_count = svn_tristate_true;
-            }
-          else if (dwb->supports_deadprop_count)
-            *dwb->supports_deadprop_count = svn_tristate_false;
-        }
-    }
-  else if (strcmp(ns, "DAV:") == 0)
+  if (strcmp(ns, "DAV:") == 0)
     {
       if (strcmp(name, SVN_DAV__VERSION_NAME) == 0)
         {
           apr_int64_t rev;
           SVN_ERR(svn_cstring_atoi64(&rev, val->data));
 
-          dwb->entry->created_rev = (svn_revnum_t)rev;
+          fdb->entry->created_rev = (svn_revnum_t)rev;
         }
       else if (strcmp(name, "creator-displayname") == 0)
         {
-          dwb->entry->last_author = apr_pstrdup(dwb->result_pool, val->data);
+          fdb->entry->last_author = apr_pstrdup(fdb->result_pool, val->data);
         }
       else if (strcmp(name, SVN_DAV__CREATIONDATE) == 0)
         {
-          SVN_ERR(svn_time_from_cstring(&dwb->entry->time,
+          SVN_ERR(svn_time_from_cstring(&fdb->entry->time,
                                         val->data,
-                                        dwb->result_pool));
+                                        fdb->result_pool));
         }
       else if (strcmp(name, "getcontentlength") == 0)
         {
           /* 'getcontentlength' property is empty for directories. */
           if (val->len)
             {
-              SVN_ERR(svn_cstring_atoi64(&dwb->entry->size, val->data));
+              SVN_ERR(svn_cstring_atoi64(&fdb->entry->size, val->data));
             }
         }
       else if (strcmp(name, "resourcetype") == 0)
         {
           if (strcmp(val->data, "collection") == 0)
             {
-              dwb->entry->kind = svn_node_dir;
+              fdb->entry->kind = svn_node_dir;
             }
           else
             {
-              dwb->entry->kind = svn_node_file;
+              fdb->entry->kind = svn_node_file;
+            }
+        }
+    }
+  else if (strcmp(ns, SVN_DAV_PROP_NS_CUSTOM) == 0)
+    {
+      fdb->entry->has_props = TRUE;
+    }
+  else if (strcmp(ns, SVN_DAV_PROP_NS_SVN) == 0)
+    {
+      fdb->entry->has_props = TRUE;
+    }
+  else if (strcmp(ns, SVN_DAV_PROP_NS_DAV) == 0)
+    {
+      if(strcmp(name, "deadprop-count") == 0)
+        {
+          if (*val->data)
+            {
+              apr_int64_t deadprop_count;
+              SVN_ERR(svn_cstring_atoi64(&deadprop_count, val->data));
+              fdb->entry->has_props = deadprop_count > 0;
+              if (fdb->supports_deadprop_count)
+                *fdb->supports_deadprop_count = svn_tristate_true;
             }
+          else if (fdb->supports_deadprop_count)
+            *fdb->supports_deadprop_count = svn_tristate_false;
         }
     }
 
@@ -279,21 +282,47 @@ get_dirent_props(apr_uint32_t dirent_fie
 /* Implements svn_ra__vtable_t.stat(). */
 svn_error_t *
 svn_ra_serf__stat(svn_ra_session_t *ra_session,
-                  const char *rel_path,
+                  const char *relpath,
                   svn_revnum_t revision,
                   svn_dirent_t **dirent,
                   apr_pool_t *pool)
 {
   svn_ra_serf__session_t *session = ra_session->priv;
-  apr_hash_t *props;
   svn_error_t *err;
-  struct dirent_walker_baton_t dwb;
+  struct fill_dirent_baton_t fdb;
   svn_tristate_t deadprop_count = svn_tristate_unknown;
+  svn_ra_serf__handler_t *handler;
+  const char *url;
+
+  url = session->session_url.path;
+
+  /* If we have a relative path, append it. */
+  if (relpath)
+    url = svn_path_url_add_component2(url, relpath, pool);
+
+  /* If we were given a specific revision, get a URL that refers to that
+     specific revision (rather than floating with HEAD).  */
+  if (SVN_IS_VALID_REVNUM(revision))
+    {
+      SVN_ERR(svn_ra_serf__get_stable_url(&url, NULL /* latest_revnum */,
+                                          session,
+                                          url, revision,
+                                          pool, pool));
+    }
+
+  fdb.entry = svn_dirent_create(pool);
+  fdb.supports_deadprop_count = &deadprop_count;
+  fdb.result_pool = pool;
+
+  SVN_ERR(svn_ra_serf__create_propfind_handler(&handler, session, url,
+                                               SVN_INVALID_REVNUM, "0",
+                                               get_dirent_props(SVN_DIRENT_ALL,
+                                                                session,
+                                                                pool),
+                                               fill_dirent_propfunc, &fdb, pool));
+
+  err = svn_ra_serf__context_run_one(handler, pool);
 
-  err = fetch_path_props(&props,
-                         session, rel_path, revision,
-                         get_dirent_props(SVN_DIRENT_ALL, session, pool),
-                         pool, pool);
   if (err)
     {
       if (err->apr_err == SVN_ERR_FS_NOT_FOUND)
@@ -306,31 +335,22 @@ svn_ra_serf__stat(svn_ra_session_t *ra_s
         return svn_error_trace(err);
     }
 
-  dwb.entry = svn_dirent_create(pool);
-  dwb.supports_deadprop_count = &deadprop_count;
-  dwb.result_pool = pool;
-  SVN_ERR(svn_ra_serf__walk_node_props(props, dirent_walker, &dwb, pool));
-
   if (deadprop_count == svn_tristate_false
       && session->supports_deadprop_count == svn_tristate_unknown
-      && !dwb.entry->has_props)
+      && !fdb.entry->has_props)
     {
       /* We have to requery as the server didn't give us the right
          information */
       session->supports_deadprop_count = svn_tristate_false;
 
-      SVN_ERR(fetch_path_props(&props,
-                               session, rel_path, SVN_INVALID_REVNUM,
-                               get_dirent_props(SVN_DIRENT_ALL, session, pool),
-                               pool, pool));
-
-      SVN_ERR(svn_ra_serf__walk_node_props(props, dirent_walker, &dwb, pool));
+      /* Run the same handler again */
+      SVN_ERR(svn_ra_serf__context_run_one(handler, pool));
     }
 
   if (deadprop_count != svn_tristate_unknown)
     session->supports_deadprop_count = deadprop_count;
 
-  *dirent = dwb.entry;
+  *dirent = fdb.entry;
 
   return SVN_NO_ERROR;
 }
@@ -346,7 +366,7 @@ struct get_dir_baton_t
   const char *path;
 };
 
-/* Implements svn_ra_serf__prop_func */
+/* Implements svn_ra_serf__prop_func_t */
 static svn_error_t *
 get_dir_dirents_cb(void *baton,
                    const char *path,
@@ -362,22 +382,22 @@ get_dir_dirents_cb(void *baton,
 
   if (relpath && relpath[0] != '\0')
     {
-      struct dirent_walker_baton_t dwb;
+      struct fill_dirent_baton_t fdb;
 
       relpath = svn_path_uri_decode(relpath, scratch_pool);
-      dwb.entry = svn_hash_gets(db->dirents, relpath);
+      fdb.entry = svn_hash_gets(db->dirents, relpath);
 
-      if (!dwb.entry)
+      if (!fdb.entry)
         {
-          dwb.entry = svn_dirent_create(db->result_pool);
+          fdb.entry = svn_dirent_create(db->result_pool);
           svn_hash_sets(db->dirents,
                         apr_pstrdup(db->result_pool, relpath),
-                        dwb.entry);
+                        fdb.entry);
         }
 
-      dwb.result_pool = db->result_pool;
-      dwb.supports_deadprop_count = &db->supports_deadprop_count;
-      SVN_ERR(dirent_walker(&dwb, ns, name, value, scratch_pool));
+      fdb.result_pool = db->result_pool;
+      fdb.supports_deadprop_count = &db->supports_deadprop_count;
+      SVN_ERR(fill_dirent_propfunc(&fdb, path, ns, name, value, scratch_pool));
     }
   else if (relpath && !db->is_directory)
     {
@@ -471,7 +491,7 @@ svn_ra_serf__get_dir(svn_ra_session_t *r
   if (SVN_IS_VALID_REVNUM(revision) || fetched_rev)
     {
       SVN_ERR(svn_ra_serf__get_stable_url(&path, fetched_rev,
-                                          session, NULL /* conn */,
+                                          session,
                                           path, revision,
                                           scratch_pool, scratch_pool));
       revision = SVN_INVALID_REVNUM;
@@ -491,8 +511,8 @@ svn_ra_serf__get_dir(svn_ra_session_t *r
 
       gdb.dirents = apr_hash_make(result_pool);
 
-      SVN_ERR(svn_ra_serf__deliver_props2(&dirent_handler,
-                                          session, session->conns[0],
+      SVN_ERR(svn_ra_serf__create_propfind_handler(
+                                          &dirent_handler, session,
                                           path, SVN_INVALID_REVNUM, "1",
                                           get_dirent_props(dirent_fields,
                                                            session,
@@ -508,8 +528,8 @@ svn_ra_serf__get_dir(svn_ra_session_t *r
   if (ret_props)
     {
       gdb.ret_props = apr_hash_make(result_pool);
-      SVN_ERR(svn_ra_serf__deliver_props2(&props_handler,
-                                          session, session->conns[0],
+      SVN_ERR(svn_ra_serf__create_propfind_handler(
+                                          &props_handler, session,
                                           path, SVN_INVALID_REVNUM, "0",
                                           all_props,
                                           get_dir_props_cb, &gdb,
@@ -526,9 +546,6 @@ svn_ra_serf__get_dir(svn_ra_session_t *r
                                             session,
                                             scratch_pool));
 
-      if (dirent_handler->sline.code != 207)
-        return svn_error_trace(svn_ra_serf__unexpected_status(dirent_handler));
-
       if (gdb.supports_deadprop_count == svn_tristate_false
           && session->supports_deadprop_count == svn_tristate_unknown
           && dirent_fields & SVN_DIRENT_HAS_PROPS)
@@ -539,8 +556,8 @@ svn_ra_serf__get_dir(svn_ra_session_t *r
 
           apr_hash_clear(gdb.dirents);
 
-          SVN_ERR(svn_ra_serf__deliver_props2(&dirent_handler,
-                                              session, session->conns[0],
+          SVN_ERR(svn_ra_serf__create_propfind_handler(
+                                              &dirent_handler, session,
                                               path, SVN_INVALID_REVNUM, "1",
                                               get_dirent_props(dirent_fields,
                                                                session,
@@ -557,9 +574,6 @@ svn_ra_serf__get_dir(svn_ra_session_t *r
       SVN_ERR(svn_ra_serf__context_run_wait(&props_handler->done,
                                             session,
                                             scratch_pool));
-
-      if (props_handler->sline.code != 207)
-        return svn_error_trace(svn_ra_serf__unexpected_status(props_handler));
     }
 
   /* And dirent again for the case when we had to send the request again */
@@ -568,9 +582,6 @@ svn_ra_serf__get_dir(svn_ra_session_t *r
       SVN_ERR(svn_ra_serf__context_run_wait(&dirent_handler->done,
                                             session,
                                             scratch_pool));
-
-      if (dirent_handler->sline.code != 207)
-        return svn_error_trace(svn_ra_serf__unexpected_status(dirent_handler));
     }
 
   if (gdb.supports_deadprop_count != svn_tristate_unknown)

Modified: subversion/branches/pin-externals/subversion/libsvn_ra_serf/update.c
URL: http://svn.apache.org/viewvc/subversion/branches/pin-externals/subversion/libsvn_ra_serf/update.c?rev=1655005&r1=1655004&r2=1655005&view=diff
==============================================================================
--- subversion/branches/pin-externals/subversion/libsvn_ra_serf/update.c (original)
+++ subversion/branches/pin-externals/subversion/libsvn_ra_serf/update.c Tue Jan 27 10:51:52 2015
@@ -1429,7 +1429,7 @@ fetch_for_file(file_baton_t *file,
                                                        file->base_rev,
                                                        svn_path_uri_encode(
                                                           file->repos_relpath,
-                                                          file->pool));
+                                                          scratch_pool));
                 }
               else if (file->copyfrom_path)
                 {
@@ -1440,7 +1440,7 @@ fetch_for_file(file_baton_t *file,
                                                        file->copyfrom_rev,
                                                        svn_path_uri_encode(
                                                           file->copyfrom_path+1,
-                                                          file->pool));
+                                                          scratch_pool));
                 }
             }
           else if (ctx->sess->wc_callbacks->get_wc_prop)
@@ -1461,13 +1461,12 @@ fetch_for_file(file_baton_t *file,
                                         : NULL;
             }
 
-          handler = svn_ra_serf__create_handler(file->pool);
+          handler = svn_ra_serf__create_handler(ctx->sess, file->pool);
 
           handler->method = "GET";
           handler->path = file->url;
 
-          handler->conn = conn;
-          handler->session = ctx->sess;
+          handler->conn = conn; /* Explicit scheduling */
 
           handler->custom_accept_encoding = TRUE;
           handler->no_dav_headers = TRUE;
@@ -1494,12 +1493,13 @@ fetch_for_file(file_baton_t *file,
   /* If needed, create the PROPFIND to retrieve the file's properties. */
   if (file->fetch_props)
     {
-      SVN_ERR(svn_ra_serf__deliver_props2(&file->propfind_handler,
-                                          ctx->sess, conn, file->url,
-                                          ctx->target_rev, "0", all_props,
-                                          set_file_props, file,
-                                          file->pool));
-      SVN_ERR_ASSERT(file->propfind_handler);
+      SVN_ERR(svn_ra_serf__create_propfind_handler(&file->propfind_handler,
+                                                   ctx->sess, file->url,
+                                                   ctx->target_rev, "0",
+                                                   all_props,
+                                                   set_file_props, file,
+                                                   file->pool));
+      file->propfind_handler->conn = conn; /* Explicit scheduling */
 
       file->propfind_handler->done_delegate = file_props_done;
       file->propfind_handler->done_delegate_baton = file;
@@ -1591,13 +1591,14 @@ fetch_for_dir(dir_baton_t *dir,
   /* If needed, create the PROPFIND to retrieve the file's properties. */
   if (dir->fetch_props)
     {
-      SVN_ERR(svn_ra_serf__deliver_props2(&dir->propfind_handler,
-                                          ctx->sess, conn, dir->url,
-                                          ctx->target_rev, "0", all_props,
-                                          set_dir_prop, dir,
-                                          dir->pool));
-      SVN_ERR_ASSERT(dir->propfind_handler);
+      SVN_ERR(svn_ra_serf__create_propfind_handler(&dir->propfind_handler,
+                                                   ctx->sess, dir->url,
+                                                   ctx->target_rev, "0",
+                                                   all_props,
+                                                   set_dir_prop, dir,
+                                                   dir->pool));
 
+      dir->propfind_handler->conn = conn;
       dir->propfind_handler->done_delegate = dir_props_done;
       dir->propfind_handler->done_delegate_baton = dir;
 
@@ -2262,10 +2263,8 @@ link_path(void *report_baton,
                                _("Unable to parse URL '%s'"), url);
     }
 
-  SVN_ERR(svn_ra_serf__report_resource(&report_target, report->sess,
-                                       NULL, pool));
-  SVN_ERR(svn_ra_serf__get_relative_path(&link, uri.path, report->sess,
-                                         NULL, pool));
+  SVN_ERR(svn_ra_serf__report_resource(&report_target, report->sess, pool));
+  SVN_ERR(svn_ra_serf__get_relative_path(&link, uri.path, report->sess, pool));
 
   link = apr_pstrcat(pool, "/", link, SVN_VA_NULL);
 
@@ -2657,15 +2656,15 @@ finish_report(void *report_baton,
   SVN_ERR(svn_stream_write(report->body_template, buf->data, &buf->len));
   SVN_ERR(svn_stream_close(report->body_template));
 
-  SVN_ERR(svn_ra_serf__report_resource(&report_target, sess, NULL,
-                                       scratch_pool));
+  SVN_ERR(svn_ra_serf__report_resource(&report_target, sess,  scratch_pool));
 
   xmlctx = svn_ra_serf__xml_context_create(update_ttable,
                                            update_opened, update_closed,
                                            update_cdata,
                                            report,
                                            scratch_pool);
-  handler = svn_ra_serf__create_expat_handler(xmlctx, NULL, scratch_pool);
+  handler = svn_ra_serf__create_expat_handler(sess, xmlctx, NULL,
+                                              scratch_pool);
 
   handler->method = "REPORT";
   handler->path = report_target;
@@ -2675,8 +2674,6 @@ finish_report(void *report_baton,
   handler->custom_accept_encoding = TRUE;
   handler->header_delegate = setup_update_report_headers;
   handler->header_delegate_baton = report;
-  handler->conn = sess->conns[0];
-  handler->session = sess;
 
   svn_ra_serf__request_create(handler);
 

Modified: subversion/branches/pin-externals/subversion/libsvn_ra_serf/util.c
URL: http://svn.apache.org/viewvc/subversion/branches/pin-externals/subversion/libsvn_ra_serf/util.c?rev=1655005&r1=1655004&r2=1655005&view=diff
==============================================================================
--- subversion/branches/pin-externals/subversion/libsvn_ra_serf/util.c (original)
+++ subversion/branches/pin-externals/subversion/libsvn_ra_serf/util.c Tue Jan 27 10:51:52 2015
@@ -567,6 +567,7 @@ accept_response(serf_request_t *request,
                 void *acceptor_baton,
                 apr_pool_t *pool)
 {
+  /* svn_ra_serf__handler_t *handler = acceptor_baton; */
   serf_bucket_t *c;
   serf_bucket_alloc_t *bkt_alloc;
 
@@ -584,6 +585,7 @@ accept_head(serf_request_t *request,
             void *acceptor_baton,
             apr_pool_t *pool)
 {
+  /* svn_ra_serf__handler_t *handler = acceptor_baton; */
   serf_bucket_t *response;
 
   response = accept_response(request, stream, acceptor_baton, pool);
@@ -601,7 +603,7 @@ connection_closed(svn_ra_serf__connectio
 {
   if (why)
     {
-      return svn_error_wrap_apr(why, NULL);
+      return svn_ra_serf__wrap_err(why, NULL);
     }
 
   if (conn->session->using_ssl)
@@ -831,9 +833,14 @@ setup_serf_req(serf_request_t *request,
       serf_bucket_headers_setn(*hdrs_bkt, "Accept-Encoding", accept_encoding);
     }
 
-  /* These headers need to be sent with every request except GET; see
+  /* These headers need to be sent with every request that might need
+     capability processing (e.g. during commit, reports, etc.), see
      issue #3255 ("mod_dav_svn does not pass client capabilities to
-     start-commit hooks") for why. */
+     start-commit hooks") for why.
+
+     Some request types like GET/HEAD/PROPFIND are unaware of capability
+     handling; and in some cases the responses can even be cached by
+     proxies, so we don't have to send these hearders there. */
   if (dav_headers)
     {
       serf_bucket_headers_setn(*hdrs_bkt, "DAV", SVN_DAV_NS_DAV_SVN_DEPTH);
@@ -1534,7 +1541,7 @@ setup_request_cb(serf_request_t *request
     *acceptor = accept_head;
   else
     *acceptor = accept_response;
-  *acceptor_baton = handler->session;
+  *acceptor_baton = handler;
 
   *s_handler = handle_response_cb;
   *s_handler_baton = handler;
@@ -1580,8 +1587,7 @@ svn_ra_serf__request_create(svn_ra_serf_
 svn_error_t *
 svn_ra_serf__discover_vcc(const char **vcc_url,
                           svn_ra_serf__session_t *session,
-                          svn_ra_serf__connection_t *conn,
-                          apr_pool_t *pool)
+                          apr_pool_t *scratch_pool)
 {
   const char *path;
   const char *relative_path;
@@ -1594,12 +1600,6 @@ svn_ra_serf__discover_vcc(const char **v
       return SVN_NO_ERROR;
     }
 
-  /* If no connection is provided, use the default one. */
-  if (! conn)
-    {
-      conn = session->conns[0];
-    }
-
   path = session->session_url.path;
   *vcc_url = NULL;
   uuid = NULL;
@@ -1609,9 +1609,10 @@ svn_ra_serf__discover_vcc(const char **v
       apr_hash_t *props;
       svn_error_t *err;
 
-      err = svn_ra_serf__fetch_node_props(&props, conn,
+      err = svn_ra_serf__fetch_node_props(&props, session,
                                           path, SVN_INVALID_REVNUM,
-                                          base_props, pool, pool);
+                                          base_props,
+                                          scratch_pool, scratch_pool);
       if (! err)
         {
           apr_hash_t *ns_props;
@@ -1639,7 +1640,7 @@ svn_ra_serf__discover_vcc(const char **v
               svn_error_clear(err);
 
               /* Okay, strip off a component from PATH. */
-              path = svn_urlpath__dirname(path, pool);
+              path = svn_urlpath__dirname(path, scratch_pool);
             }
         }
     }
@@ -1665,7 +1666,7 @@ svn_ra_serf__discover_vcc(const char **v
     {
       svn_stringbuf_t *url_buf;
 
-      url_buf = svn_stringbuf_create(path, pool);
+      url_buf = svn_stringbuf_create(path, scratch_pool);
 
       svn_path_remove_components(url_buf,
                                  svn_path_component_count(relative_path));
@@ -1693,7 +1694,6 @@ svn_error_t *
 svn_ra_serf__get_relative_path(const char **rel_path,
                                const char *orig_path,
                                svn_ra_serf__session_t *session,
-                               svn_ra_serf__connection_t *conn,
                                apr_pool_t *pool)
 {
   const char *decoded_root, *decoded_orig;
@@ -1710,7 +1710,6 @@ svn_ra_serf__get_relative_path(const cha
          promises to populate the session's root-url cache, and that's
          what we really want. */
       SVN_ERR(svn_ra_serf__discover_vcc(&vcc_url, session,
-                                        conn ? conn : session->conns[0],
                                         pool));
     }
 
@@ -1724,7 +1723,6 @@ svn_ra_serf__get_relative_path(const cha
 svn_error_t *
 svn_ra_serf__report_resource(const char **report_target,
                              svn_ra_serf__session_t *session,
-                             svn_ra_serf__connection_t *conn,
                              apr_pool_t *pool)
 {
   /* If we have HTTP v2 support, we want to report against the 'me'
@@ -1734,7 +1732,7 @@ svn_ra_serf__report_resource(const char
 
   /* Otherwise, we'll use the default VCC. */
   else
-    SVN_ERR(svn_ra_serf__discover_vcc(report_target, session, conn, pool));
+    SVN_ERR(svn_ra_serf__discover_vcc(report_target, session, pool));
 
   return SVN_NO_ERROR;
 }
@@ -1839,7 +1837,7 @@ svn_ra_serf__register_editor_shim_callba
   return SVN_NO_ERROR;
 }
 
-/* Shandard done_delegate handler */
+/* Shared/standard done_delegate handler */
 static svn_error_t *
 response_done(serf_request_t *request,
               void *handler_baton,
@@ -1887,7 +1885,8 @@ handler_cleanup(void *baton)
 }
 
 svn_ra_serf__handler_t *
-svn_ra_serf__create_handler(apr_pool_t *result_pool)
+svn_ra_serf__create_handler(svn_ra_serf__session_t *session,
+                            apr_pool_t *result_pool)
 {
   svn_ra_serf__handler_t *handler;
 
@@ -1897,6 +1896,9 @@ svn_ra_serf__create_handler(apr_pool_t *
   apr_pool_cleanup_register(result_pool, handler, handler_cleanup,
                             apr_pool_cleanup_null);
 
+  handler->session = session;
+  handler->conn = session->conns[0];
+
   /* Setup the default done handler, to handle server errors */
   handler->done_delegate_baton = handler;
   handler->done_delegate = response_done;

Modified: subversion/branches/pin-externals/subversion/libsvn_ra_serf/xml.c
URL: http://svn.apache.org/viewvc/subversion/branches/pin-externals/subversion/libsvn_ra_serf/xml.c?rev=1655005&r1=1655004&r2=1655005&view=diff
==============================================================================
--- subversion/branches/pin-externals/subversion/libsvn_ra_serf/xml.c (original)
+++ subversion/branches/pin-externals/subversion/libsvn_ra_serf/xml.c Tue Jan 27 10:51:52 2015
@@ -1087,7 +1087,8 @@ expat_response_handler(serf_request_t *r
 
 
 svn_ra_serf__handler_t *
-svn_ra_serf__create_expat_handler(svn_ra_serf__xml_context_t *xmlctx,
+svn_ra_serf__create_expat_handler(svn_ra_serf__session_t *session,
+                                  svn_ra_serf__xml_context_t *xmlctx,
                                   const int *expected_status,
                                   apr_pool_t *result_pool)
 {
@@ -1100,7 +1101,7 @@ svn_ra_serf__create_expat_handler(svn_ra
   ectx->expected_status = expected_status;
   ectx->cleanup_pool = result_pool;
 
-  handler = svn_ra_serf__create_handler(result_pool);
+  handler = svn_ra_serf__create_handler(session, result_pool);
   handler->response_handler = expat_response_handler;
   handler->response_baton = ectx;
 

Modified: subversion/branches/pin-externals/subversion/libsvn_repos/dump.c
URL: http://svn.apache.org/viewvc/subversion/branches/pin-externals/subversion/libsvn_repos/dump.c?rev=1655005&r1=1655004&r2=1655005&view=diff
==============================================================================
--- subversion/branches/pin-externals/subversion/libsvn_repos/dump.c (original)
+++ subversion/branches/pin-externals/subversion/libsvn_repos/dump.c Tue Jan 27 10:51:52 2015
@@ -990,6 +990,34 @@ check_mergeinfo_normalization(const char
 }
 
 
+/* A special case of dump_node(), for a delete record.
+ *
+ * The only thing special about this version is it only writes one blank
+ * line, not two, after the headers. Why? Historical precedent for the
+ * case where a delete record is used as part of a (delete + add-with-history)
+ * in implementing a replacement.
+ *
+ * Also it doesn't do a path-tracker check.
+ */
+static svn_error_t *
+dump_node_delete(svn_stream_t *stream,
+                 const char *node_relpath,
+                 apr_pool_t *pool)
+{
+  apr_array_header_t *headers = svn_repos__dumpfile_headers_create(pool);
+
+  /* Node-path: ... */
+  svn_repos__dumpfile_header_push(
+    headers, SVN_REPOS_DUMPFILE_NODE_PATH, node_relpath);
+
+  /* Node-action: delete */
+  svn_repos__dumpfile_header_push(
+    headers, SVN_REPOS_DUMPFILE_NODE_ACTION, "delete");
+
+  SVN_ERR(svn_repos__dump_headers(stream, headers, TRUE, pool));
+  return SVN_NO_ERROR;
+}
+
 /* This helper is the main "meat" of the editor -- it does all the
    work of writing a node record.
 
@@ -1069,8 +1097,9 @@ dump_node(struct edit_baton *eb,
       compare_rev = cmp_rev;
     }
 
-  if (action == svn_node_action_change)
+  switch (action)
     {
+    case svn_node_action_change:
       if (eb->path_tracker)
         SVN_ERR_W(node_must_exist(eb, path, eb->current_rev, kind, pool),
                   apr_psprintf(pool, _("Change invalid path '%s' in r%ld"),
@@ -1091,9 +1120,27 @@ dump_node(struct edit_baton *eb,
         SVN_ERR(svn_fs_contents_different(&must_dump_text,
                                           compare_root, compare_path,
                                           eb->fs_root, path, pool));
-    }
-  else if (action == svn_node_action_replace)
-    {
+      break;
+
+    case svn_node_action_delete:
+      if (eb->path_tracker)
+        {
+          SVN_ERR_W(node_must_exist(eb, path, eb->current_rev, kind, pool),
+                    apr_psprintf(pool, _("Deleting invalid path '%s' in r%ld"),
+                                 path, eb->current_rev));
+          tracker_path_delete(eb->path_tracker, path);
+        }
+
+      svn_repos__dumpfile_header_push(
+        headers, SVN_REPOS_DUMPFILE_NODE_ACTION, "delete");
+
+      /* we can leave this routine quietly now, don't need to dump
+         any content. */
+      must_dump_text = FALSE;
+      must_dump_props = FALSE;
+      break;
+
+    case svn_node_action_replace:
       if (eb->path_tracker)
         SVN_ERR_W(node_must_exist(eb, path, eb->current_rev,
                                   svn_node_unknown, pool),
@@ -1114,63 +1161,28 @@ dump_node(struct edit_baton *eb,
           if (kind == svn_node_file)
             must_dump_text = TRUE;
           must_dump_props = TRUE;
+          break;
         }
       else
         {
+          /* more complex:  delete original, then add-with-history.  */
+          /* ### Why not write a 'replace' record? Don't know. */
+
           if (eb->path_tracker)
             {
-              SVN_ERR_W(node_must_exist(eb, compare_path, compare_rev,
-                                        kind, pool),
-                        apr_psprintf(pool,
-                                     _("Replacing path '%s' in r%ld "
-                                       "with invalid path"),
-                                     path, eb->current_rev));
-
-              /* we will call dump_node again with an addition further
-                 down the road */
               tracker_path_delete(eb->path_tracker, path);
             }
 
-          /* more complex:  delete original, then add-with-history.  */
-
-          /* the path & kind headers have already been printed;  just
-             add a delete action, and end the current record.*/
-          svn_repos__dumpfile_header_push(
-            headers, SVN_REPOS_DUMPFILE_NODE_ACTION, "delete");
-
-          SVN_ERR(svn_repos__dump_headers(eb->stream, headers, TRUE, pool));
-          /* ### Unusually, here we end this node record with only a single
+          /* ### Unusually, we end this 'delete' node record with only a single
                  blank line after the header block -- no extra blank line. */
+          SVN_ERR(dump_node_delete(eb->stream, path, pool));
 
-          /* recurse:  print an additional add-with-history record. */
-          SVN_ERR(dump_node(eb, path, kind, svn_node_action_add,
-                            is_copy, compare_path, compare_rev, pool));
-
-          /* we can leave this routine quietly now, don't need to dump
-             any content;  that was already done in the second record. */
-          return SVN_NO_ERROR;
+          /* The remaining action is a non-replacing add-with-history */
+          /* action = svn_node_action_add; */
         }
-    }
-  else if (action == svn_node_action_delete)
-    {
-      if (eb->path_tracker)
-        {
-          SVN_ERR_W(node_must_exist(eb, path, eb->current_rev, kind, pool),
-                    apr_psprintf(pool, _("Deleting invalid path '%s' in r%ld"),
-                                 path, eb->current_rev));
-          tracker_path_delete(eb->path_tracker, path);
-        }
-
-      svn_repos__dumpfile_header_push(
-        headers, SVN_REPOS_DUMPFILE_NODE_ACTION, "delete");
+      /* FALL THROUGH to 'add' */
 
-      /* we can leave this routine quietly now, don't need to dump
-         any content. */
-      must_dump_text = FALSE;
-      must_dump_props = FALSE;
-    }
-  else if (action == svn_node_action_add)
-    {
+    case svn_node_action_add:
       if (eb->path_tracker)
         SVN_ERR_W(node_must_not_exist(eb, path, eb->current_rev, pool),
                   apr_psprintf(pool,
@@ -1258,6 +1270,7 @@ dump_node(struct edit_baton *eb,
                   headers, SVN_REPOS_DUMPFILE_TEXT_COPY_SOURCE_SHA1, hex_digest);
             }
         }
+      break;
     }
 
   if ((! must_dump_text) && (! must_dump_props))

Modified: subversion/branches/pin-externals/subversion/libsvn_subr/checksum.c
URL: http://svn.apache.org/viewvc/subversion/branches/pin-externals/subversion/libsvn_subr/checksum.c?rev=1655005&r1=1655004&r2=1655005&view=diff
==============================================================================
--- subversion/branches/pin-externals/subversion/libsvn_subr/checksum.c (original)
+++ subversion/branches/pin-externals/subversion/libsvn_subr/checksum.c Tue Jan 27 10:51:52 2015
@@ -165,12 +165,15 @@ checksum_create_without_digest(svn_check
   return checksum;
 }
 
+/* Return a checksum object, allocated in POOL.  The checksum will be of
+ * type KIND and contain the given DIGEST.
+ */
 static svn_checksum_t *
 checksum_create(svn_checksum_kind_t kind,
-                apr_size_t digest_size,
                 const unsigned char *digest,
                 apr_pool_t *pool)
 {
+  apr_size_t digest_size = DIGESTSIZE(kind);
   svn_checksum_t *checksum = checksum_create_without_digest(kind, digest_size,
                                                             pool);
   memcpy((unsigned char *)checksum->digest, digest, digest_size);
@@ -206,32 +209,28 @@ svn_checksum_t *
 svn_checksum__from_digest_md5(const unsigned char *digest,
                               apr_pool_t *result_pool)
 {
-  return checksum_create(svn_checksum_md5, APR_MD5_DIGESTSIZE, digest,
-                         result_pool);
+  return checksum_create(svn_checksum_md5, digest, result_pool);
 }
 
 svn_checksum_t *
 svn_checksum__from_digest_sha1(const unsigned char *digest,
                                apr_pool_t *result_pool)
 {
-  return checksum_create(svn_checksum_sha1, APR_SHA1_DIGESTSIZE, digest,
-                         result_pool);
+  return checksum_create(svn_checksum_sha1, digest, result_pool);
 }
 
 svn_checksum_t *
 svn_checksum__from_digest_fnv1a_32(const unsigned char *digest,
                                    apr_pool_t *result_pool)
 {
-  return checksum_create(svn_checksum_fnv1a_32, sizeof(digest), digest,
-                         result_pool);
+  return checksum_create(svn_checksum_fnv1a_32, digest, result_pool);
 }
 
 svn_checksum_t *
 svn_checksum__from_digest_fnv1a_32x4(const unsigned char *digest,
                                      apr_pool_t *result_pool)
 {
-  return checksum_create(svn_checksum_fnv1a_32x4, sizeof(digest), digest,
-                         result_pool);
+  return checksum_create(svn_checksum_fnv1a_32x4, digest, result_pool);
 }
 
 svn_error_t *
@@ -428,10 +427,7 @@ svn_checksum_dup(const svn_checksum_t *c
       case svn_checksum_sha1:
       case svn_checksum_fnv1a_32:
       case svn_checksum_fnv1a_32x4:
-        return checksum_create(checksum->kind,
-                               digest_sizes[checksum->kind],
-                               checksum->digest,
-                               pool);
+        return checksum_create(checksum->kind, checksum->digest, pool);
 
       default:
         SVN_ERR_MALFUNCTION_NO_RETURN();
@@ -492,10 +488,7 @@ svn_checksum_empty_checksum(svn_checksum
       case svn_checksum_sha1:
       case svn_checksum_fnv1a_32:
       case svn_checksum_fnv1a_32x4:
-        return checksum_create(kind,
-                               digest_sizes[kind],
-                               empty_string_digests[kind],
-                               pool);
+        return checksum_create(kind, empty_string_digests[kind], pool);
 
       default:
         /* We really shouldn't get here, but if we do... */

Modified: subversion/branches/pin-externals/subversion/libsvn_wc/wc_db.c
URL: http://svn.apache.org/viewvc/subversion/branches/pin-externals/subversion/libsvn_wc/wc_db.c?rev=1655005&r1=1655004&r2=1655005&view=diff
==============================================================================
--- subversion/branches/pin-externals/subversion/libsvn_wc/wc_db.c (original)
+++ subversion/branches/pin-externals/subversion/libsvn_wc/wc_db.c Tue Jan 27 10:51:52 2015
@@ -1591,19 +1591,32 @@ svn_wc__db_init(svn_wc__db_t *db,
                         FALSE /* auto-upgrade */,
                         db->state_pool, scratch_pool));
 
-  /* The WCROOT is complete. Stash it into DB.  */
-  svn_hash_sets(db->dir_data, wcroot->abspath, wcroot);
+  /* Any previously cached children may now have a new WCROOT, most likely that
+     of the new WCROOT, but there might be descendant directories that are their
+     own working copy, in which case setting WCROOT to our new WCROOT might
+     actually break things for those.
+
+     Clearing is the safest thing we can do in this case, as a test would lead
+     to unnecessary probing, while the standard code probes later anyway. So we
+     only lose a bit of memory
 
-  /* Any previously cached children now have a new WCROOT. */
+     ### Perhaps we could check wcroot->abspath to detect which case we have
+         where, but currently it is already very hard to trigger this from
+         the short living 'svn' client. (GUI clients like TortoiseSVN are far
+         more likely to get in these cases)
+     */
   for (hi = apr_hash_first(scratch_pool, db->dir_data);
        hi;
        hi = apr_hash_next(hi))
     {
       const char *abspath = apr_hash_this_key(hi);
       if (svn_dirent_is_ancestor(wcroot->abspath, abspath))
-        svn_hash_sets(db->dir_data, abspath, wcroot);
+        svn_hash_sets(db->dir_data, abspath, NULL);
     }
 
+  /* The WCROOT is complete. Stash it into DB.  */
+  svn_hash_sets(db->dir_data, wcroot->abspath, wcroot);
+
   return SVN_NO_ERROR;
 }
 

Modified: subversion/branches/pin-externals/subversion/mod_dav_svn/liveprops.c
URL: http://svn.apache.org/viewvc/subversion/branches/pin-externals/subversion/mod_dav_svn/liveprops.c?rev=1655005&r1=1655004&r2=1655005&view=diff
==============================================================================
--- subversion/branches/pin-externals/subversion/mod_dav_svn/liveprops.c (original)
+++ subversion/branches/pin-externals/subversion/mod_dav_svn/liveprops.c Tue Jan 27 10:51:52 2015
@@ -36,6 +36,7 @@
 #include "svn_time.h"
 #include "svn_dav.h"
 #include "svn_props.h"
+#include "svn_ctype.h"
 
 #include "private/svn_dav_protocol.h"
 
@@ -422,7 +423,43 @@ insert_prop_internal(const dav_resource
         if (last_author == NULL)
           return DAV_PROP_INSERT_NOTDEF;
 
-        value = apr_xml_quote_string(scratch_pool, last_author->data, 1);
+        if (svn_xml_is_xml_safe(last_author->data, last_author->len)
+            || !resource->info->repos->is_svn_client)
+          value = apr_xml_quote_string(scratch_pool, last_author->data, 1);
+        else
+          {
+            /* We are talking to a Subversion client, which will (like any proper
+               xml parser) error out if we produce control characters in XML.
+
+               However Subversion clients process both the generic
+               <creator-displayname /> as the custom element for svn:author.
+
+               Let's skip outputting the invalid characters here to make the XML
+               valid, so clients can see the custom element.
+
+               Subversion Clients will then either use a slightly invalid
+               author (unlikely) or more likely use the second result, which
+               will be transferred with full escaping capabilities.
+
+               We have tests in place to assert proper behavior over the RA layer.
+             */
+            apr_size_t i;
+            svn_stringbuf_t *buf;
+
+            buf = svn_stringbuf_create_from_string(last_author, scratch_pool);
+
+            for (i = 0; i < buf->len; i++)
+              {
+                char c = buf->data[i];
+
+                if (svn_ctype_iscntrl(c))
+                  {
+                    svn_stringbuf_remove(buf, i--, 1);
+                  }
+              }
+
+            value = apr_xml_quote_string(scratch_pool, buf->data, 1);
+          }
         break;
       }
 

Modified: subversion/branches/pin-externals/subversion/svnrdump/dump_editor.c
URL: http://svn.apache.org/viewvc/subversion/branches/pin-externals/subversion/svnrdump/dump_editor.c?rev=1655005&r1=1655004&r2=1655005&view=diff
==============================================================================
--- subversion/branches/pin-externals/subversion/svnrdump/dump_editor.c (original)
+++ subversion/branches/pin-externals/subversion/svnrdump/dump_editor.c Tue Jan 27 10:51:52 2015
@@ -136,11 +136,10 @@ struct dump_edit_baton {
   /* The revision we're currently dumping. */
   svn_revnum_t current_revision;
 
-  /* The kind (file or directory) and baton of the item whose block of
+  /* The baton of the directory node whose block of
      dump stream data has not been fully completed; NULL if there's no
      such item. */
-  svn_node_kind_t pending_kind;
-  void *pending_baton;
+  struct dir_baton *pending_db;
 };
 
 /* Make a directory baton to represent the directory at PATH (relative
@@ -252,16 +251,31 @@ get_props_content(apr_array_header_t *he
   return SVN_NO_ERROR;
 }
 
+/* A special case of dump_node(), for a delete record.
+ *
+ * The only thing special about this version is it only writes one blank
+ * line, not two, after the headers. Why? Historical precedent for the
+ * case where a delete record is used as part of a (delete + add-with-history)
+ * in implementing a replacement.
+ */
 static svn_error_t *
-do_dump_newlines(struct dump_edit_baton *eb,
-                 svn_boolean_t *trigger_var,
+dump_node_delete(svn_stream_t *stream,
+                 const char *node_relpath,
                  apr_pool_t *pool)
 {
-  if (trigger_var && *trigger_var)
-    {
-      SVN_ERR(svn_stream_puts(eb->stream, "\n\n"));
-      *trigger_var = FALSE;
-    }
+  apr_array_header_t *headers = svn_repos__dumpfile_headers_create(pool);
+
+  assert(svn_relpath_is_canonical(node_relpath));
+
+  /* Node-path: ... */
+  svn_repos__dumpfile_header_push(
+    headers, SVN_REPOS_DUMPFILE_NODE_PATH, node_relpath);
+
+  /* Node-action: delete */
+  svn_repos__dumpfile_header_push(
+    headers, SVN_REPOS_DUMPFILE_NODE_ACTION, "delete");
+
+  SVN_ERR(svn_repos__dump_headers(stream, headers, TRUE, pool));
   return SVN_NO_ERROR;
 }
 
@@ -327,24 +341,20 @@ dump_node(struct dump_edit_baton *eb,
         headers, SVN_REPOS_DUMPFILE_NODE_ACTION, "change");
       break;
 
-    case svn_node_action_replace:
-      if (is_copy)
-        {
-          /* More complex case: is_copy is true, and copyfrom_path/
-             copyfrom_rev are present: delete the original, and then re-add
-             it */
-
-          svn_repos__dumpfile_header_push(
-            headers, SVN_REPOS_DUMPFILE_NODE_ACTION, "delete");
+    case svn_node_action_delete:
+      /* Node-action: delete */
+      svn_repos__dumpfile_header_push(
+        headers, SVN_REPOS_DUMPFILE_NODE_ACTION, "delete");
 
-          SVN_ERR(svn_repos__dump_headers(eb->stream, headers, TRUE, pool));
+      /* We can leave this routine quietly now. Nothing more to do-
+         print the headers terminated by one blank line, and an extra
+         blank line because we're not dumping props or text. */
+      SVN_ERR(svn_repos__dump_headers(eb->stream, headers, TRUE, pool));
+      SVN_ERR(svn_stream_puts(eb->stream, "\n"));
+      return SVN_NO_ERROR;
 
-          /* Recurse: Print an additional add-with-history record. */
-          SVN_ERR(dump_node(eb, repos_relpath, db, fb, svn_node_action_add,
-                            is_copy, copyfrom_path, copyfrom_rev, pool));
-          return SVN_NO_ERROR;
-        }
-      else
+    case svn_node_action_replace:
+      if (! is_copy)
         {
           /* Node-action: replace */
           svn_repos__dumpfile_header_push(
@@ -356,21 +366,23 @@ dump_node(struct dump_edit_baton *eb,
             fb->dump_props = TRUE;
           else if (db)
             db->dump_props = TRUE;
+          break;
         }
-      break;
-
-    case svn_node_action_delete:
-      /* Node-action: delete */
-      svn_repos__dumpfile_header_push(
-        headers, SVN_REPOS_DUMPFILE_NODE_ACTION, "delete");
+      else
+        {
+          /* More complex case: is_copy is true, and copyfrom_path/
+             copyfrom_rev are present: delete the original, and then re-add
+             it */
+          /* ### Why not write a 'replace' record? Don't know. */
 
-      /* We can leave this routine quietly now. Nothing more to do-
-         print the headers terminated by one blank line, and an extra
-         blank line because we're not dumping props or text. */
-      SVN_ERR(svn_repos__dump_headers(eb->stream, headers, TRUE, pool));
-      SVN_ERR(svn_stream_puts(eb->stream, "\n"));
+          /* ### Unusually, we end this 'delete' node record with only a single
+                 blank line after the header block -- no extra blank line. */
+          SVN_ERR(dump_node_delete(eb->stream, repos_relpath, pool));
 
-      return SVN_NO_ERROR;
+          /* The remaining action is a non-replacing add-with-history */
+          /* action = svn_node_action_add; */
+        }
+      /* FALL THROUGH to 'add' */
 
     case svn_node_action_add:
       /* Node-action: add */
@@ -466,55 +478,26 @@ dump_mkdir(struct dump_edit_baton *eb,
   return SVN_NO_ERROR;
 }
 
-/* Dump pending items from the specified node, to allow starting the dump
-   of a child node */
+/* Dump pending headers and properties for the directory DB,
+   to allow starting the dump of a child node */
 static svn_error_t *
-dump_pending(struct dump_edit_baton *eb,
-             apr_pool_t *scratch_pool)
+dump_pending_dir(struct dump_edit_baton *eb,
+                 apr_pool_t *scratch_pool)
 {
-  svn_boolean_t dump_props = FALSE;
-  apr_hash_t *props, *deleted_props;
+  struct dir_baton *db = eb->pending_db;
 
-  if (! eb->pending_baton)
+  if (! db)
     return SVN_NO_ERROR;
 
   /* Some pending properties to dump? */
-  if (eb->pending_kind == svn_node_dir)
-    {
-      struct dir_baton *db = eb->pending_baton;
-
-      if (db->dump_props)
-        {
-          dump_props = TRUE;
-          props = db->props;
-          deleted_props = db->deleted_props;
-
-          db->dump_props = FALSE;
-        }
-    }
-  else if (eb->pending_kind == svn_node_file)
-    {
-      struct file_baton *fb = eb->pending_baton;
-
-      if (fb->dump_props)
-        {
-          dump_props = TRUE;
-          props = fb->props;
-          deleted_props = fb->deleted_props;
-          fb->dump_props = FALSE;
-        }
-    }
-  else
-    abort();
-
-  if (dump_props)
+  if (db->dump_props)
     {
       apr_array_header_t *headers
         = svn_repos__dumpfile_headers_create(scratch_pool);
       svn_stringbuf_t *content;
       apr_size_t len;
 
-      SVN_ERR(get_props_content(headers, &content, props, deleted_props,
+      SVN_ERR(get_props_content(headers, &content, db->props, db->deleted_props,
                                 scratch_pool, scratch_pool));
 
       /* Content-length: 14 */
@@ -533,21 +516,20 @@ dump_pending(struct dump_edit_baton *eb,
       SVN_ERR(svn_stream_puts(eb->stream, "\n\n"));
 
       /* Cleanup so that data is never dumped twice. */
-      apr_hash_clear(props);
-      apr_hash_clear(deleted_props);
+      apr_hash_clear(db->props);
+      apr_hash_clear(db->deleted_props);
+      db->dump_props = FALSE;
     }
 
-  if (eb->pending_kind == svn_node_dir)
+  /* Some pending newlines to dump? */
+  if (db->dump_newlines)
     {
-      struct dir_baton *db = eb->pending_baton;
-
-      /* Some pending newlines to dump? */
-      SVN_ERR(do_dump_newlines(eb, &(db->dump_newlines), scratch_pool));
+      SVN_ERR(svn_stream_puts(eb->stream, "\n\n"));
+      db->dump_newlines = FALSE;
     }
 
   /* Anything that was pending is pending no longer. */
-  eb->pending_baton = NULL;
-  eb->pending_kind = svn_node_none;
+  eb->pending_db = NULL;
 
   return SVN_NO_ERROR;
 }
@@ -607,8 +589,7 @@ open_root(void *edit_baton,
 
               /* Remember that we've started but not yet finished
                  handling this directory. */
-              eb->pending_baton = new_db;
-              eb->pending_kind = svn_node_dir;
+              eb->pending_db = new_db;
             }
         }
       svn_pool_destroy(iterpool);
@@ -632,7 +613,7 @@ delete_entry(const char *path,
 {
   struct dir_baton *pb = parent_baton;
 
-  SVN_ERR(dump_pending(pb->eb, pool));
+  SVN_ERR(dump_pending_dir(pb->eb, pool));
 
   /* We don't dump this deletion immediate.  Rather, we add this path
      to the deleted_entries of the parent directory baton.  That way,
@@ -656,7 +637,7 @@ add_directory(const char *path,
   struct dir_baton *new_db;
   svn_boolean_t is_copy;
 
-  SVN_ERR(dump_pending(pb->eb, pool));
+  SVN_ERR(dump_pending_dir(pb->eb, pool));
 
   new_db = make_dir_baton(path, copyfrom_path, copyfrom_rev, pb->eb,
                           pb, pb->pool);
@@ -681,8 +662,7 @@ add_directory(const char *path,
 
   /* Remember that we've started, but not yet finished handling this
      directory. */
-  pb->eb->pending_baton = new_db;
-  pb->eb->pending_kind = svn_node_dir;
+  pb->eb->pending_db = new_db;
 
   *child_baton = new_db;
   return SVN_NO_ERROR;
@@ -700,7 +680,7 @@ open_directory(const char *path,
   const char *copyfrom_path = NULL;
   svn_revnum_t copyfrom_rev = SVN_INVALID_REVNUM;
 
-  SVN_ERR(dump_pending(pb->eb, pool));
+  SVN_ERR(dump_pending_dir(pb->eb, pool));
 
   /* If the parent directory has explicit comparison path and rev,
      record the same for this one. */
@@ -728,9 +708,9 @@ close_directory(void *dir_baton,
   svn_boolean_t this_pending;
 
   /* Remember if this directory is the one currently pending. */
-  this_pending = (db->eb->pending_baton == db);
+  this_pending = (db->eb->pending_db == db);
 
-  SVN_ERR(dump_pending(db->eb, pool));
+  SVN_ERR(dump_pending_dir(db->eb, pool));
 
   /* If this directory was pending, then dump_pending() should have
      taken care of all the props and such.  Of course, the only way
@@ -746,9 +726,8 @@ close_directory(void *dir_baton,
       SVN_ERR(dump_node(db->eb, db->repos_relpath, db, NULL,
                         svn_node_action_change, FALSE,
                         NULL, SVN_INVALID_REVNUM, pool));
-      db->eb->pending_baton = db;
-      db->eb->pending_kind = svn_node_dir;
-      SVN_ERR(dump_pending(db->eb, pool));
+      db->eb->pending_db = db;
+      SVN_ERR(dump_pending_dir(db->eb, pool));
     }
 
   /* Dump the deleted directory entries */
@@ -779,7 +758,7 @@ add_file(const char *path,
   struct file_baton *fb;
   void *was_deleted;
 
-  SVN_ERR(dump_pending(pb->eb, pool));
+  SVN_ERR(dump_pending_dir(pb->eb, pool));
 
   /* Make the file baton. */
   fb = make_file_baton(path, pb, pool);
@@ -814,7 +793,7 @@ open_file(const char *path,
   struct dir_baton *pb = parent_baton;
   struct file_baton *fb;
 
-  SVN_ERR(dump_pending(pb->eb, pool));
+  SVN_ERR(dump_pending_dir(pb->eb, pool));
 
   /* Make the file baton. */
   fb = make_file_baton(path, pb, pool);
@@ -844,9 +823,9 @@ change_dir_prop(void *parent_baton,
 
   /* This directory is not pending, but something else is, so handle
      the "something else".  */
-  this_pending = (db->eb->pending_baton == db);
+  this_pending = (db->eb->pending_db == db);
   if (! this_pending)
-    SVN_ERR(dump_pending(db->eb, pool));
+    SVN_ERR(dump_pending_dir(db->eb, pool));
 
   if (svn_property_kind2(name) != svn_prop_regular_kind)
     return SVN_NO_ERROR;
@@ -928,7 +907,7 @@ close_file(void *file_baton,
   svn_stringbuf_t *propstring;
   apr_array_header_t *headers = svn_repos__dumpfile_headers_create(pool);
 
-  SVN_ERR(dump_pending(eb, pool));
+  SVN_ERR(dump_pending_dir(eb, pool));
 
   /* Dump the node. */
   SVN_ERR(dump_node(eb, fb->repos_relpath, NULL, fb,
@@ -1158,7 +1137,7 @@ svn_rdump__get_dump_editor(const svn_del
   eb->ra_session = ra_session;
   eb->update_anchor_relpath = update_anchor_relpath;
   eb->current_revision = revision;
-  eb->pending_kind = svn_node_none;
+  eb->pending_db = NULL;
 
   /* Create a special per-revision pool */
   eb->pool = svn_pool_create(pool);

Modified: subversion/branches/pin-externals/subversion/tests/cmdline/prop_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/pin-externals/subversion/tests/cmdline/prop_tests.py?rev=1655005&r1=1655004&r2=1655005&view=diff
==============================================================================
--- subversion/branches/pin-externals/subversion/tests/cmdline/prop_tests.py (original)
+++ subversion/branches/pin-externals/subversion/tests/cmdline/prop_tests.py Tue Jan 27 10:51:52 2015
@@ -2619,7 +2619,6 @@ def peg_rev_base_working(sbox):
                                      sbox.ospath('iota') + '@BASE')
 
 @Issue(4415)
-@XFail(svntest.main.is_ra_type_dav)
 def xml_unsafe_author(sbox):
   "svn:author with XML unsafe chars"
 
@@ -2646,22 +2645,70 @@ def xml_unsafe_author(sbox):
 
   # mod_dav_svn sends svn:author (via PROPFIND for DAV)
   # Since r1553367 this works correctly on ra_serf, since we now request
-  # a single property value which somehow triggers different behavior
+  # a single property value which skips creating the creator-displayname property
   svntest.actions.run_and_verify_svn(None, ['foo\bbar'], [],
                                      'propget', '--revprop', '-r', '1',
                                      'svn:author', '--strict', wc_dir)
 
+  # Ensure a stable date
+  svntest.actions.run_and_verify_svn(None, None, [],
+                                     'propset', '--revprop', '-r', '1',
+                                     'svn:date', '2015-01-01T00:00:00.0Z', wc_dir)
+
   # But a proplist of this property value still fails via DAV.
-  expected_output = [
+  expected_output = svntest.verify.UnorderedOutput([
     'Unversioned properties on revision 1:\n',
     '  svn:author\n',
+    '    foo\bbar\n',
     '  svn:date\n',
-    '  svn:log\n'
-  ]
+    '    2015-01-01T00:00:00.0Z\n',
+    '  svn:log\n',
+    '    Log message for revision 1.\n'
+  ])
   svntest.actions.run_and_verify_svn(None, expected_output, [],
-                                     'proplist', '--revprop', '-r', '1',
+                                     'proplist', '--revprop', '-r', '1', '-v',
                                      wc_dir)
 
+@Issue(4415)
+def xml_unsafe_author2(sbox):
+  "svn:author with XML unsafe chars 2"
+
+  sbox.build(create_wc = False)
+  repo_url = sbox.repo_url
+
+  svntest.actions.enable_revprop_changes(sbox.repo_dir)
+
+  # client sends svn:author (via PROPPATCH for DAV)
+  svntest.actions.run_and_verify_svn(None, None, [],
+                                     'propset', '--revprop', '-r', '1',
+                                     'svn:author', 'foo\bbar', repo_url)
+
+  # Ensure a stable date
+  svntest.actions.run_and_verify_svn(None, None, [],
+                                     'propset', '--revprop', '-r', '1',
+                                     'svn:date', '2000-01-01T12:00:00.0Z',
+                                     repo_url)
+
+  if svntest.main.is_ra_type_dav():
+    # This receives the filtered author (but that is better than an Xml fail)
+    expected_author = 'foobar'
+  else:
+    expected_author = 'foo\bbar'
+
+  expected_output = svntest.verify.UnorderedOutput([
+    '      1 %-8s              Jan 01  2000 ./\n' % expected_author,
+    '      1 %-8s              Jan 01  2000 A/\n' % expected_author,
+    '      1 %-8s           25 Jan 01  2000 iota\n' % expected_author
+  ])
+  svntest.actions.run_and_verify_svn(None, expected_output, [],
+                                     'ls', '-v', repo_url)
+
+  expected_info = [{
+      'Repository Root' : sbox.repo_url,
+      'Last Changed Author' : expected_author,
+  }]
+  svntest.actions.run_and_verify_info(expected_info, repo_url)
+
 def dir_prop_conflict_details(sbox):
   "verify dir property conflict details"
 
@@ -2814,6 +2861,7 @@ test_list = [ None,
               almost_known_prop_names,
               peg_rev_base_working,
               xml_unsafe_author,
+              xml_unsafe_author2,
               dir_prop_conflict_details,
               iprops_list_abspath,
               wc_propop_on_url,