You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by br...@apache.org on 2014/01/09 10:31:15 UTC

svn commit: r1556765 [6/12] - in /subversion/branches/fsfs-ucsnorm: ./ contrib/server-side/fsfsfixer/fixer/ subversion/bindings/javahl/native/ subversion/bindings/javahl/native/jniwrapper/ subversion/bindings/javahl/src/org/apache/subversion/javahl/ su...

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/commit.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/commit.c?rev=1556765&r1=1556764&r2=1556765&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/commit.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/commit.c Thu Jan  9 09:31:10 2014
@@ -83,7 +83,7 @@ typedef struct proppatch_context_t {
   const char *relpath;
   const char *path;
 
-  commit_context_t *commit;
+  commit_context_t *commit_ctx;
 
   /* Changed and removed properties. */
   apr_hash_t *changed_props;
@@ -99,14 +99,11 @@ typedef struct proppatch_context_t {
 } proppatch_context_t;
 
 typedef struct delete_context_t {
-  const char *path;
+  const char *relpath;
 
   svn_revnum_t revision;
 
-  const char *lock_token;
-  apr_hash_t *lock_token_hash;
-  svn_boolean_t keep_locks;
-
+  commit_context_t *commit_ctx;
 } delete_context_t;
 
 /* Represents a directory. */
@@ -115,7 +112,7 @@ typedef struct dir_context_t {
   apr_pool_t *pool;
 
   /* The root commit we're in progress for. */
-  commit_context_t *commit;
+  commit_context_t *commit_ctx;
 
   /* URL to operate against (used for CHECKOUT and PROPPATCH before
      HTTP v2, for PROPPATCH in HTTP v2).  */
@@ -149,7 +146,6 @@ typedef struct dir_context_t {
   /* The checked-out working resource for this directory.  May be NULL; if so
      call checkout_dir() first.  */
   const char *working_url;
-
 } dir_context_t;
 
 /* Represents a file to be committed. */
@@ -158,7 +154,7 @@ typedef struct file_context_t {
   apr_pool_t *pool;
 
   /* The root commit we're in progress for. */
-  commit_context_t *commit;
+  commit_context_t *commit_ctx;
 
   /* Is this file being added?  (Otherwise, just opened.) */
   svn_boolean_t added;
@@ -202,33 +198,6 @@ typedef struct file_context_t {
 
 /* Setup routines and handlers for various requests we'll invoke. */
 
-static svn_error_t *
-return_response_err(svn_ra_serf__handler_t *handler)
-{
-  svn_error_t *err;
-
-  /* We should have captured SLINE and LOCATION in the HANDLER.  */
-  SVN_ERR_ASSERT(handler->handler_pool != NULL);
-
-  /* Ye Olde Fallback Error */
-  err = svn_error_compose_create(
-            handler->server_error != NULL
-              ? handler->server_error->error
-              : SVN_NO_ERROR,
-            svn_error_createf(SVN_ERR_RA_DAV_REQUEST_FAILED, NULL,
-                              _("%s of '%s': %d %s"),
-                              handler->method, handler->path,
-                              handler->sline.code, handler->sline.reason));
-
-  /* Try to return one of the standard errors for 301, 404, etc.,
-     then look for an error embedded in the response.  */
-  return svn_error_compose_create(svn_ra_serf__error_on_status(
-                                    handler->sline,
-                                    handler->path,
-                                    handler->location),
-                                  err);
-}
-
 /* Implements svn_ra_serf__request_body_delegate_t */
 static svn_error_t *
 create_checkout_body(serf_bucket_t **bkt,
@@ -291,32 +260,32 @@ checkout_node(const char **working_url,
               apr_pool_t *result_pool,
               apr_pool_t *scratch_pool)
 {
-  svn_ra_serf__handler_t handler = { 0 };
+  svn_ra_serf__handler_t *handler;
   apr_status_t status;
   apr_uri_t uri;
 
   /* HANDLER_POOL is the scratch pool since we don't need to remember
      anything from the handler. We just want the working resource.  */
-  handler.handler_pool = scratch_pool;
-  handler.session = commit_ctx->session;
-  handler.conn = commit_ctx->conn;
-
-  handler.body_delegate = create_checkout_body;
-  handler.body_delegate_baton = (/* const */ void *)commit_ctx->activity_url;
-  handler.body_type = "text/xml";
+  handler = svn_ra_serf__create_handler(scratch_pool);
+  handler->session = commit_ctx->session;
+  handler->conn = commit_ctx->conn;
+
+  handler->body_delegate = create_checkout_body;
+  handler->body_delegate_baton = (/* const */ void *)commit_ctx->activity_url;
+  handler->body_type = "text/xml";
 
-  handler.response_handler = svn_ra_serf__expect_empty_body;
-  handler.response_baton = &handler;
+  handler->response_handler = svn_ra_serf__expect_empty_body;
+  handler->response_baton = &handler;
 
-  handler.method = "CHECKOUT";
-  handler.path = node_url;
+  handler->method = "CHECKOUT";
+  handler->path = node_url;
 
-  SVN_ERR(svn_ra_serf__context_run_one(&handler, scratch_pool));
+  SVN_ERR(svn_ra_serf__context_run_one(handler, scratch_pool));
 
-  if (handler.sline.code != 201)
-    return svn_error_trace(return_response_err(&handler));
+  if (handler->sline.code != 201)
+    return svn_error_trace(svn_ra_serf__unexpected_status(handler));
 
-  if (handler.location == NULL)
+  if (handler->location == NULL)
     return svn_error_create(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL,
                             _("No Location header received"));
 
@@ -325,7 +294,7 @@ checkout_node(const char **working_url,
      'https:' transaction ... we'll work around that by stripping the
      scheme, host, and port here and re-adding the correct ones
      later.  */
-  status = apr_uri_parse(scratch_pool, handler.location, &uri);
+  status = apr_uri_parse(scratch_pool, handler->location, &uri);
   if (status)
     return svn_error_create(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL,
                             _("Error parsing Location header value"));
@@ -371,11 +340,11 @@ retry_checkout_node(const char **working
          error and retry a few times, asking for the latest baseline
          again. */
       if (err && (err->apr_err != SVN_ERR_APMOD_BAD_BASELINE))
-        return err;
+        return svn_error_trace(err);
     }
   while (err && retry_count--);
 
-  return err;
+  return svn_error_trace(err);
 }
 
 
@@ -383,7 +352,6 @@ static svn_error_t *
 checkout_dir(dir_context_t *dir,
              apr_pool_t *scratch_pool)
 {
-  svn_error_t *err;
   dir_context_t *c_dir = dir;
   const char *checkout_url;
   const char **working;
@@ -420,10 +388,10 @@ checkout_dir(dir_context_t *dir,
    * once to checkout the directory itself if we need to do so.
    * Note: CHECKOUT_URL should live longer than HANDLER.
    */
-  if (!dir->parent_dir && !dir->commit->baseline_url)
+  if (!dir->parent_dir && !dir->commit_ctx->baseline_url)
     {
-      checkout_url = dir->commit->vcc_url;
-      working = &dir->commit->baseline_url;
+      checkout_url = dir->commit_ctx->vcc_url;
+      working = &dir->commit_ctx->baseline_url;
     }
   else
     {
@@ -432,18 +400,9 @@ checkout_dir(dir_context_t *dir,
     }
 
   /* Checkout our directory into the activity URL now. */
-  err = retry_checkout_node(working, dir->commit, checkout_url,
-                            dir->pool, scratch_pool);
-  if (err)
-    {
-      if (err->apr_err == SVN_ERR_FS_CONFLICT)
-        SVN_ERR_W(err, apr_psprintf(scratch_pool,
-                  _("Directory '%s' is out of date; try updating"),
-                  svn_dirent_local_style(dir->relpath, scratch_pool)));
-      return err;
-    }
-
-  return SVN_NO_ERROR;
+  return svn_error_trace(retry_checkout_node(working, dir->commit_ctx,
+                                             checkout_url,
+                                             dir->pool, scratch_pool));
 }
 
 
@@ -542,7 +501,6 @@ static svn_error_t *
 checkout_file(file_context_t *file,
               apr_pool_t *scratch_pool)
 {
-  svn_error_t *err;
   dir_context_t *parent_dir = file->parent_dir;
   const char *checkout_url;
 
@@ -566,23 +524,14 @@ checkout_file(file_context_t *file,
     }
 
   SVN_ERR(get_version_url(&checkout_url,
-                          file->commit->session,
+                          file->commit_ctx->session,
                           file->relpath, file->base_revision,
                           NULL, scratch_pool, scratch_pool));
 
   /* Checkout our file into the activity URL now. */
-  err = retry_checkout_node(&file->working_url, file->commit, checkout_url,
-                            file->pool, scratch_pool);
-  if (err)
-    {
-      if (err->apr_err == SVN_ERR_FS_CONFLICT)
-        SVN_ERR_W(err, apr_psprintf(scratch_pool,
-                  _("File '%s' is out of date; try updating"),
-                  svn_dirent_local_style(file->relpath, scratch_pool)));
-      return err;
-    }
-
-  return SVN_NO_ERROR;
+  return svn_error_trace(retry_checkout_node(&file->working_url,
+                                             file->commit_ctx, checkout_url,
+                                              file->pool, scratch_pool));
 }
 
 /* Helper function for proppatch_walker() below. */
@@ -731,6 +680,8 @@ proppatch_walker(void *baton,
     prop_name = apr_pstrcat(wb->body_pool, "S:", name, SVN_VA_NULL);
   else if (strcmp(ns, SVN_DAV_PROP_NS_CUSTOM) == 0)
     prop_name = apr_pstrcat(wb->body_pool, "C:", name, SVN_VA_NULL);
+  else
+    SVN_ERR_MALFUNCTION();
 
   if (cdata_bkt)
     svn_ra_serf__add_open_tag_buckets(body_bkt, alloc, prop_name,
@@ -806,7 +757,7 @@ maybe_set_lock_token_header(serf_bucket_
 {
   const char *token;
 
-  if (! (relpath && commit_ctx->lock_tokens))
+  if (! (*relpath && commit_ctx->lock_tokens))
     return SVN_NO_ERROR;
 
   if (! svn_hash_gets(commit_ctx->deleted_entries, relpath))
@@ -848,20 +799,14 @@ setup_proppatch_headers(serf_bucket_t *h
                                            proppatch->base_revision));
     }
 
-  SVN_ERR(maybe_set_lock_token_header(headers, proppatch->commit,
-                                      proppatch->relpath, pool));
+  if (proppatch->relpath && proppatch->commit_ctx)
+    SVN_ERR(maybe_set_lock_token_header(headers, proppatch->commit_ctx,
+                                        proppatch->relpath, pool));
 
   return SVN_NO_ERROR;
 }
 
 
-struct proppatch_body_baton_t {
-  proppatch_context_t *proppatch;
-
-  /* Content in the body should be allocated here, to live long enough.  */
-  apr_pool_t *body_pool;
-};
-
 /* Implements svn_ra_serf__request_body_delegate_t */
 static svn_error_t *
 create_proppatch_body(serf_bucket_t **bkt,
@@ -869,8 +814,7 @@ create_proppatch_body(serf_bucket_t **bk
                       serf_bucket_alloc_t *alloc,
                       apr_pool_t *scratch_pool)
 {
-  struct proppatch_body_baton_t *pbb = baton;
-  proppatch_context_t *ctx = pbb->proppatch;
+  proppatch_context_t *ctx = baton;
   serf_bucket_t *body_bkt;
   walker_baton_t wb = { 0 };
 
@@ -885,7 +829,7 @@ create_proppatch_body(serf_bucket_t **bk
                                     SVN_VA_NULL);
 
   wb.body_bkt = body_bkt;
-  wb.body_pool = pbb->body_pool;
+  wb.body_pool = scratch_pool;
   wb.previous_changed_props = ctx->previous_changed_props;
   wb.previous_removed_props = ctx->previous_removed_props;
   wb.path = ctx->path;
@@ -945,45 +889,49 @@ create_proppatch_body(serf_bucket_t **bk
 }
 
 static svn_error_t*
-proppatch_resource(proppatch_context_t *proppatch,
-                   commit_context_t *commit,
+proppatch_resource(svn_ra_serf__session_t *session,
+                   svn_ra_serf__connection_t *conn,
+                   proppatch_context_t *proppatch,
                    apr_pool_t *pool)
 {
   svn_ra_serf__handler_t *handler;
-  struct proppatch_body_baton_t pbb;
+  svn_error_t *err;
+
+  handler = svn_ra_serf__create_handler(pool);
 
-  handler = apr_pcalloc(pool, sizeof(*handler));
-  handler->handler_pool = pool;
   handler->method = "PROPPATCH";
   handler->path = proppatch->path;
-  handler->conn = commit->conn;
-  handler->session = commit->session;
+  handler->conn = conn;
+  handler->session = session;
 
   handler->header_delegate = setup_proppatch_headers;
   handler->header_delegate_baton = proppatch;
 
-  pbb.proppatch = proppatch;
-  pbb.body_pool = pool;
   handler->body_delegate = create_proppatch_body;
-  handler->body_delegate_baton = &pbb;
+  handler->body_delegate_baton = proppatch;
 
   handler->response_handler = svn_ra_serf__handle_multistatus_only;
   handler->response_baton = handler;
 
-  SVN_ERR(svn_ra_serf__context_run_one(handler, pool));
+  err = svn_ra_serf__context_run_one(handler, pool);
 
-  if (handler->sline.code != 207
-      || (handler->server_error != NULL
-          && handler->server_error->error != NULL))
-    {
-      return svn_error_create(
-               SVN_ERR_RA_DAV_PROPPATCH_FAILED,
-               return_response_err(handler),
-               _("At least one property change failed; repository"
-                 " is unchanged"));
+  if (!err && handler->sline.code != 207)
+    err = svn_error_trace(svn_ra_serf__unexpected_status(handler));
+
+  /* Use specific error code for property handling errors.
+     Use loop to provide the right result with tracing */
+  if (err && err->apr_err == SVN_ERR_RA_DAV_REQUEST_FAILED)
+    {
+      svn_error_t *e = err;
+
+      while (e && e->apr_err == SVN_ERR_RA_DAV_REQUEST_FAILED)
+        {
+          e->apr_err = SVN_ERR_RA_DAV_PROPPATCH_FAILED;
+          e = e->child;
+        }
     }
 
-  return SVN_NO_ERROR;
+  return svn_error_trace(err);
 }
 
 /* Implements svn_ra_serf__request_body_delegate_t */
@@ -1052,7 +1000,7 @@ setup_put_headers(serf_bucket_t *headers
                               ctx->result_checksum);
     }
 
-  SVN_ERR(maybe_set_lock_token_header(headers, ctx->commit,
+  SVN_ERR(maybe_set_lock_token_header(headers, ctx->commit_ctx,
                                       ctx->relpath, pool));
 
   return APR_SUCCESS;
@@ -1068,19 +1016,105 @@ setup_copy_file_headers(serf_bucket_t *h
   const char *absolute_uri;
 
   /* The Dest URI must be absolute.  Bummer. */
-  uri = file->commit->session->session_url;
+  uri = file->commit_ctx->session->session_url;
   uri.path = (char*)file->url;
   absolute_uri = apr_uri_unparse(pool, &uri, 0);
 
   serf_bucket_headers_set(headers, "Destination", absolute_uri);
 
-  serf_bucket_headers_setn(headers, "Depth", "0");
-  serf_bucket_headers_setn(headers, "Overwrite", "T");
+  serf_bucket_headers_setn(headers, "Overwrite", "F");
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+setup_if_header_recursive(svn_boolean_t *added,
+                          serf_bucket_t *headers,
+                          commit_context_t *commit_ctx,
+                          const char *rq_relpath,
+                          apr_pool_t *pool)
+{
+  svn_stringbuf_t *sb = NULL;
+  apr_hash_index_t *hi;
+  apr_pool_t *iterpool = NULL;
+
+  if (!commit_ctx->lock_tokens)
+    return SVN_NO_ERROR;
+
+  /* We try to create a directory, so within the Subversion world that
+     would imply that there is nothing here, but mod_dav_svn still sees
+     locks on the old nodes here as in DAV it is perfectly legal to lock
+     something that is not there...
+
+     Let's make mod_dav, mod_dav_svn and the DAV RFC happy by providing
+     the locks we know of with the request */
+
+  for (hi = apr_hash_first(pool, commit_ctx->lock_tokens);
+       hi;
+       hi = apr_hash_next(hi))
+    {
+      const char *relpath = svn__apr_hash_index_key(hi);
+      apr_uri_t uri;
+
+      if (!svn_relpath_skip_ancestor(rq_relpath, relpath))
+        continue;
+      else if (svn_hash_gets(commit_ctx->deleted_entries, relpath))
+        {
+          /* When a path is already explicit deleted then its lock
+             will be removed by mod_dav. But mod_dav doesn't remove
+             locks on descendants */
+          continue;
+        }
+
+      if (!iterpool)
+        iterpool = svn_pool_create(pool);
+      else
+        svn_pool_clear(iterpool);
+
+      if (sb == NULL)
+        sb = svn_stringbuf_create("", pool);
+      else
+        svn_stringbuf_appendbyte(sb, ' ');
+
+      uri = commit_ctx->session->session_url;
+      uri.path = (char *)svn_path_url_add_component2(uri.path, relpath,
+                                                    iterpool);
+
+      svn_stringbuf_appendbyte(sb, '<');
+      svn_stringbuf_appendcstr(sb, apr_uri_unparse(iterpool, &uri, 0));
+      svn_stringbuf_appendcstr(sb, "> (<");
+      svn_stringbuf_appendcstr(sb, svn__apr_hash_index_val(hi));
+      svn_stringbuf_appendcstr(sb, ">)");
+    }
+
+  if (iterpool)
+    svn_pool_destroy(iterpool);
+
+  if (sb)
+    {
+      serf_bucket_headers_set(headers, "If", sb->data);
+      *added = TRUE;
+    }
+  else
+    *added = FALSE;
 
   return SVN_NO_ERROR;
 }
 
 static svn_error_t *
+setup_add_dir_common_headers(serf_bucket_t *headers,
+                             void *baton,
+                             apr_pool_t *pool)
+{
+  dir_context_t *dir = baton;
+  svn_boolean_t added;
+
+  return svn_error_trace(
+      setup_if_header_recursive(&added, headers, dir->commit_ctx, dir->relpath,
+                                pool));
+}
+
+static svn_error_t *
 setup_copy_dir_headers(serf_bucket_t *headers,
                        void *baton,
                        apr_pool_t *pool)
@@ -1090,9 +1124,9 @@ setup_copy_dir_headers(serf_bucket_t *he
   const char *absolute_uri;
 
   /* The Dest URI must be absolute.  Bummer. */
-  uri = dir->commit->session->session_url;
+  uri = dir->commit_ctx->session->session_url;
 
-  if (USING_HTTPV2_COMMIT_SUPPORT(dir->commit))
+  if (USING_HTTPV2_COMMIT_SUPPORT(dir->commit_ctx))
     {
       uri.path = (char *)dir->url;
     }
@@ -1107,12 +1141,12 @@ setup_copy_dir_headers(serf_bucket_t *he
   serf_bucket_headers_set(headers, "Destination", absolute_uri);
 
   serf_bucket_headers_setn(headers, "Depth", "infinity");
-  serf_bucket_headers_setn(headers, "Overwrite", "T");
+  serf_bucket_headers_setn(headers, "Overwrite", "F");
 
   /* Implicitly checkout this dir now. */
   dir->working_url = apr_pstrdup(dir->pool, uri.path);
 
-  return SVN_NO_ERROR;
+  return svn_error_trace(setup_add_dir_common_headers(headers, baton, pool));
 }
 
 static svn_error_t *
@@ -1120,72 +1154,22 @@ setup_delete_headers(serf_bucket_t *head
                      void *baton,
                      apr_pool_t *pool)
 {
-  delete_context_t *ctx = baton;
+  delete_context_t *del = baton;
+  svn_boolean_t added;
 
   serf_bucket_headers_set(headers, SVN_DAV_VERSION_NAME_HEADER,
-                          apr_ltoa(pool, ctx->revision));
-
-  if (ctx->lock_token_hash)
-    {
-      ctx->lock_token = svn_hash_gets(ctx->lock_token_hash, ctx->path);
-
-      if (ctx->lock_token)
-        {
-          const char *token_header;
-
-          token_header = apr_pstrcat(pool, "<", ctx->path, "> (<",
-                                     ctx->lock_token, ">)", SVN_VA_NULL);
-
-          serf_bucket_headers_set(headers, "If", token_header);
-
-          if (ctx->keep_locks)
-            serf_bucket_headers_setn(headers, SVN_DAV_OPTIONS_HEADER,
-                                     SVN_DAV_OPTION_KEEP_LOCKS);
-        }
-    }
-
-  return SVN_NO_ERROR;
-}
+                          apr_ltoa(pool, del->revision));
 
-/* Implements svn_ra_serf__request_body_delegate_t */
-static svn_error_t *
-create_delete_body(serf_bucket_t **body_bkt,
-                   void *baton,
-                   serf_bucket_alloc_t *alloc,
-                   apr_pool_t *pool)
-{
-  delete_context_t *ctx = baton;
-  serf_bucket_t *body;
-
-  body = serf_bucket_aggregate_create(alloc);
-
-  svn_ra_serf__add_xml_header_buckets(body, alloc);
-
-  svn_ra_serf__merge_lock_token_list(ctx->lock_token_hash, ctx->path,
-                                     body, alloc, pool);
-
-  *body_bkt = body;
-  return SVN_NO_ERROR;
-}
-
-/* Helper function to write the svndiff stream to temporary file. */
-static svn_error_t *
-svndiff_stream_write(void *file_baton,
-                     const char *data,
-                     apr_size_t *len)
-{
-  file_context_t *ctx = file_baton;
-  apr_status_t status;
+  SVN_ERR(setup_if_header_recursive(&added, headers, del->commit_ctx,
+                                    del->relpath, pool));
 
-  status = apr_file_write_full(ctx->svndiff, data, *len, NULL);
-  if (status)
-      return svn_error_wrap_apr(status, _("Failed writing updated file"));
+  if (added && del->commit_ctx->keep_locks)
+    serf_bucket_headers_setn(headers, SVN_DAV_OPTIONS_HEADER,
+                                      SVN_DAV_OPTION_KEEP_LOCKS);
 
   return SVN_NO_ERROR;
 }
 
-
-
 /* POST against 'me' resource handlers. */
 
 /* Implements svn_ra_serf__request_body_delegate_t */
@@ -1314,66 +1298,49 @@ open_root(void *edit_baton,
           apr_pool_t *dir_pool,
           void **root_baton)
 {
-  commit_context_t *ctx = edit_baton;
+  commit_context_t *commit_ctx = edit_baton;
   svn_ra_serf__handler_t *handler;
   proppatch_context_t *proppatch_ctx;
   dir_context_t *dir;
   apr_hash_index_t *hi;
   const char *proppatch_target = NULL;
+  apr_pool_t *scratch_pool = svn_pool_create(dir_pool);
 
-  if (SVN_RA_SERF__HAVE_HTTPV2_SUPPORT(ctx->session))
+  if (SVN_RA_SERF__HAVE_HTTPV2_SUPPORT(commit_ctx->session))
     {
       post_response_ctx_t *prc;
       const char *rel_path;
       svn_boolean_t post_with_revprops
-        = (NULL != svn_hash_gets(ctx->session->supported_posts,
+        = (NULL != svn_hash_gets(commit_ctx->session->supported_posts,
                                  "create-txn-with-props"));
 
       /* Create our activity URL now on the server. */
-      handler = apr_pcalloc(ctx->pool, sizeof(*handler));
-      handler->handler_pool = ctx->pool;
+      handler = svn_ra_serf__create_handler(scratch_pool);
+
       handler->method = "POST";
       handler->body_type = SVN_SKEL_MIME_TYPE;
       handler->body_delegate = create_txn_post_body;
       handler->body_delegate_baton =
-        post_with_revprops ? ctx->revprop_table : NULL;
+          post_with_revprops ? commit_ctx->revprop_table : NULL;
       handler->header_delegate = setup_post_headers;
       handler->header_delegate_baton = NULL;
-      handler->path = ctx->session->me_resource;
-      handler->conn = ctx->session->conns[0];
-      handler->session = ctx->session;
+      handler->path = commit_ctx->session->me_resource;
+      handler->conn = commit_ctx->session->conns[0];
+      handler->session = commit_ctx->session;
 
-      prc = apr_pcalloc(ctx->pool, sizeof(*prc));
+      prc = apr_pcalloc(scratch_pool, sizeof(*prc));
       prc->handler = handler;
-      prc->commit_ctx = ctx;
+      prc->commit_ctx = commit_ctx;
 
       handler->response_handler = post_response_handler;
       handler->response_baton = prc;
 
-      SVN_ERR(svn_ra_serf__context_run_one(handler, ctx->pool));
+      SVN_ERR(svn_ra_serf__context_run_one(handler, scratch_pool));
 
       if (handler->sline.code != 201)
-        {
-          apr_status_t status = SVN_ERR_RA_DAV_REQUEST_FAILED;
-
-          switch (handler->sline.code)
-            {
-              case 403:
-                status = SVN_ERR_RA_DAV_FORBIDDEN;
-                break;
-              case 404:
-                status = SVN_ERR_FS_NOT_FOUND;
-                break;
-            }
+        return svn_error_trace(svn_ra_serf__unexpected_status(handler));
 
-          return svn_error_createf(status, NULL,
-                                   _("%s of '%s': %d %s (%s://%s)"),
-                                   handler->method, handler->path,
-                                   handler->sline.code, handler->sline.reason,
-                                   ctx->session->session_url.scheme,
-                                   ctx->session->session_url.hostinfo);
-        }
-      if (! (ctx->txn_root_url && ctx->txn_url))
+      if (! (commit_ctx->txn_root_url && commit_ctx->txn_url))
         {
           return svn_error_createf(
             SVN_ERR_RA_DAV_REQUEST_FAILED, NULL,
@@ -1381,42 +1348,45 @@ open_root(void *edit_baton,
         }
 
       /* Fixup the txn_root_url to point to the anchor of the commit. */
-      SVN_ERR(svn_ra_serf__get_relative_path(&rel_path,
-                                             ctx->session->session_url.path,
-                                             ctx->session, NULL, dir_pool));
-      ctx->txn_root_url = svn_path_url_add_component2(ctx->txn_root_url,
-                                                      rel_path, ctx->pool);
+      SVN_ERR(svn_ra_serf__get_relative_path(
+                                        &rel_path,
+                                        commit_ctx->session->session_url.path,
+                                        commit_ctx->session, NULL,
+                                        scratch_pool));
+      commit_ctx->txn_root_url = svn_path_url_add_component2(
+                                        commit_ctx->txn_root_url,
+                                        rel_path, commit_ctx->pool);
 
       /* Build our directory baton. */
       dir = apr_pcalloc(dir_pool, sizeof(*dir));
       dir->pool = dir_pool;
-      dir->commit = ctx;
+      dir->commit_ctx = commit_ctx;
       dir->base_revision = base_revision;
       dir->relpath = "";
       dir->name = "";
       dir->changed_props = apr_hash_make(dir->pool);
       dir->removed_props = apr_hash_make(dir->pool);
-      dir->url = apr_pstrdup(dir->pool, ctx->txn_root_url);
+      dir->url = apr_pstrdup(dir->pool, commit_ctx->txn_root_url);
 
       /* If we included our revprops in the POST, we need not
          PROPPATCH them. */
-      proppatch_target = post_with_revprops ? NULL : ctx->txn_url;
+      proppatch_target = post_with_revprops ? NULL : commit_ctx->txn_url;
     }
   else
     {
-      const char *activity_str = ctx->session->activity_collection_url;
+      const char *activity_str = commit_ctx->session->activity_collection_url;
 
       if (!activity_str)
-        SVN_ERR(svn_ra_serf__v1_get_activity_collection(&activity_str,
-                                                        ctx->session->conns[0],
-                                                        ctx->pool,
-                                                        ctx->pool));
+        SVN_ERR(svn_ra_serf__v1_get_activity_collection(
+                                    &activity_str,
+                                    commit_ctx->session->conns[0],
+                                    commit_ctx->pool, scratch_pool));
 
       /* Cache the result. */
       if (activity_str)
         {
-          ctx->session->activity_collection_url =
-            apr_pstrdup(ctx->session->pool, activity_str);
+          commit_ctx->session->activity_collection_url =
+            apr_pstrdup(commit_ctx->session->pool, activity_str);
         }
       else
         {
@@ -1425,70 +1395,53 @@ open_root(void *edit_baton,
                                     "requested activity-collection-set value"));
         }
 
-      ctx->activity_url =
-        svn_path_url_add_component2(activity_str, svn_uuid_generate(ctx->pool),
-                                    ctx->pool);
+      commit_ctx->activity_url = svn_path_url_add_component2(
+                                    activity_str,
+                                    svn_uuid_generate(scratch_pool),
+                                    commit_ctx->pool);
 
       /* Create our activity URL now on the server. */
-      handler = apr_pcalloc(ctx->pool, sizeof(*handler));
-      handler->handler_pool = ctx->pool;
+      handler = svn_ra_serf__create_handler(scratch_pool);
+
       handler->method = "MKACTIVITY";
-      handler->path = ctx->activity_url;
-      handler->conn = ctx->session->conns[0];
-      handler->session = ctx->session;
+      handler->path = commit_ctx->activity_url;
+      handler->conn = commit_ctx->session->conns[0];
+      handler->session = commit_ctx->session;
 
       handler->response_handler = svn_ra_serf__expect_empty_body;
       handler->response_baton = handler;
 
-      SVN_ERR(svn_ra_serf__context_run_one(handler, ctx->pool));
+      SVN_ERR(svn_ra_serf__context_run_one(handler, scratch_pool));
 
       if (handler->sline.code != 201)
-        {
-          apr_status_t status = SVN_ERR_RA_DAV_REQUEST_FAILED;
-
-          switch (handler->sline.code)
-            {
-              case 403:
-                status = SVN_ERR_RA_DAV_FORBIDDEN;
-                break;
-              case 404:
-                status = SVN_ERR_FS_NOT_FOUND;
-                break;
-            }
-
-          return svn_error_createf(status, NULL,
-                                   _("%s of '%s': %d %s (%s://%s)"),
-                                   handler->method, handler->path,
-                                   handler->sline.code, handler->sline.reason,
-                                   ctx->session->session_url.scheme,
-                                   ctx->session->session_url.hostinfo);
-        }
+        return svn_error_trace(svn_ra_serf__unexpected_status(handler));
 
       /* Now go fetch our VCC and baseline so we can do a CHECKOUT. */
-      SVN_ERR(svn_ra_serf__discover_vcc(&(ctx->vcc_url), ctx->session,
-                                        ctx->conn, ctx->pool));
+      SVN_ERR(svn_ra_serf__discover_vcc(&(commit_ctx->vcc_url),
+                                        commit_ctx->session,
+                                        commit_ctx->conn, commit_ctx->pool));
 
 
       /* Build our directory baton. */
       dir = apr_pcalloc(dir_pool, sizeof(*dir));
       dir->pool = dir_pool;
-      dir->commit = ctx;
+      dir->commit_ctx = commit_ctx;
       dir->base_revision = base_revision;
       dir->relpath = "";
       dir->name = "";
       dir->changed_props = apr_hash_make(dir->pool);
       dir->removed_props = apr_hash_make(dir->pool);
 
-      SVN_ERR(get_version_url(&dir->url, dir->commit->session,
+      SVN_ERR(get_version_url(&dir->url, dir->commit_ctx->session,
                               dir->relpath,
-                              dir->base_revision, ctx->checked_in_url,
-                              dir->pool, dir->pool /* scratch_pool */));
-      ctx->checked_in_url = dir->url;
+                              dir->base_revision, commit_ctx->checked_in_url,
+                              dir->pool, scratch_pool));
+      commit_ctx->checked_in_url = apr_pstrdup(commit_ctx->pool, dir->url);
 
       /* Checkout our root dir */
-      SVN_ERR(checkout_dir(dir, dir->pool /* scratch_pool */));
+      SVN_ERR(checkout_dir(dir, scratch_pool));
 
-      proppatch_target = ctx->baseline_url;
+      proppatch_target = commit_ctx->baseline_url;
     }
 
   /* Unless this is NULL -- which means we don't need to PROPPATCH the
@@ -1496,15 +1449,16 @@ open_root(void *edit_baton,
      transaction with our revprops.  */
   if (proppatch_target)
     {
-      proppatch_ctx = apr_pcalloc(ctx->pool, sizeof(*proppatch_ctx));
-      proppatch_ctx->pool = dir_pool;
-      proppatch_ctx->commit = ctx;
+      proppatch_ctx = apr_pcalloc(scratch_pool, sizeof(*proppatch_ctx));
+      proppatch_ctx->pool = scratch_pool;
+      proppatch_ctx->commit_ctx = NULL; /* No lock info */
       proppatch_ctx->path = proppatch_target;
       proppatch_ctx->changed_props = apr_hash_make(proppatch_ctx->pool);
       proppatch_ctx->removed_props = apr_hash_make(proppatch_ctx->pool);
       proppatch_ctx->base_revision = SVN_INVALID_REVNUM;
 
-      for (hi = apr_hash_first(ctx->pool, ctx->revprop_table); hi;
+      for (hi = apr_hash_first(scratch_pool, commit_ctx->revprop_table);
+           hi;
            hi = apr_hash_next(hi))
         {
           const char *name = svn__apr_hash_index_key(hi);
@@ -1523,12 +1477,16 @@ open_root(void *edit_baton,
 
           svn_ra_serf__set_prop(proppatch_ctx->changed_props,
                                 proppatch_ctx->path,
-                                ns, name, value, proppatch_ctx->pool);
+                                ns, name, value, scratch_pool);
         }
 
-      SVN_ERR(proppatch_resource(proppatch_ctx, dir->commit, ctx->pool));
+      SVN_ERR(proppatch_resource(commit_ctx->session,
+                                 commit_ctx->conn,
+                                 proppatch_ctx, scratch_pool));
     }
 
+  svn_pool_destroy(scratch_pool);
+
   *root_baton = dir;
 
   return SVN_NO_ERROR;
@@ -1544,12 +1502,12 @@ delete_entry(const char *path,
   delete_context_t *delete_ctx;
   svn_ra_serf__handler_t *handler;
   const char *delete_target;
-  svn_error_t *err;
 
-  if (USING_HTTPV2_COMMIT_SUPPORT(dir->commit))
+  if (USING_HTTPV2_COMMIT_SUPPORT(dir->commit_ctx))
     {
-      delete_target = svn_path_url_add_component2(dir->commit->txn_root_url,
-                                                  path, dir->pool);
+      delete_target = svn_path_url_add_component2(
+                                    dir->commit_ctx->txn_root_url,
+                                    path, dir->pool);
     }
   else
     {
@@ -1563,15 +1521,13 @@ delete_entry(const char *path,
 
   /* DELETE our entry */
   delete_ctx = apr_pcalloc(pool, sizeof(*delete_ctx));
-  delete_ctx->path = apr_pstrdup(pool, path);
+  delete_ctx->relpath = apr_pstrdup(pool, path);
   delete_ctx->revision = revision;
-  delete_ctx->lock_token_hash = dir->commit->lock_tokens;
-  delete_ctx->keep_locks = dir->commit->keep_locks;
+  delete_ctx->commit_ctx = dir->commit_ctx;
 
-  handler = apr_pcalloc(pool, sizeof(*handler));
-  handler->handler_pool = pool;
-  handler->session = dir->commit->session;
-  handler->conn = dir->commit->conn;
+  handler = svn_ra_serf__create_handler(pool);
+  handler->session = dir->commit_ctx->session;
+  handler->conn = dir->commit_ctx->conn;
 
   handler->response_handler = svn_ra_serf__expect_empty_body;
   handler->response_baton = handler;
@@ -1582,39 +1538,14 @@ delete_entry(const char *path,
   handler->method = "DELETE";
   handler->path = delete_target;
 
-  err = svn_ra_serf__context_run_one(handler, pool);
-
-  if (err &&
-      (err->apr_err == SVN_ERR_FS_BAD_LOCK_TOKEN ||
-       err->apr_err == SVN_ERR_FS_NO_LOCK_TOKEN ||
-       err->apr_err == SVN_ERR_FS_LOCK_OWNER_MISMATCH ||
-       err->apr_err == SVN_ERR_FS_PATH_ALREADY_LOCKED))
-    {
-      svn_error_clear(err);
-
-      /* An error has been registered on the connection. Reset the thing
-         so that we can use it again.  */
-      serf_connection_reset(handler->conn->conn);
-
-      handler->body_delegate = create_delete_body;
-      handler->body_delegate_baton = delete_ctx;
-      handler->body_type = "text/xml";
-
-      SVN_ERR(svn_ra_serf__context_run_one(handler, pool));
-    }
-  else if (err)
-    {
-      return err;
-    }
+  SVN_ERR(svn_ra_serf__context_run_one(handler, pool));
 
   /* 204 No Content: item successfully deleted */
   if (handler->sline.code != 204)
-    {
-      return svn_error_trace(return_response_err(handler));
-    }
+    return svn_error_trace(svn_ra_serf__unexpected_status(handler));
 
-  svn_hash_sets(dir->commit->deleted_entries,
-                apr_pstrdup(dir->commit->pool, path), (void *)1);
+  svn_hash_sets(dir->commit_ctx->deleted_entries,
+                apr_pstrdup(dir->commit_ctx->pool, path), (void *)1);
 
   return SVN_NO_ERROR;
 }
@@ -1637,19 +1568,19 @@ add_directory(const char *path,
 
   dir->pool = dir_pool;
   dir->parent_dir = parent;
-  dir->commit = parent->commit;
+  dir->commit_ctx = parent->commit_ctx;
   dir->added = TRUE;
   dir->base_revision = SVN_INVALID_REVNUM;
   dir->copy_revision = copyfrom_revision;
-  dir->copy_path = copyfrom_path;
+  dir->copy_path = apr_pstrdup(dir->pool, copyfrom_path);
   dir->relpath = apr_pstrdup(dir->pool, path);
   dir->name = svn_relpath_basename(dir->relpath, NULL);
   dir->changed_props = apr_hash_make(dir->pool);
   dir->removed_props = apr_hash_make(dir->pool);
 
-  if (USING_HTTPV2_COMMIT_SUPPORT(dir->commit))
+  if (USING_HTTPV2_COMMIT_SUPPORT(dir->commit_ctx))
     {
-      dir->url = svn_path_url_add_component2(parent->commit->txn_root_url,
+      dir->url = svn_path_url_add_component2(parent->commit_ctx->txn_root_url,
                                              path, dir->pool);
       mkcol_target = dir->url;
     }
@@ -1658,17 +1589,16 @@ add_directory(const char *path,
       /* Ensure our parent is checked out. */
       SVN_ERR(checkout_dir(parent, dir->pool /* scratch_pool */));
 
-      dir->url = svn_path_url_add_component2(parent->commit->checked_in_url,
+      dir->url = svn_path_url_add_component2(parent->commit_ctx->checked_in_url,
                                              dir->name, dir->pool);
       mkcol_target = svn_path_url_add_component2(
                                parent->working_url,
                                dir->name, dir->pool);
     }
 
-  handler = apr_pcalloc(dir->pool, sizeof(*handler));
-  handler->handler_pool = dir->pool;
-  handler->conn = dir->commit->conn;
-  handler->session = dir->commit->session;
+  handler = svn_ra_serf__create_handler(dir->pool);
+  handler->conn = dir->commit_ctx->conn;
+  handler->session = dir->commit_ctx->session;
 
   handler->response_handler = svn_ra_serf__expect_empty_body;
   handler->response_baton = handler;
@@ -1676,6 +1606,9 @@ add_directory(const char *path,
     {
       handler->method = "MKCOL";
       handler->path = mkcol_target;
+
+      handler->header_delegate = setup_add_dir_common_headers;
+      handler->header_delegate_baton = dir;
     }
   else
     {
@@ -1692,7 +1625,7 @@ add_directory(const char *path,
 
       /* ### conn==NULL for session->conns[0]. same as commit->conn.  */
       SVN_ERR(svn_ra_serf__get_stable_url(&req_url, NULL /* latest_revnum */,
-                                          dir->commit->session,
+                                          dir->commit_ctx->session,
                                           NULL /* conn */,
                                           uri.path, dir->copy_revision,
                                           dir_pool, dir_pool));
@@ -1706,23 +1639,8 @@ add_directory(const char *path,
 
   SVN_ERR(svn_ra_serf__context_run_one(handler, dir->pool));
 
-  switch (handler->sline.code)
-    {
-      case 201: /* Created:    item was successfully copied */
-      case 204: /* No Content: item successfully replaced an existing target */
-        break;
-
-      case 403:
-        return svn_error_createf(SVN_ERR_RA_DAV_FORBIDDEN, NULL,
-                                _("Access to '%s' forbidden"),
-                                 handler->path);
-      default:
-        return svn_error_createf(SVN_ERR_RA_DAV_REQUEST_FAILED, NULL,
-                                 _("Adding directory failed: %s on %s "
-                                   "(%d %s)"),
-                                 handler->method, handler->path,
-                                 handler->sline.code, handler->sline.reason);
-    }
+  if (handler->sline.code != 201)
+    return svn_error_trace(svn_ra_serf__unexpected_status(handler));
 
   *child_baton = dir;
 
@@ -1744,7 +1662,7 @@ open_directory(const char *path,
   dir->pool = dir_pool;
 
   dir->parent_dir = parent;
-  dir->commit = parent->commit;
+  dir->commit_ctx = parent->commit_ctx;
 
   dir->added = FALSE;
   dir->base_revision = base_revision;
@@ -1753,17 +1671,17 @@ open_directory(const char *path,
   dir->changed_props = apr_hash_make(dir->pool);
   dir->removed_props = apr_hash_make(dir->pool);
 
-  if (USING_HTTPV2_COMMIT_SUPPORT(dir->commit))
+  if (USING_HTTPV2_COMMIT_SUPPORT(dir->commit_ctx))
     {
-      dir->url = svn_path_url_add_component2(parent->commit->txn_root_url,
+      dir->url = svn_path_url_add_component2(parent->commit_ctx->txn_root_url,
                                              path, dir->pool);
     }
   else
     {
       SVN_ERR(get_version_url(&dir->url,
-                              dir->commit->session,
+                              dir->commit_ctx->session,
                               dir->relpath, dir->base_revision,
-                              dir->commit->checked_in_url,
+                              dir->commit_ctx->checked_in_url,
                               dir->pool, dir->pool /* scratch_pool */));
     }
   *child_baton = dir;
@@ -1782,7 +1700,7 @@ change_dir_prop(void *dir_baton,
   const char *proppatch_target;
 
 
-  if (USING_HTTPV2_COMMIT_SUPPORT(dir->commit))
+  if (USING_HTTPV2_COMMIT_SUPPORT(dir->commit_ctx))
     {
       proppatch_target = dir->url;
     }
@@ -1839,13 +1757,13 @@ close_directory(void *dir_baton,
 
       proppatch_ctx = apr_pcalloc(pool, sizeof(*proppatch_ctx));
       proppatch_ctx->pool = pool;
-      proppatch_ctx->commit = dir->commit;
+      proppatch_ctx->commit_ctx = dir->commit_ctx;
       proppatch_ctx->relpath = dir->relpath;
       proppatch_ctx->changed_props = dir->changed_props;
       proppatch_ctx->removed_props = dir->removed_props;
       proppatch_ctx->base_revision = dir->base_revision;
 
-      if (USING_HTTPV2_COMMIT_SUPPORT(dir->commit))
+      if (USING_HTTPV2_COMMIT_SUPPORT(dir->commit_ctx))
         {
           proppatch_ctx->path = dir->url;
         }
@@ -1854,7 +1772,9 @@ close_directory(void *dir_baton,
           proppatch_ctx->path = dir->working_url;
         }
 
-      SVN_ERR(proppatch_resource(proppatch_ctx, dir->commit, dir->pool));
+      SVN_ERR(proppatch_resource(dir->commit_ctx->session,
+                                 dir->commit_ctx->conn,
+                                 proppatch_ctx, dir->pool));
     }
 
   return SVN_NO_ERROR;
@@ -1871,6 +1791,7 @@ add_file(const char *path,
   dir_context_t *dir = parent_baton;
   file_context_t *new_file;
   const char *deleted_parent = path;
+  apr_pool_t *scratch_pool = svn_pool_create(file_pool);
 
   new_file = apr_pcalloc(file_pool, sizeof(*new_file));
   new_file->pool = file_pool;
@@ -1878,12 +1799,12 @@ add_file(const char *path,
   dir->ref_count++;
 
   new_file->parent_dir = dir;
-  new_file->commit = dir->commit;
+  new_file->commit_ctx = dir->commit_ctx;
   new_file->relpath = apr_pstrdup(new_file->pool, path);
   new_file->name = svn_relpath_basename(new_file->relpath, NULL);
   new_file->added = TRUE;
   new_file->base_revision = SVN_INVALID_REVNUM;
-  new_file->copy_path = copy_path;
+  new_file->copy_path = apr_pstrdup(new_file->pool, copy_path);
   new_file->copy_revision = copy_revision;
   new_file->changed_props = apr_hash_make(new_file->pool);
   new_file->removed_props = apr_hash_make(new_file->pool);
@@ -1891,9 +1812,9 @@ add_file(const char *path,
   /* Ensure that the file doesn't exist by doing a HEAD on the
      resource.  If we're using HTTP v2, we'll just look into the
      transaction root tree for this thing.  */
-  if (USING_HTTPV2_COMMIT_SUPPORT(dir->commit))
+  if (USING_HTTPV2_COMMIT_SUPPORT(dir->commit_ctx))
     {
-      new_file->url = svn_path_url_add_component2(dir->commit->txn_root_url,
+      new_file->url = svn_path_url_add_component2(dir->commit_ctx->txn_root_url,
                                                   path, new_file->pool);
     }
   else
@@ -1908,42 +1829,82 @@ add_file(const char *path,
 
   while (deleted_parent && deleted_parent[0] != '\0')
     {
-      if (svn_hash_gets(dir->commit->deleted_entries, deleted_parent))
+      if (svn_hash_gets(dir->commit_ctx->deleted_entries, deleted_parent))
         {
           break;
         }
       deleted_parent = svn_relpath_dirname(deleted_parent, file_pool);
     }
 
-  if (! ((dir->added && !dir->copy_path) ||
-         (deleted_parent && deleted_parent[0] != '\0')))
+  if (copy_path)
+    {
+      svn_ra_serf__handler_t *handler;
+      apr_uri_t uri;
+      const char *req_url;
+      
+      apr_status_t status;
+
+      /* Create the copy directly as cheap 'does exist/out of date'
+         check. We update the copy (if needed) from close_file() */
+
+      status = apr_uri_parse(scratch_pool, copy_path, &uri);
+      if (status)
+        return svn_ra_serf__wrap_err(status, NULL);
+
+      /* ### conn==NULL for session->conns[0]. same as commit_ctx->conn.  */
+      SVN_ERR(svn_ra_serf__get_stable_url(&req_url, NULL /* latest_revnum */,
+                                          dir->commit_ctx->session,
+                                          NULL /* conn */,
+                                          uri.path, copy_revision,
+                                          scratch_pool, scratch_pool));
+
+      handler = svn_ra_serf__create_handler(scratch_pool);
+      handler->method = "COPY";
+      handler->path = req_url;
+      handler->conn = dir->commit_ctx->conn;
+      handler->session = dir->commit_ctx->session;
+
+      handler->response_handler = svn_ra_serf__expect_empty_body;
+      handler->response_baton = handler;
+
+      handler->header_delegate = setup_copy_file_headers;
+      handler->header_delegate_baton = new_file;
+
+      SVN_ERR(svn_ra_serf__context_run_one(handler, scratch_pool));
+
+      if (handler->sline.code != 201)
+        return svn_error_trace(svn_ra_serf__unexpected_status(handler));
+    }
+  else if (! ((dir->added && !dir->copy_path) ||
+           (deleted_parent && deleted_parent[0] != '\0')))
     {
       svn_ra_serf__handler_t *handler;
+      svn_error_t *err;
 
-      handler = apr_pcalloc(new_file->pool, sizeof(*handler));
-      handler->handler_pool = new_file->pool;
-      handler->session = new_file->commit->session;
-      handler->conn = new_file->commit->conn;
+      handler = svn_ra_serf__create_handler(scratch_pool);
+      handler->session = new_file->commit_ctx->session;
+      handler->conn = new_file->commit_ctx->conn;
       handler->method = "HEAD";
       handler->path = svn_path_url_add_component2(
-        dir->commit->session->session_url.path,
-        path, new_file->pool);
+                                        dir->commit_ctx->session->session_url.path,
+                                        path, scratch_pool);
       handler->response_handler = svn_ra_serf__expect_empty_body;
       handler->response_baton = handler;
 
-      SVN_ERR(svn_ra_serf__context_run_one(handler, new_file->pool));
+      err = svn_ra_serf__context_run_one(handler, scratch_pool);
 
-      if (handler->sline.code != 404)
+      if (err && err->apr_err == SVN_ERR_FS_NOT_FOUND)
         {
-          SVN_ERR(svn_ra_serf__error_on_status(handler->sline,
-                                               handler->path,
-                                               handler->location));
-
-         return svn_error_createf(SVN_ERR_FS_ALREADY_EXISTS, NULL,
-                                   _("File '%s' already exists"), path);
+          svn_error_clear(err); /* Great. We can create a new file! */
         }
+      else if (err)
+        return svn_error_trace(err);
+      else
+        return svn_error_createf(SVN_ERR_FS_ALREADY_EXISTS, NULL,
+                                 _("File '%s' already exists"), path);
     }
 
+  svn_pool_destroy(scratch_pool);
   *file_baton = new_file;
 
   return SVN_NO_ERROR;
@@ -1965,7 +1926,7 @@ open_file(const char *path,
   parent->ref_count++;
 
   new_file->parent_dir = parent;
-  new_file->commit = parent->commit;
+  new_file->commit_ctx = parent->commit_ctx;
   new_file->relpath = apr_pstrdup(new_file->pool, path);
   new_file->name = svn_relpath_basename(new_file->relpath, NULL);
   new_file->added = FALSE;
@@ -1973,9 +1934,9 @@ open_file(const char *path,
   new_file->changed_props = apr_hash_make(new_file->pool);
   new_file->removed_props = apr_hash_make(new_file->pool);
 
-  if (USING_HTTPV2_COMMIT_SUPPORT(parent->commit))
+  if (USING_HTTPV2_COMMIT_SUPPORT(parent->commit_ctx))
     {
-      new_file->url = svn_path_url_add_component2(parent->commit->txn_root_url,
+      new_file->url = svn_path_url_add_component2(parent->commit_ctx->txn_root_url,
                                                   path, new_file->pool);
     }
   else
@@ -1991,6 +1952,23 @@ open_file(const char *path,
   return SVN_NO_ERROR;
 }
 
+/* Implements svn_stream_lazyopen_func_t for apply_textdelta */
+static svn_error_t *
+delayed_commit_stream_open(svn_stream_t **stream,
+                           void *baton,
+                           apr_pool_t *result_pool,
+                           apr_pool_t *scratch_pool)
+{
+  file_context_t *file_ctx = baton;
+
+  SVN_ERR(svn_io_open_unique_file3(&file_ctx->svndiff, NULL, NULL,
+                                   svn_io_file_del_on_pool_cleanup,
+                                   file_ctx->pool, scratch_pool));
+
+  *stream = svn_stream_from_aprfile2(file_ctx->svndiff, TRUE, result_pool);
+  return SVN_NO_ERROR;
+}
+
 static svn_error_t *
 apply_textdelta(void *file_baton,
                 const char *base_checksum,
@@ -2013,12 +1991,8 @@ apply_textdelta(void *file_baton,
    * avoid too many simultaneously open files.
    */
 
-  SVN_ERR(svn_io_open_unique_file3(&ctx->svndiff, NULL, NULL,
-                                   svn_io_file_del_on_pool_cleanup,
-                                   ctx->pool, pool));
-
-  ctx->stream = svn_stream_create(ctx, pool);
-  svn_stream_set_write(ctx->stream, svndiff_stream_write);
+  ctx->stream = svn_stream_lazyopen_create(delayed_commit_stream_open,
+                                           ctx, FALSE, ctx->pool);
 
   svn_txdelta_to_svndiff3(handler, handler_baton, ctx->stream, 0,
                           SVN_DELTA_COMPRESSION_LEVEL_DEFAULT, pool);
@@ -2074,69 +2048,27 @@ close_file(void *file_baton,
 {
   file_context_t *ctx = file_baton;
   svn_boolean_t put_empty_file = FALSE;
-  apr_status_t status;
 
   ctx->result_checksum = text_checksum;
 
-  if (ctx->copy_path)
-    {
-      svn_ra_serf__handler_t *handler;
-      apr_uri_t uri;
-      const char *req_url;
-
-      status = apr_uri_parse(scratch_pool, ctx->copy_path, &uri);
-      if (status)
-        {
-          return svn_error_createf(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL,
-                                   _("Unable to parse URL '%s'"),
-                                   ctx->copy_path);
-        }
-
-      /* ### conn==NULL for session->conns[0]. same as commit->conn.  */
-      SVN_ERR(svn_ra_serf__get_stable_url(&req_url, NULL /* latest_revnum */,
-                                          ctx->commit->session,
-                                          NULL /* conn */,
-                                          uri.path, ctx->copy_revision,
-                                          scratch_pool, scratch_pool));
-
-      handler = apr_pcalloc(scratch_pool, sizeof(*handler));
-      handler->handler_pool = scratch_pool;
-      handler->method = "COPY";
-      handler->path = req_url;
-      handler->conn = ctx->commit->conn;
-      handler->session = ctx->commit->session;
-
-      handler->response_handler = svn_ra_serf__expect_empty_body;
-      handler->response_baton = handler;
-
-      handler->header_delegate = setup_copy_file_headers;
-      handler->header_delegate_baton = ctx;
-
-      SVN_ERR(svn_ra_serf__context_run_one(handler, scratch_pool));
-
-      if (handler->sline.code != 201 && handler->sline.code != 204)
-        {
-          return svn_error_trace(return_response_err(handler));
-        }
-    }
-
   /* If we got no stream of changes, but this is an added-without-history
    * file, make a note that we'll be PUTting a zero-byte file to the server.
    */
-  if ((!ctx->stream) && ctx->added && (!ctx->copy_path))
+  if ((!ctx->svndiff) && ctx->added && (!ctx->copy_path))
     put_empty_file = TRUE;
 
   /* If we had a stream of changes, push them to the server... */
-  if (ctx->stream || put_empty_file)
+  if (ctx->svndiff || put_empty_file)
     {
       svn_ra_serf__handler_t *handler;
+      int expected_result;
+
+      handler = svn_ra_serf__create_handler(scratch_pool);
 
-      handler = apr_pcalloc(scratch_pool, sizeof(*handler));
-      handler->handler_pool = scratch_pool;
       handler->method = "PUT";
       handler->path = ctx->url;
-      handler->conn = ctx->commit->conn;
-      handler->session = ctx->commit->session;
+      handler->conn = ctx->commit_ctx->conn;
+      handler->session = ctx->commit_ctx->session;
 
       handler->response_handler = svn_ra_serf__expect_empty_body;
       handler->response_baton = handler;
@@ -2159,10 +2091,13 @@ close_file(void *file_baton,
 
       SVN_ERR(svn_ra_serf__context_run_one(handler, scratch_pool));
 
-      if (handler->sline.code != 204 && handler->sline.code != 201)
-        {
-          return svn_error_trace(return_response_err(handler));
-        }
+      if (ctx->added && ! ctx->copy_path)
+        expected_result = 201; /* Created */
+      else
+        expected_result = 204; /* Updated */
+
+      if (handler->sline.code != expected_result)
+        return svn_error_trace(svn_ra_serf__unexpected_status(handler));
     }
 
   if (ctx->svndiff)
@@ -2178,12 +2113,14 @@ close_file(void *file_baton,
       proppatch->pool = scratch_pool;
       proppatch->relpath = ctx->relpath;
       proppatch->path = ctx->url;
-      proppatch->commit = ctx->commit;
+      proppatch->commit_ctx = ctx->commit_ctx;
       proppatch->changed_props = ctx->changed_props;
       proppatch->removed_props = ctx->removed_props;
       proppatch->base_revision = ctx->base_revision;
 
-      SVN_ERR(proppatch_resource(proppatch, ctx->commit, scratch_pool));
+      SVN_ERR(proppatch_resource(ctx->commit_ctx->session,
+                                 ctx->commit_ctx->conn,
+                                 proppatch, scratch_pool));
     }
 
   return SVN_NO_ERROR;
@@ -2197,10 +2134,9 @@ close_edit(void *edit_baton,
   const char *merge_target =
     ctx->activity_url ? ctx->activity_url : ctx->txn_url;
   const svn_commit_info_t *commit_info;
-  int response_code;
 
   /* MERGE our activity */
-  SVN_ERR(svn_ra_serf__run_merge(&commit_info, &response_code,
+  SVN_ERR(svn_ra_serf__run_merge(&commit_info,
                                  ctx->session,
                                  ctx->session->conns[0],
                                  merge_target,
@@ -2208,14 +2144,6 @@ close_edit(void *edit_baton,
                                  ctx->keep_locks,
                                  pool, pool));
 
-  if (response_code != 200)
-    {
-      return svn_error_createf(SVN_ERR_RA_DAV_REQUEST_FAILED, NULL,
-                               _("MERGE request failed: returned %d "
-                                 "(during commit)"),
-                               response_code);
-    }
-
   /* Inform the WC that we did a commit.  */
   if (ctx->callback)
     SVN_ERR(ctx->callback(commit_info, ctx->callback_baton, pool));
@@ -2225,8 +2153,8 @@ close_edit(void *edit_baton,
     {
       svn_ra_serf__handler_t *handler;
 
-      handler = apr_pcalloc(pool, sizeof(*handler));
-      handler->handler_pool = pool;
+      handler = svn_ra_serf__create_handler(pool);
+
       handler->method = "DELETE";
       handler->path = ctx->activity_url;
       handler->conn = ctx->conn;
@@ -2235,9 +2163,12 @@ close_edit(void *edit_baton,
       handler->response_handler = svn_ra_serf__expect_empty_body;
       handler->response_baton = handler;
 
+      ctx->activity_url = NULL; /* Don't try again in abort_edit() on fail */
+
       SVN_ERR(svn_ra_serf__context_run_one(handler, pool));
 
-      SVN_ERR_ASSERT(handler->sline.code == 204);
+      if (handler->sline.code != 204)
+        return svn_error_trace(svn_ra_serf__unexpected_status(handler));
     }
 
   return SVN_NO_ERROR;
@@ -2260,14 +2191,15 @@ abort_edit(void *edit_baton,
   serf_connection_reset(ctx->session->conns[0]->conn);
 
   /* DELETE our aborted activity */
-  handler = apr_pcalloc(pool, sizeof(*handler));
-  handler->handler_pool = pool;
+  handler = svn_ra_serf__create_handler(pool);
+
   handler->method = "DELETE";
   handler->conn = ctx->session->conns[0];
   handler->session = ctx->session;
 
   handler->response_handler = svn_ra_serf__expect_empty_body;
   handler->response_baton = handler;
+  handler->no_fail_on_http_failure_status = TRUE;
 
   if (USING_HTTPV2_COMMIT_SUPPORT(ctx)) /* HTTP v2 */
     handler->path = ctx->txn_url;
@@ -2281,12 +2213,9 @@ abort_edit(void *edit_baton,
      404 if the activity wasn't found. */
   if (handler->sline.code != 204
       && handler->sline.code != 403
-      && handler->sline.code != 404
-      )
+      && handler->sline.code != 404)
     {
-      return svn_error_createf(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL,
-                               _("DELETE returned unexpected status: %d"),
-                               handler->sline.code);
+      return svn_error_trace(svn_ra_serf__unexpected_status(handler));
     }
 
   return SVN_NO_ERROR;
@@ -2337,7 +2266,8 @@ svn_ra_serf__get_commit_editor(svn_ra_se
   ctx->callback = callback;
   ctx->callback_baton = callback_baton;
 
-  ctx->lock_tokens = lock_tokens;
+  ctx->lock_tokens = (lock_tokens && apr_hash_count(lock_tokens))
+                       ? lock_tokens : NULL;
   ctx->keep_locks = keep_locks;
 
   ctx->deleted_entries = apr_hash_make(ctx->pool);
@@ -2381,28 +2311,43 @@ svn_ra_serf__change_rev_prop(svn_ra_sess
 {
   svn_ra_serf__session_t *session = ra_session->priv;
   proppatch_context_t *proppatch_ctx;
-  commit_context_t *commit;
   const char *proppatch_target;
   const char *ns;
+  const svn_string_t *tmp_old_value;
+  svn_boolean_t atomic_capable = FALSE;
   svn_error_t *err;
 
+  if (old_value_p || !value)
+    SVN_ERR(svn_ra_serf__has_capability(ra_session, &atomic_capable,
+                                        SVN_RA_CAPABILITY_ATOMIC_REVPROPS,
+                                        pool));
+
   if (old_value_p)
     {
-      svn_boolean_t capable;
-      SVN_ERR(svn_ra_serf__has_capability(ra_session, &capable,
-                                          SVN_RA_CAPABILITY_ATOMIC_REVPROPS,
-                                          pool));
-
       /* How did you get past the same check in svn_ra_change_rev_prop2()? */
-      SVN_ERR_ASSERT(capable);
+      SVN_ERR_ASSERT(atomic_capable);
     }
+  else if (! value && atomic_capable)
+    {
+      svn_string_t *old_value;
+      /* mod_dav_svn doesn't report a failure when a property delete fails. The
+         atomic revprop change behavior is a nice workaround, to allow getting
+         access to the error anyway.
 
-  commit = apr_pcalloc(pool, sizeof(*commit));
+         Somehow the mod_dav maintainers think that returning an error from
+         mod_dav's property delete is an RFC violation.
+         See https://issues.apache.org/bugzilla/show_bug.cgi?id=53525 */
 
-  commit->pool = pool;
+      SVN_ERR(svn_ra_serf__rev_prop(ra_session, rev, name, &old_value,
+                                    pool));
 
-  commit->session = session;
-  commit->conn = session->conns[0];
+      if (!old_value)
+        return SVN_NO_ERROR; /* Nothing to delete */
+
+      /* The api expects a double const pointer. Let's make one */
+      tmp_old_value = old_value;
+      old_value_p = &tmp_old_value;
+    }
 
   if (SVN_RA_SERF__HAVE_HTTPV2_SUPPORT(session))
     {
@@ -2412,11 +2357,11 @@ svn_ra_serf__change_rev_prop(svn_ra_sess
     {
       const char *vcc_url;
 
-      SVN_ERR(svn_ra_serf__discover_vcc(&vcc_url, commit->session,
-                                        commit->conn, pool));
+      SVN_ERR(svn_ra_serf__discover_vcc(&vcc_url, session,
+                                        session->conns[0], pool));
 
       SVN_ERR(svn_ra_serf__fetch_dav_prop(&proppatch_target,
-                                          commit->conn, vcc_url, rev,
+                                          session->conns[0], vcc_url, rev,
                                           "href",
                                           pool, pool));
     }
@@ -2434,14 +2379,14 @@ svn_ra_serf__change_rev_prop(svn_ra_sess
   /* PROPPATCH our log message and pass it along.  */
   proppatch_ctx = apr_pcalloc(pool, sizeof(*proppatch_ctx));
   proppatch_ctx->pool = pool;
-  proppatch_ctx->commit = commit;
+  proppatch_ctx->commit_ctx = NULL; /* No lock headers */
   proppatch_ctx->path = proppatch_target;
-  proppatch_ctx->changed_props = apr_hash_make(proppatch_ctx->pool);
-  proppatch_ctx->removed_props = apr_hash_make(proppatch_ctx->pool);
+  proppatch_ctx->changed_props = apr_hash_make(pool);
+  proppatch_ctx->removed_props = apr_hash_make(pool);
   if (old_value_p)
     {
-      proppatch_ctx->previous_changed_props = apr_hash_make(proppatch_ctx->pool);
-      proppatch_ctx->previous_removed_props = apr_hash_make(proppatch_ctx->pool);
+      proppatch_ctx->previous_changed_props = apr_hash_make(pool);
+      proppatch_ctx->previous_removed_props = apr_hash_make(pool);
     }
   proppatch_ctx->base_revision = SVN_INVALID_REVNUM;
 
@@ -2449,37 +2394,46 @@ svn_ra_serf__change_rev_prop(svn_ra_sess
     {
       svn_ra_serf__set_prop(proppatch_ctx->previous_changed_props,
                             proppatch_ctx->path,
-                            ns, name, *old_value_p, proppatch_ctx->pool);
+                            ns, name, *old_value_p, pool);
     }
   else if (old_value_p)
     {
-      svn_string_t *dummy_value = svn_string_create_empty(proppatch_ctx->pool);
+      svn_string_t *dummy_value = svn_string_create_empty(pool);
 
       svn_ra_serf__set_prop(proppatch_ctx->previous_removed_props,
                             proppatch_ctx->path,
-                            ns, name, dummy_value, proppatch_ctx->pool);
+                            ns, name, dummy_value, pool);
     }
 
   if (value)
     {
       svn_ra_serf__set_prop(proppatch_ctx->changed_props, proppatch_ctx->path,
-                            ns, name, value, proppatch_ctx->pool);
+                            ns, name, value, pool);
     }
   else
     {
-      value = svn_string_create_empty(proppatch_ctx->pool);
+      value = svn_string_create_empty(pool);
 
       svn_ra_serf__set_prop(proppatch_ctx->removed_props, proppatch_ctx->path,
-                            ns, name, value, proppatch_ctx->pool);
+                            ns, name, value, pool);
     }
 
-  err = proppatch_resource(proppatch_ctx, commit, proppatch_ctx->pool);
-  if (err)
-    return
-      svn_error_create
-      (SVN_ERR_RA_DAV_REQUEST_FAILED, err,
-       _("DAV request failed; it's possible that the repository's "
-         "pre-revprop-change hook either failed or is non-existent"));
+  err = proppatch_resource(session,
+                           session->conns[0],
+                            proppatch_ctx, pool);
 
-  return SVN_NO_ERROR;
+  /* Use specific error code for old property value mismatch.
+     Use loop to provide the right result with tracing */
+  if (err && err->apr_err == SVN_ERR_RA_DAV_PRECONDITION_FAILED)
+    {
+      svn_error_t *e = err;
+
+      while (e && e->apr_err == SVN_ERR_RA_DAV_PRECONDITION_FAILED)
+        {
+          e->apr_err = SVN_ERR_FS_PROP_BASEVALUE_MISMATCH;
+          e = e->child;
+        }
+    }
+
+  return svn_error_trace(err);
 }

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/get_deleted_rev.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/get_deleted_rev.c?rev=1556765&r1=1556764&r2=1556765&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/get_deleted_rev.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/get_deleted_rev.c Thu Jan  9 09:31:10 2014
@@ -151,7 +151,7 @@ svn_ra_serf__get_deleted_rev(svn_ra_sess
                                       pool, pool));
 
   xmlctx = svn_ra_serf__xml_context_create(getdrev_ttable,
-                                           NULL, getdrev_closed, NULL, NULL,
+                                           NULL, getdrev_closed, NULL,
                                            drev_ctx,
                                            pool);
   handler = svn_ra_serf__create_expat_handler(xmlctx, NULL, pool);

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/getdate.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/getdate.c?rev=1556765&r1=1556764&r2=1556765&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/getdate.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/getdate.c Thu Jan  9 09:31:10 2014
@@ -131,7 +131,6 @@ svn_ra_serf__get_dated_revision(svn_ra_s
   svn_ra_serf__handler_t *handler;
   svn_ra_serf__xml_context_t *xmlctx;
   const char *report_target;
-  svn_error_t *err;
 
   date_ctx = apr_palloc(pool, sizeof(*date_ctx));
   date_ctx->time = tm;
@@ -140,7 +139,7 @@ svn_ra_serf__get_dated_revision(svn_ra_s
   SVN_ERR(svn_ra_serf__report_resource(&report_target, session, NULL, pool));
 
   xmlctx = svn_ra_serf__xml_context_create(date_ttable,
-                                           NULL, date_closed, NULL, NULL,
+                                           NULL, date_closed, NULL,
                                            date_ctx,
                                            pool);
   handler = svn_ra_serf__create_expat_handler(xmlctx, NULL, pool);
@@ -156,13 +155,11 @@ svn_ra_serf__get_dated_revision(svn_ra_s
 
   *date_ctx->revision = SVN_INVALID_REVNUM;
 
-  err = svn_ra_serf__context_run_one(handler, pool);
+  SVN_ERR(svn_ra_serf__context_run_one(handler, pool));
 
-  SVN_ERR(svn_error_compose_create(
-              svn_ra_serf__error_on_status(handler->sline,
-                                           report_target,
-                                           handler->location),
-              err));
+  SVN_ERR(svn_ra_serf__error_on_status(handler->sline,
+                                       report_target,
+                                       handler->location));
 
   SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(*revision));
 

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/getlocations.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/getlocations.c?rev=1556765&r1=1556764&r2=1556765&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/getlocations.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/getlocations.c Thu Jan  9 09:31:10 2014
@@ -159,7 +159,6 @@ svn_ra_serf__get_locations(svn_ra_sessio
   svn_ra_serf__handler_t *handler;
   svn_ra_serf__xml_context_t *xmlctx;
   const char *req_url;
-  svn_error_t *err;
 
   loc_ctx = apr_pcalloc(pool, sizeof(*loc_ctx));
   loc_ctx->pool = pool;
@@ -176,7 +175,7 @@ svn_ra_serf__get_locations(svn_ra_sessio
                                       pool, pool));
 
   xmlctx = svn_ra_serf__xml_context_create(getloc_ttable,
-                                           NULL, getloc_closed, NULL, NULL,
+                                           NULL, getloc_closed, NULL,
                                            loc_ctx,
                                            pool);
   handler = svn_ra_serf__create_expat_handler(xmlctx, NULL, pool);
@@ -189,13 +188,11 @@ svn_ra_serf__get_locations(svn_ra_sessio
   handler->conn = session->conns[0];
   handler->session = session;
 
-  err = svn_ra_serf__context_run_one(handler, pool);
+  SVN_ERR(svn_ra_serf__context_run_one(handler, pool));
 
-  SVN_ERR(svn_error_compose_create(
-              svn_ra_serf__error_on_status(handler->sline,
-                                           req_url,
-                                           handler->location),
-              err));
+  SVN_ERR(svn_ra_serf__error_on_status(handler->sline,
+                                       handler->path,
+                                       handler->location));
 
   return SVN_NO_ERROR;
 }

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/getlocationsegments.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/getlocationsegments.c?rev=1556765&r1=1556764&r2=1556765&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/getlocationsegments.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/getlocationsegments.c Thu Jan  9 09:31:10 2014
@@ -178,7 +178,7 @@ svn_ra_serf__get_location_segments(svn_r
                                       pool, pool));
 
   xmlctx = svn_ra_serf__xml_context_create(gls_ttable,
-                                           NULL, gls_closed, NULL, NULL,
+                                           NULL, gls_closed, NULL,
                                            gls_ctx,
                                            pool);
   handler = svn_ra_serf__create_expat_handler(xmlctx, NULL, pool);
@@ -193,11 +193,12 @@ svn_ra_serf__get_location_segments(svn_r
 
   err = svn_ra_serf__context_run_one(handler, pool);
 
-  err = svn_error_compose_create(
-         svn_ra_serf__error_on_status(handler->sline,
-                                      handler->path,
-                                      handler->location),
-         err);
+  if (!err)
+    {
+      err = svn_ra_serf__error_on_status(handler->sline,
+                                         handler->path,
+                                         handler->location);
+    }
 
   if (err && (err->apr_err == SVN_ERR_UNSUPPORTED_FEATURE))
     return svn_error_create(SVN_ERR_RA_NOT_IMPLEMENTED, err, NULL);

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/getlocks.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/getlocks.c?rev=1556765&r1=1556764&r2=1556765&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/getlocks.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/getlocks.c Thu Jan  9 09:31:10 2014
@@ -246,7 +246,7 @@ svn_ra_serf__get_locks(svn_ra_session_t 
   lock_ctx->hash = apr_hash_make(pool);
 
   xmlctx = svn_ra_serf__xml_context_create(getlocks_ttable,
-                                           NULL, getlocks_closed, NULL, NULL,
+                                           NULL, getlocks_closed, NULL,
                                            lock_ctx,
                                            pool);
   handler = svn_ra_serf__create_expat_handler(xmlctx, NULL, pool);
@@ -259,16 +259,22 @@ svn_ra_serf__get_locks(svn_ra_session_t 
 
   handler->body_delegate = create_getlocks_body;
   handler->body_delegate_baton = lock_ctx;
+  handler->no_fail_on_http_failure_status = TRUE;
 
   SVN_ERR(svn_ra_serf__context_run_one(handler, pool));
 
   /* We get a 404 when a path doesn't exist in HEAD, but it might
      have existed earlier (E.g. 'svn ls http://s/svn/trunk/file@1' */
-  if (handler->sline.code != 404)
+  if (handler->sline.code != 200
+      && handler->sline.code != 404)
     {
-      SVN_ERR(svn_ra_serf__error_on_status(handler->sline,
-                                           handler->path,
-                                           handler->location));
+      svn_error_t *err = svn_ra_serf__unexpected_status(handler);
+
+      if (handler->sline.code == 500 || handler->sline.code == 501)
+        return svn_error_create(SVN_ERR_RA_NOT_IMPLEMENTED, err,
+                                _("Server does not support locking features"));
+
+      return svn_error_trace(err);
     }
 
   *locks = lock_ctx->hash;

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/inherited_props.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/inherited_props.c?rev=1556765&r1=1556764&r2=1556765&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/inherited_props.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/inherited_props.c Thu Jan  9 09:31:10 2014
@@ -29,12 +29,14 @@
 #include "svn_hash.h"
 #include "svn_path.h"
 #include "svn_ra.h"
+#include "svn_sorts.h"
 #include "svn_string.h"
 #include "svn_xml.h"
 #include "svn_props.h"
 #include "svn_base64.h"
 
 #include "private/svn_dav_protocol.h"
+#include "private/svn_sorts_private.h"
 #include "../libsvn_ra/ra_loader.h"
 #include "ra_serf.h"
 
@@ -220,6 +222,155 @@ create_iprops_body(serf_bucket_t **bkt,
   return SVN_NO_ERROR;
 }
 
+/* Per request information for get_iprops_via_more_requests */
+typedef struct iprop_rq_info_t
+{
+  const char *relpath;
+  const char *urlpath;
+  apr_hash_t *props;
+  svn_ra_serf__handler_t *handler;
+} iprop_rq_info_t;
+
+/* Removes all non regular properties from PROPS */
+static void
+keep_only_regular_props(apr_hash_t *props,
+                        apr_pool_t *scratch_pool)
+{
+  apr_hash_index_t *hi;
+
+  for (hi = apr_hash_first(scratch_pool, props); hi; hi = apr_hash_next(hi))
+    {
+      const char *propname = svn__apr_hash_index_key(hi);
+
+      if (svn_property_kind2(propname) != svn_prop_regular_kind)
+        svn_hash_sets(props, propname, NULL);
+    }
+}
+
+/* Assumes session reparented to the repository root. The old session
+   root is passed as session_url */
+static svn_error_t *
+get_iprops_via_more_requests(svn_ra_session_t *ra_session,
+                             apr_array_header_t **iprops,
+                             const char *session_url,
+                             const char *path,
+                             svn_revnum_t revision,
+                             apr_pool_t *result_pool,
+                             apr_pool_t *scratch_pool)
+{
+  svn_ra_serf__session_t *session = ra_session->priv;
+  const char *url;
+  const char *relpath;
+  apr_array_header_t *rq_info;
+  apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+  apr_interval_time_t waittime_left = session->timeout;
+  const svn_revnum_t rev_marker = SVN_INVALID_REVNUM;
+  int i;
+
+  rq_info = apr_array_make(scratch_pool, 16, sizeof(iprop_rq_info_t *));
+
+  if (!svn_path_is_empty(path))
+    url = svn_path_url_add_component2(session_url, path, scratch_pool);
+  else
+    url = session_url;
+
+  relpath = svn_uri_skip_ancestor(session->repos_root_str, url, scratch_pool);
+
+  /* Create all requests */
+  while (relpath[0] != '\0')
+    {
+      iprop_rq_info_t *rq = apr_pcalloc(scratch_pool, sizeof(*rq));
+
+      relpath = svn_relpath_dirname(relpath, scratch_pool);
+
+      rq->relpath = relpath;
+      rq->props = apr_hash_make(scratch_pool);
+
+      SVN_ERR(svn_ra_serf__get_stable_url(&rq->urlpath, NULL, session,
+                                          session->conns[0],
+                                          svn_path_url_add_component2(
+                                                session->repos_root.path,
+                                                relpath, scratch_pool),
+                                          revision,
+                                          scratch_pool, scratch_pool));
+
+      SVN_ERR(svn_ra_serf__deliver_props(&rq->handler, rq->props, session,
+                                         session->conns[0], rq->urlpath,
+                                         rev_marker, "0", all_props,
+                                         NULL, scratch_pool));
+
+      /* Allow ignoring authz problems */
+      rq->handler->no_fail_on_http_failure_status = TRUE;
+
+      svn_ra_serf__request_create(rq->handler);
+
+      APR_ARRAY_PUSH(rq_info, iprop_rq_info_t *) = rq;
+    }
+
+  while (TRUE)
+    {
+      svn_pool_clear(iterpool);
+
+      SVN_ERR(svn_ra_serf__context_run(session, &waittime_left, iterpool));
+
+      for (i = 0; i < rq_info->nelts; i++)
+        {
+          iprop_rq_info_t *rq = APR_ARRAY_IDX(rq_info, i, iprop_rq_info_t *);
+
+          if (!rq->handler->done)
+            break;
+        }
+
+      if (i >= rq_info->nelts)
+        break; /* All requests done */
+    }
+
+  *iprops = apr_array_make(result_pool, rq_info->nelts,
+                           sizeof(svn_prop_inherited_item_t *));
+
+  /* And now create the result set */
+  for (i = 0; i < rq_info->nelts; i++)
+    {
+      iprop_rq_info_t *rq = APR_ARRAY_IDX(rq_info, i, iprop_rq_info_t *);
+      apr_hash_t *node_props;
+      svn_prop_inherited_item_t *new_iprop;
+
+      if (rq->handler->sline.code >= 400 && rq->handler->sline.code != 403)
+        {
+          return svn_error_trace(
+                        svn_ra_serf__error_on_status(rq->handler->sline,
+                                                     rq->handler->path,
+                                                     rq->handler->location));
+        }
+
+      /* Obtain the real properties from the double hash */
+      node_props = apr_hash_get(rq->props, &rev_marker, sizeof(rev_marker));
+
+      if (!node_props)
+        continue;
+
+      node_props = svn_hash_gets(node_props, rq->urlpath);
+
+      if (!node_props)
+        continue;
+
+      SVN_ERR(svn_ra_serf__flatten_props(&node_props, node_props,
+                                         scratch_pool, scratch_pool));
+
+      keep_only_regular_props(node_props, scratch_pool);
+
+      if (!apr_hash_count(node_props))
+        continue;
+
+      new_iprop = apr_palloc(result_pool, sizeof(*new_iprop));
+      new_iprop->path_or_url = apr_pstrdup(result_pool, rq->relpath);
+      new_iprop->prop_hash = svn_prop_hash_dup(node_props, result_pool);
+      svn_sort__array_insert(*iprops, &new_iprop, 0);
+    }
+
+  return SVN_NO_ERROR;
+}
+
 /* Request a inherited-props-report from the URL attached to RA_SESSION,
    and fill the IPROPS array hash with the results.  */
 svn_error_t *
@@ -230,12 +381,47 @@ svn_ra_serf__get_inherited_props(svn_ra_
                                  apr_pool_t *result_pool,
                                  apr_pool_t *scratch_pool)
 {
-  svn_error_t *err;
   iprops_context_t *iprops_ctx;
   svn_ra_serf__session_t *session = ra_session->priv;
   svn_ra_serf__handler_t *handler;
   svn_ra_serf__xml_context_t *xmlctx;
   const char *req_url;
+  svn_boolean_t iprop_capable;
+
+  SVN_ERR(svn_ra_serf__has_capability(ra_session, &iprop_capable,
+                                      SVN_RA_CAPABILITY_INHERITED_PROPS,
+                                      scratch_pool));
+
+  if (!iprop_capable)
+    {
+      svn_error_t *err;
+      const char *reparent_uri = NULL;
+      const char *session_uri;
+      const char *repos_root_url;
+
+      SVN_ERR(svn_ra_serf__get_repos_root(ra_session, &repos_root_url,
+                                          scratch_pool));
+
+      session_uri = apr_pstrdup(scratch_pool, session->session_url_str);
+      if (strcmp(repos_root_url, session->session_url_str) != 0)
+        {
+          reparent_uri  = session_uri;
+          SVN_ERR(svn_ra_serf__reparent(ra_session, repos_root_url,
+                                        scratch_pool));
+        }
+
+      /* For now, use implementation in libsvn_ra */
+      err = get_iprops_via_more_requests(ra_session, iprops, session_uri, path,
+                                         revision, result_pool, scratch_pool);
+
+      if (reparent_uri)
+        err = svn_error_compose_create(err,
+                                       svn_ra_serf__reparent(ra_session,
+                                                             reparent_uri ,
+                                                             scratch_pool));
+
+      return svn_error_trace(err);
+    }
 
   SVN_ERR(svn_ra_serf__get_stable_url(&req_url,
                                       NULL /* latest_revnum */,
@@ -259,7 +445,7 @@ svn_ra_serf__get_inherited_props(svn_ra_
 
   xmlctx = svn_ra_serf__xml_context_create(iprops_table,
                                            iprops_opened, iprops_closed,
-                                           NULL, NULL,
+                                           NULL,
                                            iprops_ctx,
                                            scratch_pool);
   handler = svn_ra_serf__create_expat_handler(xmlctx, NULL, scratch_pool);
@@ -271,14 +457,11 @@ svn_ra_serf__get_inherited_props(svn_ra_
   handler->body_delegate = create_iprops_body;
   handler->body_delegate_baton = iprops_ctx;
   handler->body_type = "text/xml";
-  handler->handler_pool = scratch_pool;
 
-  err = svn_ra_serf__context_run_one(handler, scratch_pool);
-  SVN_ERR(svn_error_compose_create(
-                    svn_ra_serf__error_on_status(handler->sline,
-                                                 handler->path,
-                                                 handler->location),
-                    err));
+  SVN_ERR(svn_ra_serf__context_run_one(handler, scratch_pool));
+
+  if (handler->sline.code != 200)
+    return svn_error_trace(svn_ra_serf__unexpected_status(handler));
 
   *iprops = iprops_ctx->iprops;
 

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/log.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/log.c?rev=1556765&r1=1556764&r2=1556765&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/log.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/log.c Thu Jan  9 09:31:10 2014
@@ -542,7 +542,6 @@ svn_ra_serf__get_log(svn_ra_session_t *r
   svn_ra_serf__xml_context_t *xmlctx;
   svn_boolean_t want_custom_revprops;
   svn_revnum_t peg_rev;
-  svn_error_t *err;
   const char *req_url;
 
   log_ctx = apr_pcalloc(pool, sizeof(*log_ctx));
@@ -604,7 +603,7 @@ svn_ra_serf__get_log(svn_ra_session_t *r
                                       pool, pool));
 
   xmlctx = svn_ra_serf__xml_context_create(log_ttable,
-                                           log_opened, log_closed, NULL, NULL,
+                                           log_opened, log_closed, NULL,
                                            log_ctx,
                                            pool);
   handler = svn_ra_serf__create_expat_handler(xmlctx, NULL, pool);
@@ -617,13 +616,10 @@ svn_ra_serf__get_log(svn_ra_session_t *r
   handler->conn = session->conns[0];
   handler->session = session;
 
-  err = svn_ra_serf__context_run_one(handler, pool);
+  SVN_ERR(svn_ra_serf__context_run_one(handler, pool));
 
-  SVN_ERR(svn_error_compose_create(
+  return svn_error_trace(
               svn_ra_serf__error_on_status(handler->sline,
                                            req_url,
-                                           handler->location),
-              err));
-
-  return SVN_NO_ERROR;
+                                           handler->location));
 }

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/merge.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/merge.c?rev=1556765&r1=1556764&r2=1556765&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/merge.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/merge.c Thu Jan  9 09:31:10 2014
@@ -65,7 +65,7 @@ typedef enum merge_state_e {
   AUTHOR,
   POST_COMMIT_ERR,
 
-  PROP_VAL
+  STATUS
 } merge_state_e;
 
 
@@ -279,12 +279,12 @@ setup_merge_headers(serf_bucket_t *heade
   return SVN_NO_ERROR;
 }
 
-void
-svn_ra_serf__merge_lock_token_list(apr_hash_t *lock_tokens,
-                                   const char *parent,
-                                   serf_bucket_t *body,
-                                   serf_bucket_alloc_t *alloc,
-                                   apr_pool_t *pool)
+static void
+merge_lock_token_list(apr_hash_t *lock_tokens,
+                      const char *parent,
+                      serf_bucket_t *body,
+                      serf_bucket_alloc_t *alloc,
+                      apr_pool_t *pool)
 {
   apr_hash_index_t *hi;
 
@@ -363,8 +363,7 @@ create_merge_body(serf_bucket_t **bkt,
   svn_ra_serf__add_tag_buckets(body_bkt, "D:creator-displayname", NULL, alloc);
   svn_ra_serf__add_close_tag_buckets(body_bkt, alloc, "D:prop");
 
-  svn_ra_serf__merge_lock_token_list(ctx->lock_tokens, NULL, body_bkt, alloc,
-                                     pool);
+  merge_lock_token_list(ctx->lock_tokens, NULL, body_bkt, alloc, pool);
 
   svn_ra_serf__add_close_tag_buckets(body_bkt, alloc, "D:merge");
 
@@ -376,7 +375,6 @@ create_merge_body(serf_bucket_t **bkt,
 
 svn_error_t *
 svn_ra_serf__run_merge(const svn_commit_info_t **commit_info,
-                       int *response_code,
                        svn_ra_serf__session_t *session,
                        svn_ra_serf__connection_t *conn,
                        const char *merge_resource_url,
@@ -404,7 +402,7 @@ svn_ra_serf__run_merge(const svn_commit_
   merge_ctx->merge_url = session->session_url.path;
 
   xmlctx = svn_ra_serf__xml_context_create(merge_ttable,
-                                           NULL, merge_closed, NULL, NULL,
+                                           NULL, merge_closed, NULL,
                                            merge_ctx,
                                            scratch_pool);
   handler = svn_ra_serf__create_expat_handler(xmlctx, NULL, scratch_pool);
@@ -423,8 +421,10 @@ svn_ra_serf__run_merge(const svn_commit_
 
   SVN_ERR(svn_ra_serf__context_run_one(handler, scratch_pool));
 
+  if (handler->sline.code != 200)
+    return svn_error_trace(svn_ra_serf__unexpected_status(handler));
+
   *commit_info = merge_ctx->commit_info;
-  *response_code = handler->sline.code;
 
   return SVN_NO_ERROR;
 }

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/mergeinfo.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/mergeinfo.c?rev=1556765&r1=1556764&r2=1556765&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/mergeinfo.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/mergeinfo.c Thu Jan  9 09:31:10 2014
@@ -191,7 +191,6 @@ svn_ra_serf__get_mergeinfo(svn_ra_sessio
                            svn_boolean_t include_descendants,
                            apr_pool_t *pool)
 {
-  svn_error_t *err;
   mergeinfo_context_t *mergeinfo_ctx;
   svn_ra_serf__session_t *session = ra_session->priv;
   svn_ra_serf__handler_t *handler;
@@ -214,7 +213,7 @@ svn_ra_serf__get_mergeinfo(svn_ra_sessio
   mergeinfo_ctx->include_descendants = include_descendants;
 
   xmlctx = svn_ra_serf__xml_context_create(mergeinfo_ttable,
-                                           NULL, mergeinfo_closed, NULL, NULL,
+                                           NULL, mergeinfo_closed, NULL,
                                            mergeinfo_ctx,
                                            pool);
   handler = svn_ra_serf__create_expat_handler(xmlctx, NULL, pool);
@@ -227,14 +226,12 @@ svn_ra_serf__get_mergeinfo(svn_ra_sessio
   handler->body_delegate_baton = mergeinfo_ctx;
   handler->body_type = "text/xml";
 
-  err = svn_ra_serf__context_run_one(handler, pool);
+  SVN_ERR(svn_ra_serf__context_run_one(handler, pool));
 
-  SVN_ERR(svn_error_compose_create(
-                svn_ra_serf__error_on_status(handler->sline, handler->path,
-                                             handler->location),
-                err));
+  SVN_ERR(svn_ra_serf__error_on_status(handler->sline, handler->path,
+                                       handler->location));
 
-  if (handler->done && apr_hash_count(mergeinfo_ctx->result_catalog))
+  if (apr_hash_count(mergeinfo_ctx->result_catalog))
     *catalog = mergeinfo_ctx->result_catalog;
 
   return SVN_NO_ERROR;