You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by vm...@apache.org on 2012/05/29 03:39:49 UTC

svn commit: r1343447 [12/27] - in /subversion/branches/javahl-ra: ./ build/ build/ac-macros/ build/generator/ build/generator/templates/ build/win32/ contrib/client-side/emacs/ contrib/server-side/ notes/ notes/api-errata/1.8/ notes/merge-tracking/ sub...

Modified: subversion/branches/javahl-ra/subversion/libsvn_ra_serf/serf.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_ra_serf/serf.c?rev=1343447&r1=1343446&r2=1343447&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_ra_serf/serf.c (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_ra_serf/serf.c Tue May 29 01:39:41 2012
@@ -27,9 +27,6 @@
 #include <apr_want.h>
 
 #include <apr_uri.h>
-
-#include <expat.h>
-
 #include <serf.h>
 
 #include "svn_pools.h"
@@ -48,11 +45,13 @@
 #include "private/svn_dav_protocol.h"
 #include "private/svn_dep_compat.h"
 #include "private/svn_fspath.h"
+#include "private/svn_subr_private.h"
 #include "svn_private_config.h"
 
 #include "ra_serf.h"
 
 
+/* Implements svn_ra__vtable_t.get_version(). */
 static const svn_version_t *
 ra_serf_version(void)
 {
@@ -62,12 +61,14 @@ ra_serf_version(void)
 #define RA_SERF_DESCRIPTION \
     N_("Module for accessing a repository via WebDAV protocol using serf.")
 
+/* Implements svn_ra__vtable_t.get_description(). */
 static const char *
 ra_serf_get_description(void)
 {
   return _(RA_SERF_DESCRIPTION);
 }
 
+/* Implements svn_ra__vtable_t.get_schemes(). */
 static const char * const *
 ra_serf_get_schemes(apr_pool_t *pool)
 {
@@ -334,6 +335,7 @@ svn_ra_serf__progress(void *progress_bat
     }
 }
 
+/* Implements svn_ra__vtable_t.open_session(). */
 static svn_error_t *
 svn_ra_serf__open(svn_ra_session_t *session,
                   const char **corrected_url,
@@ -440,6 +442,7 @@ svn_ra_serf__open(svn_ra_session_t *sess
   return svn_ra_serf__exchange_capabilities(serf_sess, corrected_url, pool);
 }
 
+/* Implements svn_ra__vtable_t.reparent(). */
 static svn_error_t *
 svn_ra_serf__reparent(svn_ra_session_t *ra_session,
                       const char *url,
@@ -482,6 +485,7 @@ svn_ra_serf__reparent(svn_ra_session_t *
   return SVN_NO_ERROR;
 }
 
+/* Implements svn_ra__vtable_t.get_session_url(). */
 static svn_error_t *
 svn_ra_serf__get_session_url(svn_ra_session_t *ra_session,
                              const char **url,
@@ -492,20 +496,19 @@ svn_ra_serf__get_session_url(svn_ra_sess
   return SVN_NO_ERROR;
 }
 
+/* Implements svn_ra__vtable_t.get_latest_revnum(). */
 static svn_error_t *
 svn_ra_serf__get_latest_revnum(svn_ra_session_t *ra_session,
                                svn_revnum_t *latest_revnum,
                                apr_pool_t *pool)
 {
-  const char *relative_url, *basecoll_url;
   svn_ra_serf__session_t *session = ra_session->priv;
 
-  return svn_ra_serf__get_baseline_info(&basecoll_url, &relative_url, session,
-                                        NULL, session->session_url.path,
-                                        SVN_INVALID_REVNUM, latest_revnum,
-                                        pool);
+  return svn_error_trace(svn_ra_serf__get_youngest_revnum(
+                           latest_revnum, session, pool));
 }
 
+/* Implements svn_ra__vtable_t.rev_proplist(). */
 static svn_error_t *
 svn_ra_serf__rev_proplist(svn_ra_session_t *ra_session,
                           svn_revnum_t rev,
@@ -532,6 +535,7 @@ svn_ra_serf__rev_proplist(svn_ra_session
       SVN_ERR(svn_ra_serf__discover_vcc(&propfind_path, session, NULL, pool));
     }
 
+  /* ### fix: fetch hash of *just* the PATH@REV props. no nested hash.  */
   SVN_ERR(svn_ra_serf__retrieve_props(&props, session, session->conns[0],
                                       propfind_path, rev, "0", all_props,
                                       pool, pool));
@@ -542,6 +546,7 @@ svn_ra_serf__rev_proplist(svn_ra_session
   return SVN_NO_ERROR;
 }
 
+/* Implements svn_ra__vtable_t.rev_prop(). */
 static svn_error_t *
 svn_ra_serf__rev_prop(svn_ra_session_t *session,
                       svn_revnum_t rev,
@@ -559,71 +564,43 @@ svn_ra_serf__rev_prop(svn_ra_session_t *
 }
 
 static svn_error_t *
-fetch_path_props(svn_ra_serf__propfind_context_t **ret_prop_ctx,
-                 apr_hash_t **ret_props,
-                 const char **ret_path,
-                 svn_revnum_t *ret_revision,
+fetch_path_props(apr_hash_t **props,
                  svn_ra_serf__session_t *session,
-                 const char *rel_path,
+                 const char *session_relpath,
                  svn_revnum_t revision,
                  const svn_ra_serf__dav_props_t *desired_props,
-                 apr_pool_t *pool)
+                 apr_pool_t *result_pool,
+                 apr_pool_t *scratch_pool)
 {
-  svn_ra_serf__propfind_context_t *prop_ctx;
-  apr_hash_t *props;
-  const char *path;
+  const char *url;
 
-  path = session->session_url.path;
+  url = session->session_url.path;
 
   /* If we have a relative path, append it. */
-  if (rel_path)
-    {
-      path = svn_path_url_add_component2(path, rel_path, pool);
-    }
-
-  props = apr_hash_make(pool);
-
-  /* If we were given a specific revision, we have to fetch the VCC and
-   * do a PROPFIND off of that.
-   */
-  if (!SVN_IS_VALID_REVNUM(revision))
-    {
-      SVN_ERR(svn_ra_serf__deliver_props(&prop_ctx, props, session,
-                                         session->conns[0], path, revision,
-                                         "0", desired_props, NULL,
-                                         pool));
-    }
-  else
-    {
-      const char *relative_url, *basecoll_url;
+  if (session_relpath)
+    url = svn_path_url_add_component2(url, session_relpath, scratch_pool);
 
-      SVN_ERR(svn_ra_serf__get_baseline_info(&basecoll_url, &relative_url,
-                                             session, NULL, path,
-                                             revision, NULL, pool));
-
-      /* We will try again with our new path; however, we're now
-       * technically an unversioned resource because we are accessing
-       * the revision's baseline-collection.
-       */
-      path = svn_path_url_add_component2(basecoll_url, relative_url, pool);
-      revision = SVN_INVALID_REVNUM;
-      SVN_ERR(svn_ra_serf__deliver_props(&prop_ctx, props, session,
-                                         session->conns[0], path, revision,
-                                         "0", desired_props, NULL,
-                                         pool));
-    }
-
-  /* ### switch to svn_ra_serf__retrieve_props?  */
-  SVN_ERR(svn_ra_serf__wait_for_props(prop_ctx, session, pool));
-
-  *ret_path = path;
-  *ret_prop_ctx = prop_ctx;
-  *ret_props = props;
-  *ret_revision = revision;
+  /* 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 */,
+                                          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(). */
 static svn_error_t *
 svn_ra_serf__check_path(svn_ra_session_t *ra_session,
                         const char *rel_path,
@@ -633,13 +610,10 @@ svn_ra_serf__check_path(svn_ra_session_t
 {
   svn_ra_serf__session_t *session = ra_session->priv;
   apr_hash_t *props;
-  svn_ra_serf__propfind_context_t *prop_ctx;
-  const char *path;
-  svn_revnum_t fetched_rev;
 
-  svn_error_t *err = fetch_path_props(&prop_ctx, &props, &path, &fetched_rev,
-                                      session, rel_path,
-                                      revision, check_path_props, pool);
+  svn_error_t *err = fetch_path_props(&props, session, rel_path,
+                                      revision, check_path_props,
+                                      pool, pool);
 
   if (err && err->apr_err == SVN_ERR_FS_NOT_FOUND)
     {
@@ -648,11 +622,14 @@ svn_ra_serf__check_path(svn_ra_session_t
     }
   else
     {
+      svn_kind_t res_kind;
+
       /* Any other error, raise to caller. */
       if (err)
-        return err;
+        return svn_error_trace(err);
 
-      SVN_ERR(svn_ra_serf__get_resource_type(kind, props, path, fetched_rev));
+      SVN_ERR(svn_ra_serf__get_resource_type(&res_kind, props));
+      *kind = svn__node_kind_from_kind(res_kind);
     }
 
   return SVN_NO_ERROR;
@@ -862,6 +839,7 @@ get_dirent_props(apr_uint32_t dirent_fie
   return (svn_ra_serf__dav_props_t *) props->elts;
 }
 
+/* Implements svn_ra__vtable_t.stat(). */
 static svn_error_t *
 svn_ra_serf__stat(svn_ra_session_t *ra_session,
                   const char *rel_path,
@@ -871,17 +849,14 @@ svn_ra_serf__stat(svn_ra_session_t *ra_s
 {
   svn_ra_serf__session_t *session = ra_session->priv;
   apr_hash_t *props;
-  svn_ra_serf__propfind_context_t *prop_ctx;
-  const char *path;
-  svn_revnum_t fetched_rev;
   svn_error_t *err;
   struct dirent_walker_baton_t dwb;
   svn_tristate_t deadprop_count = svn_tristate_unknown;
 
-  err = fetch_path_props(&prop_ctx, &props, &path, &fetched_rev,
+  err = fetch_path_props(&props,
                          session, rel_path, revision,
                          get_dirent_props(SVN_DIRENT_ALL, session, pool),
-                         pool);
+                         pool, pool);
   if (err)
     {
       if (err->apr_err == SVN_ERR_FS_NOT_FOUND)
@@ -897,9 +872,7 @@ svn_ra_serf__stat(svn_ra_session_t *ra_s
   dwb.entry = apr_pcalloc(pool, sizeof(*dwb.entry));
   dwb.supports_deadprop_count = &deadprop_count;
   dwb.result_pool = pool;
-  SVN_ERR(svn_ra_serf__walk_all_props(props, path, fetched_rev,
-                                      dirent_walker, &dwb,
-                                      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
@@ -909,14 +882,12 @@ svn_ra_serf__stat(svn_ra_session_t *ra_s
          information */
       session->supports_deadprop_count = svn_tristate_false;
 
-      SVN_ERR(fetch_path_props(&prop_ctx, &props, &path, &fetched_rev,
-                               session, rel_path, fetched_rev,
+      SVN_ERR(fetch_path_props(&props,
+                               session, rel_path, SVN_INVALID_REVNUM,
                                get_dirent_props(SVN_DIRENT_ALL, session, pool),
-                               pool));
+                               pool, pool));
 
-      SVN_ERR(svn_ra_serf__walk_all_props(props, path, fetched_rev,
-                                      dirent_walker, &dwb,
-                                      pool));
+      SVN_ERR(svn_ra_serf__walk_node_props(props, dirent_walker, &dwb, pool));
     }
 
   if (deadprop_count != svn_tristate_unknown)
@@ -932,15 +903,13 @@ svn_ra_serf__stat(svn_ra_session_t *ra_s
  * SVN_ERR_FS_NOT_DIRECTORY if not.
  */
 static svn_error_t *
-resource_is_directory(apr_hash_t *props,
-                      const char *path,
-                      svn_revnum_t revision)
+resource_is_directory(apr_hash_t *props)
 {
-  svn_node_kind_t kind;
+  svn_kind_t kind;
 
-  SVN_ERR(svn_ra_serf__get_resource_type(&kind, props, path, revision));
+  SVN_ERR(svn_ra_serf__get_resource_type(&kind, props));
 
-  if (kind != svn_node_dir)
+  if (kind != svn_kind_dir)
     {
       return svn_error_create(SVN_ERR_FS_NOT_DIRECTORY, NULL,
                               _("Can't get entries of non-directory"));
@@ -949,6 +918,7 @@ resource_is_directory(apr_hash_t *props,
   return SVN_NO_ERROR;
 }
 
+/* Implements svn_ra__vtable_t.get_dir(). */
 static svn_error_t *
 svn_ra_serf__get_dir(svn_ra_session_t *ra_session,
                      apr_hash_t **dirents,
@@ -975,34 +945,37 @@ svn_ra_serf__get_dir(svn_ra_session_t *r
      public url. */
   if (SVN_IS_VALID_REVNUM(revision) || fetched_rev)
     {
-      const char *relative_url, *basecoll_url;
-
-      SVN_ERR(svn_ra_serf__get_baseline_info(&basecoll_url, &relative_url,
-                                             session, NULL, path, revision,
-                                             fetched_rev, pool));
-
-      path = svn_path_url_add_component2(basecoll_url, relative_url, pool);
+      SVN_ERR(svn_ra_serf__get_stable_url(&path, fetched_rev,
+                                          session, NULL /* conn */,
+                                          path, revision,
+                                          pool, pool));
       revision = SVN_INVALID_REVNUM;
     }
+  /* REVISION is always SVN_INVALID_REVNUM  */
+  SVN_ERR_ASSERT(!SVN_IS_VALID_REVNUM(revision));
 
   /* If we're asked for children, fetch them now. */
   if (dirents)
     {
       struct path_dirent_visitor_t dirent_walk;
       apr_hash_t *props;
+      const char *rtype;
 
       /* Always request node kind to check that path is really a
        * directory.
        */
       dirent_fields |= SVN_DIRENT_KIND;
       SVN_ERR(svn_ra_serf__retrieve_props(&props, session, session->conns[0],
-                                          path, revision, "1",
+                                          path, SVN_INVALID_REVNUM, "1",
                                           get_dirent_props(dirent_fields,
                                                            session, pool),
                                           pool, pool));
 
       /* Check if the path is really a directory. */
-      SVN_ERR(resource_is_directory(props, path, revision));
+      rtype = svn_ra_serf__get_prop(props, path, "DAV:", "resourcetype");
+      if (rtype == NULL || strcmp(rtype, "collection") != 0)
+        return svn_error_create(SVN_ERR_FS_NOT_DIRECTORY, NULL,
+                                _("Can't get entries of non-directory"));
 
       /* We're going to create two hashes to help the walker along.
        * We're going to return the 2nd one back to the caller as it
@@ -1014,8 +987,9 @@ svn_ra_serf__get_dir(svn_ra_session_t *r
       dirent_walk.supports_deadprop_count = svn_tristate_unknown;
       dirent_walk.result_pool = pool;
 
-      SVN_ERR(svn_ra_serf__walk_all_paths(props, revision, path_dirent_walker,
-                                          &dirent_walk, pool));
+      SVN_ERR(svn_ra_serf__walk_all_paths(props, SVN_INVALID_REVNUM,
+                                          path_dirent_walker, &dirent_walk,
+                                          pool));
 
       if (dirent_walk.supports_deadprop_count == svn_tristate_false
           && session->supports_deadprop_count == svn_tristate_unknown
@@ -1026,7 +1000,7 @@ svn_ra_serf__get_dir(svn_ra_session_t *r
           session->supports_deadprop_count = svn_tristate_false;
           SVN_ERR(svn_ra_serf__retrieve_props(&props, session,
                                               session->conns[0],
-                                              path, revision, "1",
+                                              path, SVN_INVALID_REVNUM, "1",
                                               get_dirent_props(dirent_fields,
                                                                session, pool),
                                               pool, pool));
@@ -1034,7 +1008,7 @@ svn_ra_serf__get_dir(svn_ra_session_t *r
           SVN_ERR(svn_hash__clear(dirent_walk.full_paths, pool));
           SVN_ERR(svn_hash__clear(dirent_walk.base_paths, pool));
 
-          SVN_ERR(svn_ra_serf__walk_all_paths(props, revision,
+          SVN_ERR(svn_ra_serf__walk_all_paths(props, SVN_INVALID_REVNUM,
                                               path_dirent_walker,
                                               &dirent_walk, pool));
         }
@@ -1050,14 +1024,17 @@ svn_ra_serf__get_dir(svn_ra_session_t *r
     {
       apr_hash_t *props;
 
-      SVN_ERR(svn_ra_serf__retrieve_props(&props, session, session->conns[0],
-                                          path, revision, "0", all_props,
-                                          pool, pool));
+      SVN_ERR(svn_ra_serf__fetch_node_props(&props, session->conns[0],
+                                            path, SVN_INVALID_REVNUM,
+                                            all_props,
+                                            pool, pool));
+
       /* Check if the path is really a directory. */
-      SVN_ERR(resource_is_directory(props, path, revision));
+      SVN_ERR(resource_is_directory(props));
 
-      SVN_ERR(svn_ra_serf__flatten_props(ret_props, props, path, revision,
-                                         pool, pool));
+      /* ### flatten_props() does not copy PROPVALUE, but fetch_node_props()
+         ### put them into POOL, so we're okay.  */
+      SVN_ERR(svn_ra_serf__flatten_props(ret_props, props, pool, pool));
     }
 
   return SVN_NO_ERROR;
@@ -1088,6 +1065,8 @@ svn_ra_serf__get_repos_root(svn_ra_sessi
    case where the root of the repository is not readable.
    However, it does not handle the case where we're fetching path not existing
    in HEAD of a repository with unreadable root directory.
+
+   Implements svn_ra__vtable_t.get_uuid().
  */
 static svn_error_t *
 svn_ra_serf__get_uuid(svn_ra_session_t *ra_session,

Modified: subversion/branches/javahl-ra/subversion/libsvn_ra_serf/update.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_ra_serf/update.c?rev=1343447&r1=1343446&r2=1343447&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_ra_serf/update.c (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_ra_serf/update.c Tue May 29 01:39:41 2012
@@ -126,17 +126,10 @@ typedef struct report_dir_t
   /* Our base revision - SVN_INVALID_REVNUM if we're adding this dir. */
   svn_revnum_t base_rev;
 
-  /* The target revision we're retrieving. */
-  svn_revnum_t target_rev;
-
   /* controlling dir baton - this is only created in open_dir() */
   void *dir_baton;
   apr_pool_t *dir_baton_pool;
 
-  /* Our master update editor and baton. */
-  const svn_delta_editor_t *update_editor;
-  void *update_baton;
-
   /* How many references to this directory do we still have open? */
   apr_size_t ref_count;
 
@@ -200,9 +193,6 @@ typedef struct report_info_t
   /* Our base revision - SVN_INVALID_REVNUM if we're adding this file. */
   svn_revnum_t base_rev;
 
-  /* The target revision we're retrieving. */
-  svn_revnum_t target_rev;
-
   /* our delta base, if present (NULL if we're adding the file) */
   const char *delta_base;
 
@@ -237,6 +227,10 @@ typedef struct report_info_t
   /* Checksum for close_file */
   const char *final_checksum;
 
+  /* Stream containing file contents already cached in the working
+     copy (which may be used to avoid a GET request for the same). */
+  svn_stream_t *cached_contents;
+
   /* temporary property for this file which is currently being parsed
    * It will eventually be stored in our parent directory's property hash.
    */
@@ -252,6 +246,9 @@ typedef struct report_info_t
  */
 typedef struct report_fetch_t {
 
+  /* The handler representing this particular fetch.  */
+  svn_ra_serf__handler_t *handler;
+
   /* The session we should use to fetch the file. */
   svn_ra_serf__session_t *sess;
 
@@ -349,7 +346,7 @@ struct report_context_t {
   /* number of pending PROPFIND requests */
   unsigned int active_propfinds;
 
-  /* completed PROPFIND requests (contains propfind_context_t) */
+  /* completed PROPFIND requests (contains svn_ra_serf__propfind_context_t) */
   svn_ra_serf__list_t *done_propfinds;
 
   /* list of files that only have prop changes (contains report_info_t) */
@@ -407,9 +404,6 @@ push_state(svn_ra_serf__xml_parser_t *pa
       new_info->props = new_info->dir->props;
       new_info->dir->removed_props = apr_hash_make(new_info->pool);
 
-      /* Point to the update_editor */
-      new_info->dir->update_editor = ctx->update_editor;
-      new_info->dir->update_baton = ctx->update_baton;
       new_info->dir->report_context = ctx;
 
       if (info)
@@ -467,7 +461,7 @@ set_file_props(void *baton,
                apr_pool_t *scratch_pool)
 {
   report_info_t *info = baton;
-  const svn_delta_editor_t *editor = info->dir->update_editor;
+  const svn_delta_editor_t *editor = info->dir->report_context->update_editor;
   const char *prop_name;
 
   if (strcmp(name, "md5-checksum") == 0
@@ -492,7 +486,7 @@ set_dir_props(void *baton,
               apr_pool_t *scratch_pool)
 {
   report_dir_t *dir = baton;
-  const svn_delta_editor_t *editor = dir->update_editor;
+  const svn_delta_editor_t *editor = dir->report_context->update_editor;
   const char *prop_name;
 
   prop_name = svn_ra_serf__svnname_from_wirename(ns, name, scratch_pool);
@@ -513,7 +507,7 @@ remove_file_props(void *baton,
                   apr_pool_t *scratch_pool)
 {
   report_info_t *info = baton;
-  const svn_delta_editor_t *editor = info->dir->update_editor;
+  const svn_delta_editor_t *editor = info->dir->report_context->update_editor;
   const char *prop_name;
 
   prop_name = svn_ra_serf__svnname_from_wirename(ns, name, scratch_pool);
@@ -534,7 +528,7 @@ remove_dir_props(void *baton,
                  apr_pool_t *scratch_pool)
 {
   report_dir_t *dir = baton;
-  const svn_delta_editor_t *editor = dir->update_editor;
+  const svn_delta_editor_t *editor = dir->report_context->update_editor;
   const char *prop_name;
 
   prop_name = svn_ra_serf__svnname_from_wirename(ns, name, scratch_pool);
@@ -552,6 +546,8 @@ remove_dir_props(void *baton,
 static svn_error_t*
 open_dir(report_dir_t *dir)
 {
+  report_context_t *ctx = dir->report_context;
+
   /* if we're already open, return now */
   if (dir->dir_baton)
     {
@@ -562,16 +558,16 @@ open_dir(report_dir_t *dir)
     {
       dir->dir_baton_pool = svn_pool_create(dir->pool);
 
-      if (dir->report_context->destination &&
-          dir->report_context->sess->wc_callbacks->invalidate_wc_props)
+      if (ctx->destination
+          && ctx->sess->wc_callbacks->invalidate_wc_props)
         {
-          SVN_ERR(dir->report_context->sess->wc_callbacks->invalidate_wc_props(
-                      dir->report_context->sess->wc_callback_baton,
-                      dir->report_context->update_target,
+          SVN_ERR(ctx->sess->wc_callbacks->invalidate_wc_props(
+                      ctx->sess->wc_callback_baton,
+                      ctx->update_target,
                       SVN_RA_SERF__WC_CHECKED_IN_URL, dir->pool));
         }
 
-      SVN_ERR(dir->update_editor->open_root(dir->update_baton, dir->base_rev,
+      SVN_ERR(ctx->update_editor->open_root(ctx->update_baton, dir->base_rev,
                                             dir->dir_baton_pool,
                                             &dir->dir_baton));
     }
@@ -583,7 +579,7 @@ open_dir(report_dir_t *dir)
 
       if (SVN_IS_VALID_REVNUM(dir->base_rev))
         {
-          SVN_ERR(dir->update_editor->open_directory(dir->name,
+          SVN_ERR(ctx->update_editor->open_directory(dir->name,
                                                      dir->parent_dir->dir_baton,
                                                      dir->base_rev,
                                                      dir->dir_baton_pool,
@@ -591,7 +587,7 @@ open_dir(report_dir_t *dir)
         }
       else
         {
-          SVN_ERR(dir->update_editor->add_directory(dir->name,
+          SVN_ERR(ctx->update_editor->add_directory(dir->name,
                                                     dir->parent_dir->dir_baton,
                                                     NULL, SVN_INVALID_REVNUM,
                                                     dir->dir_baton_pool,
@@ -625,12 +621,13 @@ close_dir(report_dir_t *dir)
   if (dir->fetch_props)
     {
       SVN_ERR(svn_ra_serf__walk_all_props(dir->props, dir->url,
-                                          dir->target_rev,
+                                          dir->report_context->target_rev,
                                           set_dir_props, dir,
                                           scratch_pool));
     }
 
-  SVN_ERR(dir->update_editor->close_directory(dir->dir_baton, scratch_pool));
+  SVN_ERR(dir->report_context->update_editor->close_directory(
+            dir->dir_baton, scratch_pool));
 
   /* remove us from our parent's children list */
   if (dir->parent_dir)
@@ -694,7 +691,7 @@ check_lock(report_info_t *info)
   const char *lock_val;
 
   lock_val = svn_ra_serf__get_ver_prop(info->props, info->url,
-                                       info->target_rev,
+                                       info->dir->report_context->target_rev,
                                        "DAV:", "lockdiscovery");
 
   if (lock_val)
@@ -801,6 +798,105 @@ error_fetch(serf_request_t *request,
   return err;
 }
 
+/* Wield the editor referenced by INFO to open (or add) the file
+   file also associated with INFO, setting properties on the file and
+   calling the editor's apply_textdelta() function on it if necessary
+   (or if FORCE_APPLY_TEXTDELTA is set).
+
+   Callers will probably want to also see the function that serves
+   the opposite purpose of this one, close_updated_file().  */
+static svn_error_t *
+open_updated_file(report_info_t *info,
+                  svn_boolean_t force_apply_textdelta,
+                  apr_pool_t *scratch_pool)
+{
+  report_context_t *ctx = info->dir->report_context;
+  const svn_delta_editor_t *update_editor = ctx->update_editor;
+
+  /* Ensure our parent is open. */
+  SVN_ERR(open_dir(info->dir));
+  info->editor_pool = svn_pool_create(info->dir->dir_baton_pool);
+
+  /* Expand our full name now if we haven't done so yet. */
+  if (!info->name)
+    {
+      info->name = svn_relpath_join(info->dir->name, info->base_name,
+                                    info->editor_pool);
+    }
+
+  /* Open (or add) the file. */
+  if (SVN_IS_VALID_REVNUM(info->base_rev))
+    {
+      SVN_ERR(update_editor->open_file(info->name,
+                                       info->dir->dir_baton,
+                                       info->base_rev,
+                                       info->editor_pool,
+                                       &info->file_baton));
+    }
+  else
+    {
+      SVN_ERR(update_editor->add_file(info->name,
+                                      info->dir->dir_baton,
+                                      info->copyfrom_path,
+                                      info->copyfrom_rev,
+                                      info->editor_pool,
+                                      &info->file_baton));
+    }
+
+  /* Check for lock information. */
+  if (info->lock_token)
+    check_lock(info);
+
+  /* Set all of the properties we received */
+  SVN_ERR(svn_ra_serf__walk_all_props(info->props,
+                                      info->base_name,
+                                      info->base_rev,
+                                      set_file_props, info,
+                                      scratch_pool));
+  SVN_ERR(svn_ra_serf__walk_all_props(info->dir->removed_props,
+                                      info->base_name,
+                                      info->base_rev,
+                                      remove_file_props, info,
+                                      scratch_pool));
+  if (info->fetch_props)
+    {
+      SVN_ERR(svn_ra_serf__walk_all_props(info->props,
+                                          info->url,
+                                          ctx->target_rev,
+                                          set_file_props, info,
+                                          scratch_pool));
+    }
+
+  /* Get (maybe) a textdelta window handler for transmitting file
+     content changes. */
+  if (info->fetch_file || force_apply_textdelta)
+    {
+      SVN_ERR(update_editor->apply_textdelta(info->file_baton,
+                                             info->base_checksum,
+                                             info->editor_pool,
+                                             &info->textdelta,
+                                             &info->textdelta_baton));
+    }
+
+  return SVN_NO_ERROR;
+}
+
+/* Close the file associated with INFO->file_baton, and cleanup other
+   bits of that structure managed by open_updated_file(). */
+static svn_error_t *
+close_updated_file(report_info_t *info,
+                   apr_pool_t *scratch_pool)
+{
+  /* Close the file via the editor. */
+  SVN_ERR(info->dir->report_context->update_editor->close_file(
+            info->file_baton, info->final_checksum, scratch_pool));
+
+  /* We're done with our editor pool. */
+  svn_pool_destroy(info->editor_pool);
+
+  return SVN_NO_ERROR;
+}
+
 /* Implements svn_ra_serf__response_handler_t */
 static svn_error_t *
 handle_fetch(serf_request_t *request,
@@ -813,7 +909,9 @@ handle_fetch(serf_request_t *request,
   apr_status_t status;
   report_fetch_t *fetch_ctx = handler_baton;
   svn_error_t *err;
-  serf_status_line sl;
+
+  /* ### new field. make sure we didn't miss some initialization.  */
+  SVN_ERR_ASSERT(fetch_ctx->handler != NULL);
 
   if (fetch_ctx->read_headers == FALSE)
     {
@@ -825,50 +923,8 @@ handle_fetch(serf_request_t *request,
       val = serf_bucket_headers_get(hdrs, "Content-Type");
       info = fetch_ctx->info;
 
-      err = open_dir(info->dir);
-      if (err)
-        {
-          return error_fetch(request, fetch_ctx, err);
-        }
-
-      info->editor_pool = svn_pool_create(info->dir->dir_baton_pool);
-
-      /* Expand our full name now if we haven't done so yet. */
-      if (!info->name)
-        {
-          info->name = svn_relpath_join(info->dir->name, info->base_name,
-                                        info->editor_pool);
-        }
-
-      if (SVN_IS_VALID_REVNUM(info->base_rev))
-        {
-          err = info->dir->update_editor->open_file(info->name,
-                                                    info->dir->dir_baton,
-                                                    info->base_rev,
-                                                    info->editor_pool,
-                                                    &info->file_baton);
-        }
-      else
-        {
-          err = info->dir->update_editor->add_file(info->name,
-                                                   info->dir->dir_baton,
-                                                   info->copyfrom_path,
-                                                   info->copyfrom_rev,
-                                                   info->editor_pool,
-                                                   &info->file_baton);
-        }
-
-      if (err)
-        {
-          return error_fetch(request, fetch_ctx, err);
-        }
-
-      err = info->dir->update_editor->apply_textdelta(info->file_baton,
-                                                      info->base_checksum,
-                                                      info->editor_pool,
-                                                      &info->textdelta,
-                                                      &info->textdelta_baton);
-
+      /* Open the file for editing. */
+      err = open_updated_file(info, FALSE, info->pool);
       if (err)
         {
           return error_fetch(request, fetch_ctx, err);
@@ -891,16 +947,12 @@ handle_fetch(serf_request_t *request,
 
   /* If the error code wasn't 200, something went wrong. Don't use the returned
      data as its probably an error message. Just bail out instead. */
-  status = serf_bucket_response_status(response, &sl);
-  if (SERF_BUCKET_READ_ERROR(status))
-    {
-      return svn_error_wrap_apr(status, NULL);
-    }
-  if (sl.code != 200)
+  if (fetch_ctx->handler->sline.code != 200)
     {
       err = svn_error_createf(SVN_ERR_RA_DAV_REQUEST_FAILED, NULL,
                               _("GET request failed: %d %s"),
-                              sl.code, sl.reason);
+                              fetch_ctx->handler->sline.code,
+                              fetch_ctx->handler->sline.reason);
       return error_fetch(request, fetch_ctx, err);
     }
 
@@ -983,51 +1035,17 @@ handle_fetch(serf_request_t *request,
         {
           report_info_t *info = fetch_ctx->info;
 
-          /* ### this doesn't feel quite right. but it gets tossed at the
-             ### end of this block, so it will work for now.  */
-          apr_pool_t *scratch_pool = info->editor_pool;
-
           if (fetch_ctx->delta_stream)
             err = svn_error_trace(svn_stream_close(fetch_ctx->delta_stream));
           else
             err = svn_error_trace(info->textdelta(NULL,
                                                   info->textdelta_baton));
-
           if (err)
             {
               return error_fetch(request, fetch_ctx, err);
             }
 
-          if (info->lock_token)
-            check_lock(info);
-
-          /* set all of the properties we received */
-          err = svn_ra_serf__walk_all_props(info->props,
-                                            info->base_name,
-                                            info->base_rev,
-                                            set_file_props, info,
-                                            scratch_pool);
-
-          if (!err)
-            err = svn_ra_serf__walk_all_props(info->dir->removed_props,
-                                              info->base_name,
-                                              info->base_rev,
-                                              remove_file_props, info,
-                                              scratch_pool);
-          if (!err && info->fetch_props)
-            {
-              err = svn_ra_serf__walk_all_props(info->props,
-                                                info->url,
-                                                info->target_rev,
-                                                set_file_props, info,
-                                                scratch_pool);
-            }
-
-          if (!err)
-            err = info->dir->update_editor->close_file(info->file_baton,
-                                                       info->final_checksum,
-                                                       scratch_pool);
-
+          err = close_updated_file(info, info->pool);
           if (err)
             {
               return svn_error_trace(error_fetch(request, fetch_ctx, err));
@@ -1039,8 +1057,7 @@ handle_fetch(serf_request_t *request,
           fetch_ctx->done_item.next = *fetch_ctx->done_list;
           *fetch_ctx->done_list = &fetch_ctx->done_item;
 
-          /* We're done with our pools. */
-          svn_pool_destroy(info->editor_pool);
+          /* We're done with our pool. */
           svn_pool_destroy(info->pool);
 
           if (status)
@@ -1062,26 +1079,22 @@ handle_stream(serf_request_t *request,
               apr_pool_t *pool)
 {
   report_fetch_t *fetch_ctx = handler_baton;
-  serf_status_line sl;
   const char *location;
   svn_error_t *err;
   apr_status_t status;
 
-  status = serf_bucket_response_status(response, &sl);
-  if (SERF_BUCKET_READ_ERROR(status))
-    {
-      return svn_error_wrap_apr(status, NULL);
-    }
+  /* ### new field. make sure we didn't miss some initialization.  */
+  SVN_ERR_ASSERT(fetch_ctx->handler != NULL);
 
   /* Woo-hoo.  Nothing here to see.  */
   location = svn_ra_serf__response_get_location(response, pool);
 
-  err = svn_ra_serf__error_on_status(sl.code,
+  err = svn_ra_serf__error_on_status(fetch_ctx->handler->sline.code,
                                      fetch_ctx->info->name,
                                      location);
   if (err)
     {
-      fetch_ctx->done = TRUE;
+      fetch_ctx->handler->done = TRUE;
 
       err = svn_error_compose_create(
                   err,
@@ -1157,78 +1170,100 @@ static svn_error_t *
 handle_propchange_only(report_info_t *info,
                        apr_pool_t *scratch_pool)
 {
-  /* Ensure our parent is open. */
-  SVN_ERR(open_dir(info->dir));
+  /* Open the file for editing (without forcing an apply_textdelta),
+     pass along any propchanges we've recorded for it, and then close
+     the file. */
+  SVN_ERR(open_updated_file(info, FALSE, scratch_pool));
+  SVN_ERR(close_updated_file(info, scratch_pool));
+  
+  /* We're done with our pool. */
+  svn_pool_destroy(info->pool);
 
-  info->editor_pool = svn_pool_create(info->dir->dir_baton_pool);
+  info->dir->ref_count--;
 
-  /* Expand our full name now if we haven't done so yet. */
-  if (!info->name)
-    {
-      info->name = svn_relpath_join(info->dir->name, info->base_name,
-                                    info->editor_pool);
-    }
+  return SVN_NO_ERROR;
+}
 
-  if (SVN_IS_VALID_REVNUM(info->base_rev))
-    {
-      SVN_ERR(info->dir->update_editor->open_file(info->name,
-                                                  info->dir->dir_baton,
-                                                  info->base_rev,
-                                                  info->editor_pool,
-                                                  &info->file_baton));
-    }
-  else
-    {
-      SVN_ERR(info->dir->update_editor->add_file(info->name,
-                                                 info->dir->dir_baton,
-                                                 info->copyfrom_path,
-                                                 info->copyfrom_rev,
-                                                 info->editor_pool,
-                                                 &info->file_baton));
-    }
+/* "Fetch" a file whose contents were made available via the
+   get_wc_contents() callback (as opposed to requiring a GET to the
+   server), and feed the information through the associated update
+   editor. */
+static svn_error_t *
+local_fetch(report_info_t *info,
+            apr_pool_t *scratch_pool)
+{
+  SVN_ERR(open_updated_file(info, TRUE, scratch_pool));
+
+  SVN_ERR(svn_txdelta_send_stream(info->cached_contents, info->textdelta,
+                                  info->textdelta_baton, NULL, scratch_pool));
+  SVN_ERR(svn_stream_close(info->cached_contents));
+  info->cached_contents = NULL;
+  SVN_ERR(close_updated_file(info, scratch_pool));
 
-  if (info->fetch_file)
-    {
-      SVN_ERR(info->dir->update_editor->apply_textdelta(info->file_baton,
-                                                    info->base_checksum,
-                                                    info->editor_pool,
-                                                    &info->textdelta,
-                                                    &info->textdelta_baton));
-    }
+  /* We're done with our pool. */
+  svn_pool_destroy(info->pool);
 
-  if (info->lock_token)
-    check_lock(info);
+  return SVN_NO_ERROR;
+}
 
-  /* set all of the properties we received */
-  SVN_ERR(svn_ra_serf__walk_all_props(info->props,
-                                      info->base_name, info->base_rev,
-                                      set_file_props, info,
-                                      scratch_pool));
-  SVN_ERR(svn_ra_serf__walk_all_props(info->dir->removed_props,
-                                      info->base_name, info->base_rev,
-                                      remove_file_props, info,
-                                      scratch_pool));
-  if (info->fetch_props)
-    {
-      SVN_ERR(svn_ra_serf__walk_all_props(info->props, info->url,
-                                          info->target_rev,
-                                          set_file_props, info,
-                                          scratch_pool));
-    }
+/* Implements svn_ra_serf__response_handler_t */
+static svn_error_t *
+handle_local_fetch(serf_request_t *request,
+                   serf_bucket_t *response,
+                   void *handler_baton,
+                   apr_pool_t *pool)
+{
+  report_fetch_t *fetch_ctx = handler_baton;
+  apr_status_t status;
+  svn_error_t *err;
+  const char *data;
+  apr_size_t len;
 
-  SVN_ERR(info->dir->update_editor->close_file(info->file_baton,
-                                               info->final_checksum,
-                                               scratch_pool));
+  /* ### new field. make sure we didn't miss some initialization.  */
+  SVN_ERR_ASSERT(fetch_ctx->handler != NULL);
 
-  /* We're done with our pools. */
-  svn_pool_destroy(info->editor_pool);
-  svn_pool_destroy(info->pool);
+  /* If the error code wasn't 200, something went wrong. Don't use the returned
+     data as its probably an error message. Just bail out instead. */
+  if (fetch_ctx->handler->sline.code != 200)
+    {
+      err = svn_error_createf(SVN_ERR_RA_DAV_REQUEST_FAILED, NULL,
+                              _("HEAD request failed: %d %s"),
+                              fetch_ctx->handler->sline.code,
+                              fetch_ctx->handler->sline.reason);
+      return error_fetch(request, fetch_ctx, err);
+    }
 
-  info->dir->ref_count--;
+  while (1)
+    {
+      status = serf_bucket_read(response, 8000, &data, &len);
+      if (SERF_BUCKET_READ_ERROR(status))
+        {
+          return svn_error_wrap_apr(status, NULL);
+        }
+      if (APR_STATUS_IS_EOF(status))
+        {
+          err = local_fetch(fetch_ctx->info, fetch_ctx->info->pool);
+          if (err)
+            {
+              return error_fetch(request, fetch_ctx, err);
+            }
 
-  return SVN_NO_ERROR;
+          fetch_ctx->done = TRUE;
+          fetch_ctx->done_item.data = fetch_ctx;
+          fetch_ctx->done_item.next = *fetch_ctx->done_list;
+          *fetch_ctx->done_list = &fetch_ctx->done_item;
+          return svn_error_wrap_apr(status, NULL);
+        }
+      if (APR_STATUS_IS_EAGAIN(status))
+        {
+          return svn_error_wrap_apr(status, NULL);
+        }
+    }
+  /* not reached */
 }
 
+/* --------------------------------------------------------- */
+
 static svn_error_t *
 fetch_file(report_context_t *ctx, report_info_t *info)
 {
@@ -1239,9 +1274,8 @@ fetch_file(report_context_t *ctx, report
   conn = ctx->sess->conns[ctx->sess->cur_conn];
 
   /* go fetch info->name from DAV:checked-in */
-  info->url =
-      svn_ra_serf__get_ver_prop(info->props, info->base_name,
-                                info->base_rev, "DAV:", "checked-in");
+  info->url = svn_ra_serf__get_ver_prop(info->props, info->base_name,
+                                        info->base_rev, "DAV:", "checked-in");
 
   if (!info->url)
     {
@@ -1256,7 +1290,7 @@ fetch_file(report_context_t *ctx, report
     {
       SVN_ERR(svn_ra_serf__deliver_props(&info->propfind, info->props,
                                          ctx->sess, conn, info->url,
-                                         info->target_rev, "0", all_props,
+                                         ctx->target_rev, "0", all_props,
                                          &ctx->done_propfinds,
                                          info->dir->pool));
       SVN_ERR_ASSERT(info->propfind);
@@ -1269,34 +1303,104 @@ fetch_file(report_context_t *ctx, report
    */
   if (info->fetch_file && ctx->text_deltas)
     {
-      report_fetch_t *fetch_ctx;
+      svn_stream_t *contents = NULL;
 
-      fetch_ctx = apr_pcalloc(info->dir->pool, sizeof(*fetch_ctx));
-      fetch_ctx->info = info;
-      fetch_ctx->done_list = &ctx->done_fetches;
-      fetch_ctx->sess = ctx->sess;
-      fetch_ctx->conn = conn;
+      if (ctx->sess->wc_callbacks->get_wc_contents
+          && info->final_sha1_checksum)
+        {
+          svn_error_t *err;
+          svn_checksum_t *sha1_checksum;
 
-      handler = apr_pcalloc(info->dir->pool, sizeof(*handler));
+          err = svn_checksum_parse_hex(&sha1_checksum, svn_checksum_sha1,
+                                       info->final_sha1_checksum, info->pool);
+          if (!err)
+            {
+              err = ctx->sess->wc_callbacks->get_wc_contents(
+                        ctx->sess->wc_callback_baton, &contents,
+                        sha1_checksum, info->pool);
+            }
 
-      handler->method = "GET";
-      handler->path = fetch_ctx->info->url;
+          if (err)
+            {
+              /* Meh.  Maybe we'll care one day why we're in an
+                 errorful state, but this codepath is optional.  */
+              svn_error_clear(err);
+            }
+          else
+            {
+              info->cached_contents = contents;
+            }
+        }          
 
-      handler->conn = conn;
-      handler->session = ctx->sess;
+      /* If the working copy can provided cached contents for this
+         file, we'll send a simple HEAD request (which I'll claim is
+         to verify readability, but really is just so I can provide a
+         Serf-queued-request-compliant way of processing the contents
+         after the PROPFIND for the file's properties ... ugh).
 
-      handler->header_delegate = headers_fetch;
-      handler->header_delegate_baton = fetch_ctx;
+         Otherwise, we use a GET request for the file's contents. */
+      if (info->cached_contents)
+        {
+          report_fetch_t *fetch_ctx;
 
-      handler->response_handler = handle_fetch;
-      handler->response_baton = fetch_ctx;
+          fetch_ctx = apr_pcalloc(info->dir->pool, sizeof(*fetch_ctx));
+          fetch_ctx->info = info;
+          fetch_ctx->done_list = &ctx->done_fetches;
+          fetch_ctx->sess = ctx->sess;
+          fetch_ctx->conn = conn;
 
-      handler->response_error = cancel_fetch;
-      handler->response_error_baton = fetch_ctx;
+          handler = apr_pcalloc(info->dir->pool, sizeof(*handler));
 
-      svn_ra_serf__request_create(handler);
+          handler->handler_pool = info->dir->pool;
+          handler->method = "HEAD";
+          handler->path = fetch_ctx->info->url;
+
+          handler->conn = conn;
+          handler->session = ctx->sess;
+
+          handler->response_handler = handle_local_fetch;
+          handler->response_baton = fetch_ctx;
+
+          fetch_ctx->handler = handler;
+
+          svn_ra_serf__request_create(handler);
+
+          ctx->active_fetches++;
+        }
+      else
+        {
+          report_fetch_t *fetch_ctx;
 
-      ctx->active_fetches++;
+          fetch_ctx = apr_pcalloc(info->dir->pool, sizeof(*fetch_ctx));
+          fetch_ctx->info = info;
+          fetch_ctx->done_list = &ctx->done_fetches;
+          fetch_ctx->sess = ctx->sess;
+          fetch_ctx->conn = conn;
+
+          handler = apr_pcalloc(info->dir->pool, sizeof(*handler));
+
+          handler->handler_pool = info->dir->pool;
+          handler->method = "GET";
+          handler->path = fetch_ctx->info->url;
+
+          handler->conn = conn;
+          handler->session = ctx->sess;
+
+          handler->header_delegate = headers_fetch;
+          handler->header_delegate_baton = fetch_ctx;
+
+          handler->response_handler = handle_fetch;
+          handler->response_baton = fetch_ctx;
+
+          handler->response_error = cancel_fetch;
+          handler->response_error_baton = fetch_ctx;
+
+          fetch_ctx->handler = handler;
+
+          svn_ra_serf__request_create(handler);
+
+          ctx->active_fetches++;
+        }
     }
   else if (info->propfind)
     {
@@ -1373,7 +1477,6 @@ start_report(svn_ra_serf__xml_parser_t *
 
       info->base_rev = SVN_STR_TO_REV(rev);
       info->dir->base_rev = info->base_rev;
-      info->dir->target_rev = ctx->target_rev;
       info->fetch_props = TRUE;
 
       info->dir->base_name = "";
@@ -1426,7 +1529,6 @@ start_report(svn_ra_serf__xml_parser_t *
 
       info->base_rev = SVN_STR_TO_REV(rev);
       dir->base_rev = info->base_rev;
-      dir->target_rev = ctx->target_rev;
 
       info->fetch_props = FALSE;
 
@@ -1480,7 +1582,6 @@ start_report(svn_ra_serf__xml_parser_t *
       /* Mark that we don't have a base. */
       info->base_rev = SVN_INVALID_REVNUM;
       dir->base_rev = info->base_rev;
-      dir->target_rev = ctx->target_rev;
       dir->fetch_props = TRUE;
 
       dir->repos_relpath = svn_relpath_join(dir->parent_dir->repos_relpath,
@@ -1513,7 +1614,6 @@ start_report(svn_ra_serf__xml_parser_t *
       info = push_state(parser, ctx, OPEN_FILE);
 
       info->base_rev = SVN_STR_TO_REV(rev);
-      info->target_rev = ctx->target_rev;
       info->fetch_props = FALSE;
 
       info->base_name = apr_pstrdup(info->pool, file_name);
@@ -1539,7 +1639,6 @@ start_report(svn_ra_serf__xml_parser_t *
       info = push_state(parser, ctx, ADD_FILE);
 
       info->base_rev = SVN_INVALID_REVNUM;
-      info->target_rev = ctx->target_rev;
       info->fetch_props = TRUE;
       info->fetch_file = TRUE;
 
@@ -1586,10 +1685,10 @@ start_report(svn_ra_serf__xml_parser_t *
 
       full_path = svn_relpath_join(info->dir->name, file_name, tmppool);
 
-      SVN_ERR(info->dir->update_editor->delete_entry(full_path,
-                                                     delete_rev,
-                                                     info->dir->dir_baton,
-                                                     tmppool));
+      SVN_ERR(ctx->update_editor->delete_entry(full_path,
+                                               delete_rev,
+                                               info->dir->dir_baton,
+                                               tmppool));
 
       svn_pool_destroy(tmppool);
     }
@@ -1852,7 +1951,7 @@ end_report(svn_ra_serf__xml_parser_t *pa
                                              info->dir->props, ctx->sess,
                                              ctx->sess->conns[ctx->sess->cur_conn],
                                              info->dir->url,
-                                             info->dir->target_rev, "0",
+                                             ctx->target_rev, "0",
                                              all_props,
                                              &ctx->done_propfinds,
                                              info->dir->pool));
@@ -2295,7 +2394,6 @@ finish_report(void *report_baton,
   svn_ra_serf__xml_parser_t *parser_ctx;
   const char *report_target;
   svn_boolean_t closed_root;
-  int status_code;
   svn_stringbuf_t *buf = NULL;
   apr_pool_t *iterpool = svn_pool_create(pool);
   svn_error_t *err;
@@ -2325,6 +2423,7 @@ finish_report(void *report_baton,
 
   handler = apr_pcalloc(pool, sizeof(*handler));
 
+  handler->handler_pool = pool;
   handler->method = "REPORT";
   handler->path = report->path;
   handler->body_delegate = create_update_report_body;
@@ -2344,9 +2443,6 @@ finish_report(void *report_baton,
   parser_ctx->end = end_report;
   parser_ctx->cdata = cdata_report;
   parser_ctx->done = &report->done;
-  /* While we provide a location here to store the status code, we don't
-     do anything with it. The error in parser_ctx->error is sufficient. */
-  parser_ctx->status_code = &status_code;
 
   handler->response_handler = svn_ra_serf__handle_xml_parser;
   handler->response_baton = parser_ctx;
@@ -2788,7 +2884,7 @@ svn_ra_serf__get_file(svn_ra_session_t *
   svn_ra_serf__connection_t *conn;
   const char *fetch_url;
   apr_hash_t *fetch_props;
-  svn_node_kind_t res_kind;
+  svn_kind_t res_kind;
 
   /* What connection should we go on? */
   conn = session->conns[session->cur_conn];
@@ -2804,24 +2900,23 @@ svn_ra_serf__get_file(svn_ra_session_t *
    */
   if (SVN_IS_VALID_REVNUM(revision) || fetched_rev)
     {
-      const char *baseline_url, *rel_path;
-
-      SVN_ERR(svn_ra_serf__get_baseline_info(&baseline_url, &rel_path,
-                                             session, conn, fetch_url,
-                                             revision, fetched_rev, pool));
-      fetch_url = svn_path_url_add_component2(baseline_url, rel_path, pool);
+      SVN_ERR(svn_ra_serf__get_stable_url(&fetch_url, fetched_rev,
+                                          session, conn,
+                                          fetch_url, revision,
+                                          pool, pool));
       revision = SVN_INVALID_REVNUM;
     }
+  /* REVISION is always SVN_INVALID_REVNUM  */
+  SVN_ERR_ASSERT(!SVN_IS_VALID_REVNUM(revision));
 
-  SVN_ERR(svn_ra_serf__retrieve_props(&fetch_props, session, conn, fetch_url,
-                                      revision, "0",
-                                      props ? all_props : check_path_props,
-                                      pool, pool));
-
-  /* Verify that resource type is not colelction. */
-  SVN_ERR(svn_ra_serf__get_resource_type(&res_kind, fetch_props, fetch_url,
-                                         revision));
-  if (res_kind != svn_node_file)
+  SVN_ERR(svn_ra_serf__fetch_node_props(&fetch_props, conn, fetch_url,
+                                        SVN_INVALID_REVNUM,
+                                        props ? all_props : check_path_props,
+                                        pool, pool));
+
+  /* Verify that resource type is not collection. */
+  SVN_ERR(svn_ra_serf__get_resource_type(&res_kind, fetch_props));
+  if (res_kind != svn_kind_file)
     {
       return svn_error_create(SVN_ERR_FS_NOT_FILE, NULL,
                               _("Can't get text contents of a directory"));
@@ -2830,8 +2925,10 @@ svn_ra_serf__get_file(svn_ra_session_t *
   /* TODO Filter out all of our props into a usable format. */
   if (props)
     {
-      SVN_ERR(svn_ra_serf__flatten_props(props, fetch_props, fetch_url,
-                                         revision, pool, pool));
+      /* ### flatten_props() does not copy PROPVALUE, but fetch_node_props()
+         ### put them into POOL, so we're okay.  */
+      SVN_ERR(svn_ra_serf__flatten_props(props, fetch_props,
+                                         pool, pool));
     }
 
   if (stream)
@@ -2848,6 +2945,8 @@ svn_ra_serf__get_file(svn_ra_session_t *
       stream_ctx->info->name = fetch_url;
 
       handler = apr_pcalloc(pool, sizeof(*handler));
+
+      handler->handler_pool = pool;
       handler->method = "GET";
       handler->path = fetch_url;
       handler->conn = conn;
@@ -2862,6 +2961,8 @@ svn_ra_serf__get_file(svn_ra_session_t *
       handler->response_error = cancel_fetch;
       handler->response_error_baton = stream_ctx;
 
+      stream_ctx->handler = handler;
+
       svn_ra_serf__request_create(handler);
 
       SVN_ERR(svn_ra_serf__context_run_wait(&stream_ctx->done, session, pool));