summaryrefslogtreecommitdiff
path: root/subversion/libsvn_ra_serf/commit.c
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@baserock.org>2015-03-18 13:33:26 +0000
committer <>2015-07-08 14:41:01 +0000
commitbb0ef45f7c46b0ae221b26265ef98a768c33f820 (patch)
tree98bae10dde41c746c51ae97ec4f879e330415aa7 /subversion/libsvn_ra_serf/commit.c
parent239dfafe71711b2f4c43d7b90a1228d7bdc5195e (diff)
downloadsubversion-tarball-subversion-1.8.13.tar.gz
Imported from /home/lorry/working-area/delta_subversion-tarball/subversion-1.8.13.tar.gz.subversion-1.8.13
Diffstat (limited to 'subversion/libsvn_ra_serf/commit.c')
-rw-r--r--subversion/libsvn_ra_serf/commit.c1216
1 files changed, 627 insertions, 589 deletions
diff --git a/subversion/libsvn_ra_serf/commit.c b/subversion/libsvn_ra_serf/commit.c
index 25aefb3..9d48d41 100644
--- a/subversion/libsvn_ra_serf/commit.c
+++ b/subversion/libsvn_ra_serf/commit.c
@@ -22,11 +22,9 @@
*/
#include <apr_uri.h>
-
-#include <expat.h>
-
#include <serf.h>
+#include "svn_hash.h"
#include "svn_pools.h"
#include "svn_ra.h"
#include "svn_dav.h"
@@ -41,23 +39,11 @@
#include "svn_private_config.h"
#include "private/svn_dep_compat.h"
#include "private/svn_fspath.h"
+#include "private/svn_skel.h"
#include "ra_serf.h"
#include "../libsvn_ra/ra_loader.h"
-
-/* Structure associated with a CHECKOUT request. */
-typedef struct checkout_context_t {
-
- apr_pool_t *pool;
-
- const char *activity_url;
- const char *checkout_url;
- const char *resource_url;
-
- svn_ra_serf__simple_request_context_t progress;
-
-} checkout_context_t;
/* Baton passed back with the commit editor. */
typedef struct commit_context_t {
@@ -82,7 +68,7 @@ typedef struct commit_context_t {
/* HTTP v1 stuff (only valid when 'txn_url' is NULL) */
const char *activity_url; /* activity base URL... */
- checkout_context_t *baseline; /* checkout for the baseline */
+ const char *baseline_url; /* the working-baseline resource */
const char *checked_in_url; /* checked-in root to base CHECKOUTs from */
const char *vcc_url; /* vcc url */
@@ -110,19 +96,14 @@ typedef struct proppatch_context_t {
/* In HTTP v2, this is the file/directory version we think we're changing. */
svn_revnum_t base_revision;
- svn_ra_serf__simple_request_context_t progress;
} 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;
-
- svn_ra_serf__simple_request_context_t progress;
+ commit_context_t *commit;
} delete_context_t;
/* Represents a directory. */
@@ -162,10 +143,9 @@ typedef struct dir_context_t {
apr_hash_t *changed_props;
apr_hash_t *removed_props;
- /* The checked out context for this directory. May be NULL; if so
+ /* The checked-out working resource for this directory. May be NULL; if so
call checkout_dir() first. */
- checkout_context_t *checkout;
-
+ const char *working_url;
} dir_context_t;
/* Represents a file to be committed. */
@@ -184,8 +164,8 @@ typedef struct file_context_t {
const char *relpath;
const char *name;
- /* The checked out context for this file. */
- checkout_context_t *checkout;
+ /* The checked-out working resource for this file. */
+ const char *working_url;
/* The base revision of the file. */
svn_revnum_t base_revision;
@@ -219,24 +199,29 @@ 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_ra_serf__simple_request_context_t *ctx)
+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(
- ctx->server_error.error,
+ 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,
- ctx->status, ctx->reason));
+ 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(ctx->status,
- handler->path,
- ctx->location),
+ return svn_error_compose_create(svn_ra_serf__error_on_status(
+ handler->sline,
+ handler->path,
+ handler->location),
err);
}
@@ -247,7 +232,7 @@ create_checkout_body(serf_bucket_t **bkt,
serf_bucket_alloc_t *alloc,
apr_pool_t *pool)
{
- checkout_context_t *ctx = baton;
+ const char *activity_url = baton;
serf_bucket_t *body_bkt;
body_bkt = serf_bucket_aggregate_create(alloc);
@@ -259,8 +244,10 @@ create_checkout_body(serf_bucket_t **bkt,
svn_ra_serf__add_open_tag_buckets(body_bkt, alloc, "D:activity-set", NULL);
svn_ra_serf__add_open_tag_buckets(body_bkt, alloc, "D:href", NULL);
+ SVN_ERR_ASSERT(activity_url != NULL);
svn_ra_serf__add_cdata_len_buckets(body_bkt, alloc,
- ctx->activity_url, strlen(ctx->activity_url));
+ activity_url,
+ strlen(activity_url));
svn_ra_serf__add_close_tag_buckets(body_bkt, alloc, "D:href");
svn_ra_serf__add_close_tag_buckets(body_bkt, alloc, "D:activity-set");
@@ -271,137 +258,185 @@ create_checkout_body(serf_bucket_t **bkt,
return SVN_NO_ERROR;
}
-/* Implements svn_ra_serf__response_handler_t */
+
+/* Using the HTTPv1 protocol, perform a CHECKOUT of NODE_URL within the
+ given COMMIT_CTX. The resulting working resource will be returned in
+ *WORKING_URL, allocated from RESULT_POOL. All temporary allocations
+ are performed in SCRATCH_POOL.
+
+ ### are these URLs actually repos relpath values? or fspath? or maybe
+ ### the abspath portion of the full URL.
+
+ This function operates synchronously.
+
+ Strictly speaking, we could perform "all" of the CHECKOUT requests
+ when the commit starts, and only block when we need a specific
+ answer. Or, at a minimum, send off these individual requests async
+ and block when we need the answer (eg PUT or PROPPATCH).
+
+ However: the investment to speed this up is not worthwhile, given
+ that CHECKOUT (and the related round trip) is completely obviated
+ in HTTPv2.
+*/
static svn_error_t *
-handle_checkout(serf_request_t *request,
- serf_bucket_t *response,
- void *handler_baton,
- apr_pool_t *pool)
+checkout_node(const char **working_url,
+ const commit_context_t *commit_ctx,
+ const char *node_url,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
{
- checkout_context_t *ctx = handler_baton;
+ svn_ra_serf__handler_t handler = { 0 };
+ apr_status_t status;
+ apr_uri_t uri;
- svn_error_t *err = svn_ra_serf__handle_status_only(request, response,
- &ctx->progress, pool);
+ /* 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;
- /* These handler functions are supposed to return an APR_EOF status
- wrapped in a svn_error_t to indicate to serf that the response was
- completely read. While we have to return this status code to our
- caller, we should treat it as the normal case for now. */
- if (err && ! APR_STATUS_IS_EOF(err->apr_err))
- return err;
+ handler.body_delegate = create_checkout_body;
+ handler.body_delegate_baton = (/* const */ void *)commit_ctx->activity_url;
+ handler.body_type = "text/xml";
- /* Get the resulting location. */
- if (ctx->progress.done && ctx->progress.status == 201)
- {
- serf_bucket_t *hdrs;
- apr_uri_t uri;
- const char *location;
- apr_status_t status;
+ handler.response_handler = svn_ra_serf__expect_empty_body;
+ handler.response_baton = &handler;
- hdrs = serf_bucket_response_get_headers(response);
- location = serf_bucket_headers_get(hdrs, "Location");
- if (!location)
- return svn_error_create(SVN_ERR_RA_DAV_MALFORMED_DATA, err,
- _("No Location header received"));
+ handler.method = "CHECKOUT";
+ handler.path = node_url;
- status = apr_uri_parse(pool, location, &uri);
+ SVN_ERR(svn_ra_serf__context_run_one(&handler, scratch_pool));
- if (status)
- err = svn_error_compose_create(svn_error_wrap_apr(status, NULL), err);
+ if (handler.sline.code != 201)
+ return svn_error_trace(return_response_err(&handler));
+
+ if (handler.location == NULL)
+ return svn_error_create(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL,
+ _("No Location header received"));
+
+ /* We only want the path portion of the Location header.
+ (code.google.com sometimes returns an 'http:' scheme for an
+ '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);
+ if (status)
+ return svn_error_create(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL,
+ _("Error parsing Location header value"));
+
+ *working_url = svn_urlpath__canonicalize(uri.path, result_pool);
+
+ return SVN_NO_ERROR;
+}
+
+
+/* This is a wrapper around checkout_node() (which see for
+ documentation) which simply retries the CHECKOUT request when it
+ fails due to an SVN_ERR_APMOD_BAD_BASELINE error return from the
+ server.
- ctx->resource_url = svn_urlpath__canonicalize(uri.path, ctx->pool);
+ See http://subversion.tigris.org/issues/show_bug.cgi?id=4127 for
+ details.
+*/
+static svn_error_t *
+retry_checkout_node(const char **working_url,
+ const commit_context_t *commit_ctx,
+ const char *node_url,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ svn_error_t *err = SVN_NO_ERROR;
+ int retry_count = 5; /* Magic, arbitrary number. */
+
+ do
+ {
+ svn_error_clear(err);
+
+ err = checkout_node(working_url, commit_ctx, node_url,
+ result_pool, scratch_pool);
+
+ /* There's a small chance of a race condition here if Apache is
+ experiencing heavy commit concurrency or if the network has
+ long latency. It's possible that the value of HEAD changed
+ between the time we fetched the latest baseline and the time
+ we try to CHECKOUT that baseline. If that happens, Apache
+ will throw us a BAD_BASELINE error (deltaV says you can only
+ checkout the latest baseline). We just ignore that specific
+ error and retry a few times, asking for the latest baseline
+ again. */
+ if (err && (err->apr_err != SVN_ERR_APMOD_BAD_BASELINE))
+ return err;
}
+ while (err && retry_count--);
return err;
}
+
static svn_error_t *
-checkout_dir(dir_context_t *dir)
+checkout_dir(dir_context_t *dir,
+ apr_pool_t *scratch_pool)
{
- checkout_context_t *checkout_ctx;
- svn_ra_serf__handler_t *handler;
svn_error_t *err;
dir_context_t *p_dir = dir;
+ const char *checkout_url;
+ const char **working;
- if (dir->checkout)
+ if (dir->working_url)
{
return SVN_NO_ERROR;
}
- /* Is this directory or one of our parent dirs newly added?
+ /* Is this directory or one of our parent dirs newly added?
* If so, we're already implicitly checked out. */
while (p_dir)
{
if (p_dir->added)
{
- /* Implicitly checkout this dir now. */
- dir->checkout = apr_pcalloc(dir->pool, sizeof(*dir->checkout));
- dir->checkout->pool = dir->pool;
- dir->checkout->progress.pool = dir->pool;
- dir->checkout->activity_url = dir->commit->activity_url;
- dir->checkout->resource_url =
- svn_path_url_add_component2(dir->parent_dir->checkout->resource_url,
- dir->name, dir->pool);
+ /* Calculate the working_url by skipping the shared ancestor bewteen
+ * the parent->relpath and dir->relpath. This is safe since an
+ * add is guaranteed to have a parent that is checked out. */
+ dir_context_t *parent = p_dir->parent_dir;
+ const char *relpath = svn_relpath_skip_ancestor(parent->relpath,
+ dir->relpath);
+ /* Implicitly checkout this dir now. */
+ SVN_ERR_ASSERT(parent->working_url);
+ dir->working_url = svn_path_url_add_component2(
+ parent->working_url,
+ relpath, dir->pool);
return SVN_NO_ERROR;
}
p_dir = p_dir->parent_dir;
}
- /* Checkout our directory into the activity URL now. */
- handler = apr_pcalloc(dir->pool, sizeof(*handler));
- handler->session = dir->commit->session;
- handler->conn = dir->commit->conn;
-
- checkout_ctx = apr_pcalloc(dir->pool, sizeof(*checkout_ctx));
- checkout_ctx->pool = dir->pool;
- checkout_ctx->progress.pool = dir->pool;
-
- checkout_ctx->activity_url = dir->commit->activity_url;
-
/* We could be called twice for the root: once to checkout the baseline;
* 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)
+ if (!dir->parent_dir && !dir->commit->baseline_url)
{
- checkout_ctx->checkout_url = dir->commit->vcc_url;
- dir->commit->baseline = checkout_ctx;
+ checkout_url = dir->commit->vcc_url;
+ working = &dir->commit->baseline_url;
}
else
{
- checkout_ctx->checkout_url = dir->url;
- dir->checkout = checkout_ctx;
+ checkout_url = dir->url;
+ working = &dir->working_url;
}
- handler->body_delegate = create_checkout_body;
- handler->body_delegate_baton = checkout_ctx;
- handler->body_type = "text/xml";
-
- handler->response_handler = handle_checkout;
- handler->response_baton = checkout_ctx;
-
- handler->method = "CHECKOUT";
- handler->path = checkout_ctx->checkout_url;
-
- svn_ra_serf__request_create(handler);
-
- err = svn_ra_serf__context_run_wait(&checkout_ctx->progress.done,
- dir->commit->session,
- dir->pool);
+ /* 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(dir->pool,
+ SVN_ERR_W(err, apr_psprintf(scratch_pool,
_("Directory '%s' is out of date; try updating"),
- svn_dirent_local_style(dir->relpath, dir->pool)));
+ svn_dirent_local_style(dir->relpath, scratch_pool)));
return err;
}
- if (checkout_ctx->progress.status != 201)
- {
- return return_response_err(handler, &checkout_ctx->progress);
- }
-
return SVN_NO_ERROR;
}
@@ -419,16 +454,17 @@ checkout_dir(dir_context_t *dir)
* BASE_REVISION, and set *CHECKED_IN_URL to the concatenation of that
* with RELPATH.
*
- * Allocate the result in POOL, and use POOL for temporary allocation.
+ * Allocate the result in RESULT_POOL, and use SCRATCH_POOL for
+ * temporary allocation.
*/
static svn_error_t *
get_version_url(const char **checked_in_url,
svn_ra_serf__session_t *session,
- svn_ra_serf__connection_t *conn,
const char *relpath,
svn_revnum_t base_revision,
const char *parent_vsn_url,
- apr_pool_t *pool)
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
{
const char *root_checkout;
@@ -436,15 +472,16 @@ get_version_url(const char **checked_in_url,
{
const svn_string_t *current_version;
- SVN_ERR(session->wc_callbacks->get_wc_prop(session->wc_callback_baton,
- relpath,
- SVN_RA_SERF__WC_CHECKED_IN_URL,
- &current_version, pool));
+ SVN_ERR(session->wc_callbacks->get_wc_prop(
+ session->wc_callback_baton,
+ relpath,
+ SVN_RA_SERF__WC_CHECKED_IN_URL,
+ &current_version, scratch_pool));
if (current_version)
{
*checked_in_url =
- svn_urlpath__canonicalize(current_version->data, pool);
+ svn_urlpath__canonicalize(current_version->data, result_pool);
return SVN_NO_ERROR;
}
}
@@ -455,63 +492,53 @@ get_version_url(const char **checked_in_url,
}
else
{
- svn_ra_serf__propfind_context_t *propfind_ctx;
- apr_hash_t *props;
const char *propfind_url;
-
- props = apr_hash_make(pool);
+ svn_ra_serf__connection_t *conn = session->conns[0];
if (SVN_IS_VALID_REVNUM(base_revision))
{
- const char *bc_url, *bc_relpath;
-
/* mod_dav_svn can't handle the "Label:" header that
svn_ra_serf__deliver_props() is going to try to use for
this lookup, so we'll do things the hard(er) way, by
looking up the version URL from a resource in the
baseline collection. */
- SVN_ERR(svn_ra_serf__get_baseline_info(&bc_url, &bc_relpath,
- session, conn,
- session->session_url.path,
- base_revision, NULL, pool));
- propfind_url = svn_path_url_add_component2(bc_url, bc_relpath, pool);
+ /* ### conn==NULL for session->conns[0]. same as CONN. */
+ SVN_ERR(svn_ra_serf__get_stable_url(&propfind_url,
+ NULL /* latest_revnum */,
+ session, NULL /* conn */,
+ NULL /* url */, base_revision,
+ scratch_pool, scratch_pool));
}
else
{
propfind_url = session->session_url.path;
}
- /* ### switch to svn_ra_serf__retrieve_props */
- SVN_ERR(svn_ra_serf__deliver_props(&propfind_ctx, props, session, conn,
- propfind_url, base_revision, "0",
- checked_in_props, NULL, pool));
- SVN_ERR(svn_ra_serf__wait_for_props(propfind_ctx, session, pool));
-
- /* We wouldn't get here if the url wasn't found (404), so the checked-in
- property should have been set. */
- root_checkout =
- svn_ra_serf__get_ver_prop(props, propfind_url,
- base_revision, "DAV:", "checked-in");
-
+ SVN_ERR(svn_ra_serf__fetch_dav_prop(&root_checkout,
+ conn, propfind_url, base_revision,
+ "checked-in",
+ scratch_pool, scratch_pool));
if (!root_checkout)
return svn_error_createf(SVN_ERR_RA_DAV_REQUEST_FAILED, NULL,
_("Path '%s' not present"),
session->session_url.path);
- root_checkout = svn_urlpath__canonicalize(root_checkout, pool);
+ root_checkout = svn_urlpath__canonicalize(root_checkout, scratch_pool);
}
- *checked_in_url = svn_path_url_add_component2(root_checkout, relpath, pool);
+ *checked_in_url = svn_path_url_add_component2(root_checkout, relpath,
+ result_pool);
return SVN_NO_ERROR;
}
static svn_error_t *
-checkout_file(file_context_t *file)
+checkout_file(file_context_t *file,
+ apr_pool_t *scratch_pool)
{
- svn_ra_serf__handler_t *handler;
svn_error_t *err;
dir_context_t *parent_dir = file->parent_dir;
+ const char *checkout_url;
/* Is one of our parent dirs newly added? If so, we're already
* implicitly checked out.
@@ -521,69 +548,33 @@ checkout_file(file_context_t *file)
if (parent_dir->added)
{
/* Implicitly checkout this file now. */
- file->checkout = apr_pcalloc(file->pool, sizeof(*file->checkout));
- file->checkout->pool = file->pool;
- file->checkout->progress.pool = file->pool;
- file->checkout->activity_url = file->commit->activity_url;
- file->checkout->resource_url =
- svn_path_url_add_component2(parent_dir->checkout->resource_url,
- svn_relpath__is_child(parent_dir->relpath,
- file->relpath,
- file->pool),
- file->pool);
+ file->working_url = svn_path_url_add_component2(
+ parent_dir->working_url,
+ svn_relpath_skip_ancestor(
+ parent_dir->relpath, file->relpath),
+ file->pool);
return SVN_NO_ERROR;
}
parent_dir = parent_dir->parent_dir;
}
- /* Checkout our file into the activity URL now. */
- handler = apr_pcalloc(file->pool, sizeof(*handler));
- handler->session = file->commit->session;
- handler->conn = file->commit->conn;
-
- file->checkout = apr_pcalloc(file->pool, sizeof(*file->checkout));
- file->checkout->pool = file->pool;
- file->checkout->progress.pool = file->pool;
-
- file->checkout->activity_url = file->commit->activity_url;
-
- SVN_ERR(get_version_url(&(file->checkout->checkout_url),
- file->commit->session, file->commit->conn,
+ SVN_ERR(get_version_url(&checkout_url,
+ file->commit->session,
file->relpath, file->base_revision,
- NULL, file->pool));
-
- handler->body_delegate = create_checkout_body;
- handler->body_delegate_baton = file->checkout;
- handler->body_type = "text/xml";
-
- handler->response_handler = handle_checkout;
- handler->response_baton = file->checkout;
+ NULL, scratch_pool, scratch_pool));
- handler->method = "CHECKOUT";
- handler->path = file->checkout->checkout_url;
-
- svn_ra_serf__request_create(handler);
-
- /* There's no need to wait here as we only need this when we start the
- * PROPPATCH or PUT of the file.
- */
- err = svn_ra_serf__context_run_wait(&file->checkout->progress.done,
- file->commit->session,
- file->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(file->pool,
+ SVN_ERR_W(err, apr_psprintf(scratch_pool,
_("File '%s' is out of date; try updating"),
- svn_dirent_local_style(file->relpath, file->pool)));
+ svn_dirent_local_style(file->relpath, scratch_pool)));
return err;
}
- if (file->checkout->progress.status != 201)
- {
- return return_response_err(handler, &file->checkout->progress);
- }
-
return SVN_NO_ERROR;
}
@@ -788,6 +779,54 @@ proppatch_walker(void *baton,
return SVN_NO_ERROR;
}
+/* Possible add the lock-token "If:" precondition header to HEADERS if
+ an examination of COMMIT_CTX and RELPATH indicates that this is the
+ right thing to do.
+
+ Generally speaking, if the client provided a lock token for
+ RELPATH, it's the right thing to do. There is a notable instance
+ where this is not the case, however. If the file at RELPATH was
+ explicitly deleted in this commit already, then mod_dav removed its
+ lock token when it fielded the DELETE request, so we don't want to
+ set the lock precondition again. (See
+ http://subversion.tigris.org/issues/show_bug.cgi?id=3674 for details.)
+*/
+static svn_error_t *
+maybe_set_lock_token_header(serf_bucket_t *headers,
+ commit_context_t *commit_ctx,
+ const char *relpath,
+ apr_pool_t *pool)
+{
+ const char *token;
+
+ if (! (relpath && commit_ctx->lock_tokens))
+ return SVN_NO_ERROR;
+
+ if (! svn_hash_gets(commit_ctx->deleted_entries, relpath))
+ {
+ token = svn_hash_gets(commit_ctx->lock_tokens, relpath);
+ if (token)
+ {
+ const char *token_header;
+ const char *token_uri;
+ apr_uri_t uri = commit_ctx->session->session_url;
+
+ /* Supplying the optional URI affects apache response when
+ the lock is broken, see issue 4369. When present any URI
+ must be absolute (RFC 2518 9.4). */
+ uri.path = (char *)svn_path_url_add_component2(uri.path, relpath,
+ pool);
+ token_uri = apr_uri_unparse(pool, &uri, 0);
+
+ token_header = apr_pstrcat(pool, "<", token_uri, "> (<", token, ">)",
+ (char *)NULL);
+ serf_bucket_headers_set(headers, "If", token_header);
+ }
+ }
+
+ return SVN_NO_ERROR;
+}
+
static svn_error_t *
setup_proppatch_headers(serf_bucket_t *headers,
void *baton,
@@ -802,22 +841,8 @@ setup_proppatch_headers(serf_bucket_t *headers,
proppatch->base_revision));
}
- if (proppatch->relpath && proppatch->commit->lock_tokens)
- {
- const char *token;
-
- token = apr_hash_get(proppatch->commit->lock_tokens, proppatch->relpath,
- APR_HASH_KEY_STRING);
-
- if (token)
- {
- const char *token_header;
-
- token_header = apr_pstrcat(pool, "(<", token, ">)", (char *)NULL);
-
- serf_bucket_headers_set(headers, "If", token_header);
- }
- }
+ SVN_ERR(maybe_set_lock_token_header(headers, proppatch->commit,
+ proppatch->relpath, pool));
return SVN_NO_ERROR;
}
@@ -921,6 +946,7 @@ proppatch_resource(proppatch_context_t *proppatch,
struct proppatch_body_baton_t pbb;
handler = apr_pcalloc(pool, sizeof(*handler));
+ handler->handler_pool = pool;
handler->method = "PROPPATCH";
handler->path = proppatch->path;
handler->conn = commit->conn;
@@ -935,20 +961,19 @@ proppatch_resource(proppatch_context_t *proppatch,
handler->body_delegate_baton = &pbb;
handler->response_handler = svn_ra_serf__handle_multistatus_only;
- handler->response_baton = &proppatch->progress;
+ handler->response_baton = handler;
- svn_ra_serf__request_create(handler);
+ SVN_ERR(svn_ra_serf__context_run_one(handler, pool));
- /* If we don't wait for the response, our pool will be gone! */
- SVN_ERR(svn_ra_serf__context_run_wait(&proppatch->progress.done,
- commit->session, pool));
-
- if (proppatch->progress.status != 207 ||
- proppatch->progress.server_error.error)
+ 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, &proppatch->progress),
- _("At least one property change failed; repository is unchanged"));
+ return svn_error_create(
+ SVN_ERR_RA_DAV_PROPPATCH_FAILED,
+ return_response_err(handler),
+ _("At least one property change failed; repository"
+ " is unchanged"));
}
return SVN_NO_ERROR;
@@ -1020,22 +1045,8 @@ setup_put_headers(serf_bucket_t *headers,
ctx->result_checksum);
}
- if (ctx->commit->lock_tokens)
- {
- const char *token;
-
- token = apr_hash_get(ctx->commit->lock_tokens, ctx->relpath,
- APR_HASH_KEY_STRING);
-
- if (token)
- {
- const char *token_header;
-
- token_header = apr_pstrcat(pool, "(<", token, ">)", (char *)NULL);
-
- serf_bucket_headers_set(headers, "If", token_header);
- }
- }
+ SVN_ERR(maybe_set_lock_token_header(headers, ctx->commit,
+ ctx->relpath, pool));
return APR_SUCCESS;
}
@@ -1056,13 +1067,103 @@ setup_copy_file_headers(serf_bucket_t *headers,
serf_bucket_headers_set(headers, "Destination", absolute_uri);
- serf_bucket_headers_set(headers, "Depth", "0");
- serf_bucket_headers_set(headers, "Overwrite", "T");
+ serf_bucket_headers_setn(headers, "Depth", "0");
+ serf_bucket_headers_setn(headers, "Overwrite", "T");
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)
+ {
+ *added = FALSE;
+ 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, dir->relpath,
+ pool));
+}
+
+static svn_error_t *
setup_copy_dir_headers(serf_bucket_t *headers,
void *baton,
apr_pool_t *pool)
@@ -1081,24 +1182,20 @@ setup_copy_dir_headers(serf_bucket_t *headers,
else
{
uri.path = (char *)svn_path_url_add_component2(
- dir->parent_dir->checkout->resource_url,
+ dir->parent_dir->working_url,
dir->name, pool);
}
absolute_uri = apr_uri_unparse(pool, &uri, 0);
serf_bucket_headers_set(headers, "Destination", absolute_uri);
- serf_bucket_headers_set(headers, "Depth", "infinity");
- serf_bucket_headers_set(headers, "Overwrite", "T");
+ serf_bucket_headers_setn(headers, "Depth", "infinity");
+ serf_bucket_headers_setn(headers, "Overwrite", "T");
/* Implicitly checkout this dir now. */
- dir->checkout = apr_pcalloc(dir->pool, sizeof(*dir->checkout));
- dir->checkout->pool = dir->pool;
- dir->checkout->progress.pool = dir->pool;
- dir->checkout->activity_url = dir->commit->activity_url;
- dir->checkout->resource_url = apr_pstrdup(dir->checkout->pool, uri.path);
+ 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 *
@@ -1106,55 +1203,22 @@ setup_delete_headers(serf_bucket_t *headers,
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 = apr_hash_get(ctx->lock_token_hash, ctx->path,
- APR_HASH_KEY_STRING);
-
- if (ctx->lock_token)
- {
- const char *token_header;
+ apr_ltoa(pool, del->revision));
- token_header = apr_pstrcat(pool, "<", ctx->path, "> (<",
- ctx->lock_token, ">)", (char *)NULL);
+ SVN_ERR(setup_if_header_recursive(&added, headers, del->commit,
+ del->relpath, pool));
- serf_bucket_headers_set(headers, "If", token_header);
-
- if (ctx->keep_locks)
- serf_bucket_headers_set(headers, SVN_DAV_OPTIONS_HEADER,
- SVN_DAV_OPTION_KEEP_LOCKS);
- }
- }
+ if (added && del->commit->keep_locks)
+ serf_bucket_headers_setn(headers, SVN_DAV_OPTIONS_HEADER,
+ SVN_DAV_OPTION_KEEP_LOCKS);
return SVN_NO_ERROR;
}
-/* 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,
@@ -1182,7 +1246,26 @@ create_txn_post_body(serf_bucket_t **body_bkt,
serf_bucket_alloc_t *alloc,
apr_pool_t *pool)
{
- *body_bkt = SERF_BUCKET_SIMPLE_STRING("( create-txn )", alloc);
+ apr_hash_t *revprops = baton;
+ svn_skel_t *request_skel;
+ svn_stringbuf_t *skel_str;
+
+ request_skel = svn_skel__make_empty_list(pool);
+ if (revprops)
+ {
+ svn_skel_t *proplist_skel;
+
+ SVN_ERR(svn_skel__unparse_proplist(&proplist_skel, revprops, pool));
+ svn_skel__prepend(proplist_skel, request_skel);
+ svn_skel__prepend_str("create-txn-with-props", request_skel, pool);
+ skel_str = svn_skel__unparse(request_skel, pool);
+ *body_bkt = SERF_BUCKET_SIMPLE_STRING(skel_str->data, alloc);
+ }
+ else
+ {
+ *body_bkt = SERF_BUCKET_SIMPLE_STRING("( create-txn )", alloc);
+ }
+
return SVN_NO_ERROR;
}
@@ -1206,7 +1289,7 @@ setup_post_headers(serf_bucket_t *headers,
/* Handler baton for POST request. */
typedef struct post_response_ctx_t
{
- svn_ra_serf__simple_request_context_t *request_ctx;
+ svn_ra_serf__handler_t *handler;
commit_context_t *commit_ctx;
} post_response_ctx_t;
@@ -1251,14 +1334,15 @@ post_headers_iterator_callback(void *baton,
/* A custom serf_response_handler_t which is mostly a wrapper around
- svn_ra_serf__handle_status_only -- it just notices POST response
+ svn_ra_serf__expect_empty_body -- it just notices POST response
headers, too.
+
Implements svn_ra_serf__response_handler_t */
static svn_error_t *
post_response_handler(serf_request_t *request,
serf_bucket_t *response,
void *baton,
- apr_pool_t *pool)
+ apr_pool_t *scratch_pool)
{
post_response_ctx_t *prc = baton;
serf_bucket_t *hdrs = serf_bucket_response_get_headers(response);
@@ -1267,8 +1351,8 @@ post_response_handler(serf_request_t *request,
serf_bucket_headers_do(hdrs, post_headers_iterator_callback, prc);
/* Execute the 'real' response handler to XML-parse the repsonse body. */
- return svn_ra_serf__handle_status_only(request, response,
- prc->request_ctx, pool);
+ return svn_ra_serf__expect_empty_body(request, response,
+ prc->handler, scratch_pool);
}
@@ -1286,45 +1370,44 @@ open_root(void *edit_baton,
proppatch_context_t *proppatch_ctx;
dir_context_t *dir;
apr_hash_index_t *hi;
- const char *proppatch_target;
+ const char *proppatch_target = NULL;
if (SVN_RA_SERF__HAVE_HTTPV2_SUPPORT(ctx->session))
{
- svn_ra_serf__simple_request_context_t *post_ctx;
post_response_ctx_t *prc;
const char *rel_path;
+ svn_boolean_t post_with_revprops
+ = (NULL != svn_hash_gets(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->method = "POST";
handler->body_type = SVN_SKEL_MIME_TYPE;
handler->body_delegate = create_txn_post_body;
- handler->body_delegate_baton = NULL;
+ handler->body_delegate_baton =
+ post_with_revprops ? 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;
- post_ctx = apr_pcalloc(ctx->pool, sizeof(*post_ctx));
- post_ctx->pool = ctx->pool;
-
prc = apr_pcalloc(ctx->pool, sizeof(*prc));
- prc->request_ctx = post_ctx;
+ prc->handler = handler;
prc->commit_ctx = ctx;
handler->response_handler = post_response_handler;
handler->response_baton = prc;
- svn_ra_serf__request_create(handler);
+ SVN_ERR(svn_ra_serf__context_run_one(handler, ctx->pool));
- SVN_ERR(svn_ra_serf__context_run_wait(&post_ctx->done, ctx->session,
- ctx->pool));
-
- if (post_ctx->status != 201)
+ if (handler->sline.code != 201)
{
apr_status_t status = SVN_ERR_RA_DAV_REQUEST_FAILED;
- switch(post_ctx->status)
+
+ switch (handler->sline.code)
{
case 403:
status = SVN_ERR_RA_DAV_FORBIDDEN;
@@ -1337,7 +1420,7 @@ open_root(void *edit_baton,
return svn_error_createf(status, NULL,
_("%s of '%s': %d %s (%s://%s)"),
handler->method, handler->path,
- post_ctx->status, post_ctx->reason,
+ handler->sline.code, handler->sline.reason,
ctx->session->session_url.scheme,
ctx->session->session_url.hostinfo);
}
@@ -1366,28 +1449,32 @@ open_root(void *edit_baton,
dir->removed_props = apr_hash_make(dir->pool);
dir->url = apr_pstrdup(dir->pool, ctx->txn_root_url);
- proppatch_target = ctx->txn_url;
+ /* If we included our revprops in the POST, we need not
+ PROPPATCH them. */
+ proppatch_target = post_with_revprops ? NULL : ctx->txn_url;
}
else
{
- svn_ra_serf__options_context_t *opt_ctx;
- svn_ra_serf__simple_request_context_t *mkact_ctx;
- const char *activity_str;
+ const char *activity_str = ctx->session->activity_collection_url;
- SVN_ERR(svn_ra_serf__create_options_req(&opt_ctx, ctx->session,
- ctx->session->conns[0],
- ctx->session->session_url.path,
- ctx->pool));
-
- SVN_ERR(svn_ra_serf__context_run_wait(
- svn_ra_serf__get_options_done_ptr(opt_ctx),
- ctx->session, ctx->pool));
-
- activity_str = svn_ra_serf__options_get_activity_collection(opt_ctx);
if (!activity_str)
- return svn_error_create(SVN_ERR_RA_DAV_OPTIONS_REQ_FAILED, NULL,
- _("The OPTIONS response did not include the "
- "requested activity-collection-set value"));
+ SVN_ERR(svn_ra_serf__v1_get_activity_collection(&activity_str,
+ ctx->session->conns[0],
+ ctx->pool,
+ ctx->pool));
+
+ /* Cache the result. */
+ if (activity_str)
+ {
+ ctx->session->activity_collection_url =
+ apr_pstrdup(ctx->session->pool, activity_str);
+ }
+ else
+ {
+ return svn_error_create(SVN_ERR_RA_DAV_OPTIONS_REQ_FAILED, NULL,
+ _("The OPTIONS response did not include the "
+ "requested activity-collection-set value"));
+ }
ctx->activity_url =
svn_path_url_add_component2(activity_str, svn_uuid_generate(ctx->pool),
@@ -1395,26 +1482,22 @@ open_root(void *edit_baton,
/* Create our activity URL now on the server. */
handler = apr_pcalloc(ctx->pool, sizeof(*handler));
+ handler->handler_pool = ctx->pool;
handler->method = "MKACTIVITY";
handler->path = ctx->activity_url;
handler->conn = ctx->session->conns[0];
handler->session = ctx->session;
- mkact_ctx = apr_pcalloc(ctx->pool, sizeof(*mkact_ctx));
- mkact_ctx->pool = ctx->pool;
+ handler->response_handler = svn_ra_serf__expect_empty_body;
+ handler->response_baton = handler;
- handler->response_handler = svn_ra_serf__handle_status_only;
- handler->response_baton = mkact_ctx;
+ SVN_ERR(svn_ra_serf__context_run_one(handler, ctx->pool));
- svn_ra_serf__request_create(handler);
-
- SVN_ERR(svn_ra_serf__context_run_wait(&mkact_ctx->done, ctx->session,
- ctx->pool));
-
- if (mkact_ctx->status != 201)
+ if (handler->sline.code != 201)
{
apr_status_t status = SVN_ERR_RA_DAV_REQUEST_FAILED;
- switch(mkact_ctx->status)
+
+ switch (handler->sline.code)
{
case 403:
status = SVN_ERR_RA_DAV_FORBIDDEN;
@@ -1427,7 +1510,7 @@ open_root(void *edit_baton,
return svn_error_createf(status, NULL,
_("%s of '%s': %d %s (%s://%s)"),
handler->method, handler->path,
- mkact_ctx->status, mkact_ctx->reason,
+ handler->sline.code, handler->sline.reason,
ctx->session->session_url.scheme,
ctx->session->session_url.hostinfo);
}
@@ -1448,57 +1531,55 @@ open_root(void *edit_baton,
dir->removed_props = apr_hash_make(dir->pool);
SVN_ERR(get_version_url(&dir->url, dir->commit->session,
- dir->commit->conn, dir->relpath,
+ dir->relpath,
dir->base_revision, ctx->checked_in_url,
- dir->pool));
+ dir->pool, dir->pool /* scratch_pool */));
ctx->checked_in_url = dir->url;
/* Checkout our root dir */
- SVN_ERR(checkout_dir(dir));
+ SVN_ERR(checkout_dir(dir, dir->pool /* scratch_pool */));
- proppatch_target = ctx->baseline->resource_url;
+ proppatch_target = ctx->baseline_url;
}
-
- /* PROPPATCH our revprops and pass them along. */
- proppatch_ctx = apr_pcalloc(ctx->pool, sizeof(*proppatch_ctx));
- proppatch_ctx->pool = dir_pool;
- proppatch_ctx->progress.pool = dir_pool;
- proppatch_ctx->commit = ctx;
- 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;
- hi = apr_hash_next(hi))
+ /* Unless this is NULL -- which means we don't need to PROPPATCH the
+ transaction with our revprops -- then, you know, PROPPATCH the
+ transaction with our revprops. */
+ if (proppatch_target)
{
- const void *key;
- void *val;
- const char *name;
- svn_string_t *value;
- const char *ns;
-
- apr_hash_this(hi, &key, NULL, &val);
- name = key;
- value = val;
+ proppatch_ctx = apr_pcalloc(ctx->pool, sizeof(*proppatch_ctx));
+ proppatch_ctx->pool = dir_pool;
+ proppatch_ctx->commit = ctx;
+ 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;
- if (strncmp(name, SVN_PROP_PREFIX, sizeof(SVN_PROP_PREFIX) - 1) == 0)
- {
- ns = SVN_DAV_PROP_NS_SVN;
- name += sizeof(SVN_PROP_PREFIX) - 1;
- }
- else
+ for (hi = apr_hash_first(ctx->pool, ctx->revprop_table); hi;
+ hi = apr_hash_next(hi))
{
- ns = SVN_DAV_PROP_NS_CUSTOM;
+ const char *name = svn__apr_hash_index_key(hi);
+ svn_string_t *value = svn__apr_hash_index_val(hi);
+ const char *ns;
+
+ if (strncmp(name, SVN_PROP_PREFIX, sizeof(SVN_PROP_PREFIX) - 1) == 0)
+ {
+ ns = SVN_DAV_PROP_NS_SVN;
+ name += sizeof(SVN_PROP_PREFIX) - 1;
+ }
+ else
+ {
+ ns = SVN_DAV_PROP_NS_CUSTOM;
+ }
+
+ svn_ra_serf__set_prop(proppatch_ctx->changed_props,
+ proppatch_ctx->path,
+ ns, name, value, proppatch_ctx->pool);
}
- svn_ra_serf__set_prop(proppatch_ctx->changed_props, proppatch_ctx->path,
- ns, name, value, proppatch_ctx->pool);
+ SVN_ERR(proppatch_resource(proppatch_ctx, dir->commit, ctx->pool));
}
- SVN_ERR(proppatch_resource(proppatch_ctx, dir->commit, ctx->pool));
-
*root_baton = dir;
return SVN_NO_ERROR;
@@ -1514,7 +1595,6 @@ 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))
{
@@ -1524,8 +1604,8 @@ delete_entry(const char *path,
else
{
/* Ensure our directory has been checked out */
- SVN_ERR(checkout_dir(dir));
- delete_target = svn_path_url_add_component2(dir->checkout->resource_url,
+ SVN_ERR(checkout_dir(dir, pool /* scratch_pool */));
+ delete_target = svn_path_url_add_component2(dir->working_url,
svn_relpath_basename(path,
NULL),
pool);
@@ -1533,18 +1613,17 @@ delete_entry(const char *path,
/* DELETE our entry */
delete_ctx = apr_pcalloc(pool, sizeof(*delete_ctx));
- delete_ctx->progress.pool = pool;
- 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 = dir->commit;
handler = apr_pcalloc(pool, sizeof(*handler));
+ handler->handler_pool = pool;
handler->session = dir->commit->session;
handler->conn = dir->commit->conn;
- handler->response_handler = svn_ra_serf__handle_status_only;
- handler->response_baton = &delete_ctx->progress;
+ handler->response_handler = svn_ra_serf__expect_empty_body;
+ handler->response_baton = handler;
handler->header_delegate = setup_delete_headers;
handler->header_delegate_baton = delete_ctx;
@@ -1552,48 +1631,16 @@ delete_entry(const char *path,
handler->method = "DELETE";
handler->path = delete_target;
- svn_ra_serf__request_create(handler);
-
- err = svn_ra_serf__context_run_wait(&delete_ctx->progress.done,
- dir->commit->session, 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_ra_serf__request_create(handler);
-
- delete_ctx->progress.done = 0;
-
- SVN_ERR(svn_ra_serf__context_run_wait(&delete_ctx->progress.done,
- dir->commit->session, pool));
- }
- else if (err)
- {
- return err;
- }
+ SVN_ERR(svn_ra_serf__context_run_one(handler, pool));
/* 204 No Content: item successfully deleted */
- if (delete_ctx->progress.status != 204)
+ if (handler->sline.code != 204)
{
- return return_response_err(handler, &delete_ctx->progress);
+ return svn_error_trace(return_response_err(handler));
}
- apr_hash_set(dir->commit->deleted_entries,
- apr_pstrdup(dir->commit->pool, path), APR_HASH_KEY_STRING,
- (void*)1);
+ svn_hash_sets(dir->commit->deleted_entries,
+ apr_pstrdup(dir->commit->pool, path), (void *)1);
return SVN_NO_ERROR;
}
@@ -1609,7 +1656,6 @@ add_directory(const char *path,
dir_context_t *parent = parent_baton;
dir_context_t *dir;
svn_ra_serf__handler_t *handler;
- svn_ra_serf__simple_request_context_t *add_dir_ctx;
apr_status_t status;
const char *mkcol_target;
@@ -1621,7 +1667,7 @@ add_directory(const char *path,
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);
@@ -1636,33 +1682,34 @@ add_directory(const char *path,
else
{
/* Ensure our parent is checked out. */
- SVN_ERR(checkout_dir(parent));
+ SVN_ERR(checkout_dir(parent, dir->pool /* scratch_pool */));
dir->url = svn_path_url_add_component2(parent->commit->checked_in_url,
dir->name, dir->pool);
mkcol_target = svn_path_url_add_component2(
- parent->checkout->resource_url,
+ 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;
- add_dir_ctx = apr_pcalloc(dir->pool, sizeof(*add_dir_ctx));
- add_dir_ctx->pool = dir->pool;
-
- handler->response_handler = svn_ra_serf__handle_status_only;
- handler->response_baton = add_dir_ctx;
+ handler->response_handler = svn_ra_serf__expect_empty_body;
+ handler->response_baton = handler;
if (!dir->copy_path)
{
handler->method = "MKCOL";
handler->path = mkcol_target;
+
+ handler->header_delegate = setup_add_dir_common_headers;
+ handler->header_delegate_baton = dir;
}
else
{
apr_uri_t uri;
- const char *rel_copy_path, *basecoll_url, *req_url;
+ const char *req_url;
status = apr_uri_parse(dir->pool, dir->copy_path, &uri);
if (status)
@@ -1672,13 +1719,12 @@ add_directory(const char *path,
dir->copy_path);
}
- SVN_ERR(svn_ra_serf__get_baseline_info(&basecoll_url, &rel_copy_path,
- dir->commit->session,
- dir->commit->conn,
- uri.path, dir->copy_revision,
- NULL, dir_pool));
- req_url = svn_path_url_add_component2(basecoll_url, rel_copy_path,
- dir->pool);
+ /* ### 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,
+ NULL /* conn */,
+ uri.path, dir->copy_revision,
+ dir_pool, dir_pool));
handler->method = "COPY";
handler->path = req_url;
@@ -1687,29 +1733,24 @@ add_directory(const char *path,
handler->header_delegate_baton = dir;
}
- svn_ra_serf__request_create(handler);
-
- SVN_ERR(svn_ra_serf__context_run_wait(&add_dir_ctx->done,
- dir->commit->session, dir->pool));
+ SVN_ERR(svn_ra_serf__context_run_one(handler, dir->pool));
- switch (add_dir_ctx->status)
+ switch (handler->sline.code)
{
case 201: /* Created: item was successfully copied */
case 204: /* No Content: item successfully replaced an existing target */
break;
case 403:
- SVN_ERR(add_dir_ctx->server_error.error);
return svn_error_createf(SVN_ERR_RA_DAV_FORBIDDEN, NULL,
_("Access to '%s' forbidden"),
handler->path);
default:
- SVN_ERR(add_dir_ctx->server_error.error);
return svn_error_createf(SVN_ERR_RA_DAV_REQUEST_FAILED, NULL,
_("Adding directory failed: %s on %s "
"(%d %s)"),
handler->method, handler->path,
- add_dir_ctx->status, add_dir_ctx->reason);
+ handler->sline.code, handler->sline.reason);
}
*child_baton = dir;
@@ -1749,9 +1790,10 @@ open_directory(const char *path,
else
{
SVN_ERR(get_version_url(&dir->url,
- dir->commit->session, dir->commit->conn,
+ dir->commit->session,
dir->relpath, dir->base_revision,
- dir->commit->checked_in_url, dir->pool));
+ dir->commit->checked_in_url,
+ dir->pool, dir->pool /* scratch_pool */));
}
*child_baton = dir;
@@ -1776,9 +1818,9 @@ change_dir_prop(void *dir_baton,
else
{
/* Ensure we have a checked out dir. */
- SVN_ERR(checkout_dir(dir));
+ SVN_ERR(checkout_dir(dir, pool /* scratch_pool */));
- proppatch_target = dir->checkout->resource_url;
+ proppatch_target = dir->working_url;
}
name = apr_pstrdup(dir->pool, name);
@@ -1800,7 +1842,7 @@ change_dir_prop(void *dir_baton,
}
else
{
- value = svn_string_create("", dir->pool);
+ value = svn_string_create_empty(dir->pool);
svn_ra_serf__set_prop(dir->removed_props, proppatch_target,
ns, name, value, dir->pool);
}
@@ -1826,7 +1868,6 @@ close_directory(void *dir_baton,
proppatch_ctx = apr_pcalloc(pool, sizeof(*proppatch_ctx));
proppatch_ctx->pool = pool;
- proppatch_ctx->progress.pool = pool;
proppatch_ctx->commit = dir->commit;
proppatch_ctx->relpath = dir->relpath;
proppatch_ctx->changed_props = dir->changed_props;
@@ -1839,7 +1880,7 @@ close_directory(void *dir_baton,
}
else
{
- proppatch_ctx->path = dir->checkout->resource_url;
+ proppatch_ctx->path = dir->working_url;
}
SVN_ERR(proppatch_resource(proppatch_ctx, dir->commit, dir->pool));
@@ -1871,7 +1912,7 @@ add_file(const char *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);
@@ -1887,17 +1928,16 @@ add_file(const char *path,
else
{
/* Ensure our parent directory has been checked out */
- SVN_ERR(checkout_dir(dir));
+ SVN_ERR(checkout_dir(dir, new_file->pool /* scratch_pool */));
new_file->url =
- svn_path_url_add_component2(dir->checkout->resource_url,
+ svn_path_url_add_component2(dir->working_url,
new_file->name, new_file->pool);
}
while (deleted_parent && deleted_parent[0] != '\0')
{
- if (apr_hash_get(dir->commit->deleted_entries,
- deleted_parent, APR_HASH_KEY_STRING))
+ if (svn_hash_gets(dir->commit->deleted_entries, deleted_parent))
{
break;
}
@@ -1907,30 +1947,35 @@ add_file(const char *path,
if (! ((dir->added && !dir->copy_path) ||
(deleted_parent && deleted_parent[0] != '\0')))
{
- svn_ra_serf__simple_request_context_t *head_ctx;
svn_ra_serf__handler_t *handler;
- head_ctx = apr_pcalloc(new_file->pool, sizeof(*head_ctx));
- head_ctx->pool = new_file->pool;
-
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->method = "HEAD";
handler->path = svn_path_url_add_component2(
dir->commit->session->session_url.path,
path, new_file->pool);
- handler->response_handler = svn_ra_serf__handle_status_only;
- handler->response_baton = head_ctx;
- svn_ra_serf__request_create(handler);
+ handler->response_handler = svn_ra_serf__expect_empty_body;
+ handler->response_baton = handler;
- SVN_ERR(svn_ra_serf__context_run_wait(&head_ctx->done,
- new_file->commit->session,
- new_file->pool));
+ SVN_ERR(svn_ra_serf__context_run_one(handler, new_file->pool));
- if (head_ctx->status != 404)
+ if (handler->sline.code != 404)
{
- return svn_error_createf(SVN_ERR_RA_DAV_ALREADY_EXISTS, NULL,
+ if (handler->sline.code != 200)
+ {
+ svn_error_t *err;
+
+ err = svn_ra_serf__error_on_status(handler->sline,
+ handler->path,
+ handler->location);
+
+ SVN_ERR(err);
+ }
+
+ return svn_error_createf(SVN_ERR_FS_ALREADY_EXISTS, NULL,
_("File '%s' already exists"), path);
}
}
@@ -1972,9 +2017,9 @@ open_file(const char *path,
else
{
/* CHECKOUT the file into our activity. */
- SVN_ERR(checkout_file(new_file));
+ SVN_ERR(checkout_file(new_file, new_file->pool /* scratch_pool */));
- new_file->url = new_file->checkout->resource_url;
+ new_file->url = new_file->working_url;
}
*file_baton = new_file;
@@ -2011,7 +2056,8 @@ apply_textdelta(void *file_baton,
ctx->stream = svn_stream_create(ctx, pool);
svn_stream_set_write(ctx->stream, svndiff_stream_write);
- svn_txdelta_to_svndiff2(handler, handler_baton, ctx->stream, 0, pool);
+ svn_txdelta_to_svndiff3(handler, handler_baton, ctx->stream, 0,
+ SVN_DELTA_COMPRESSION_LEVEL_DEFAULT, pool);
if (base_checksum)
ctx->base_checksum = apr_pstrdup(ctx->pool, base_checksum);
@@ -2048,7 +2094,7 @@ change_file_prop(void *file_baton,
}
else
{
- value = svn_string_create("", file->pool);
+ value = svn_string_create_empty(file->pool);
svn_ra_serf__set_prop(file->removed_props, file->url,
ns, name, value, file->pool);
@@ -2060,7 +2106,7 @@ change_file_prop(void *file_baton,
static svn_error_t *
close_file(void *file_baton,
const char *text_checksum,
- apr_pool_t *pool)
+ apr_pool_t *scratch_pool)
{
file_context_t *ctx = file_baton;
svn_boolean_t put_empty_file = FALSE;
@@ -2071,11 +2117,10 @@ close_file(void *file_baton,
if (ctx->copy_path)
{
svn_ra_serf__handler_t *handler;
- svn_ra_serf__simple_request_context_t *copy_ctx;
apr_uri_t uri;
- const char *rel_copy_path, *basecoll_url, *req_url;
+ const char *req_url;
- status = apr_uri_parse(pool, ctx->copy_path, &uri);
+ status = apr_uri_parse(scratch_pool, ctx->copy_path, &uri);
if (status)
{
return svn_error_createf(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL,
@@ -2083,36 +2128,31 @@ close_file(void *file_baton,
ctx->copy_path);
}
- SVN_ERR(svn_ra_serf__get_baseline_info(&basecoll_url, &rel_copy_path,
- ctx->commit->session,
- ctx->commit->conn,
- uri.path, ctx->copy_revision,
- NULL, pool));
- req_url = svn_path_url_add_component2(basecoll_url, rel_copy_path, pool);
+ /* ### 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(pool, sizeof(*handler));
+ 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;
- copy_ctx = apr_pcalloc(pool, sizeof(*copy_ctx));
- copy_ctx->pool = pool;
-
- handler->response_handler = svn_ra_serf__handle_status_only;
- handler->response_baton = copy_ctx;
+ 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_ra_serf__request_create(handler);
-
- SVN_ERR(svn_ra_serf__context_run_wait(&copy_ctx->done,
- ctx->commit->session, pool));
+ SVN_ERR(svn_ra_serf__context_run_one(handler, scratch_pool));
- if (copy_ctx->status != 201 && copy_ctx->status != 204)
+ if (handler->sline.code != 201 && handler->sline.code != 204)
{
- return return_response_err(handler, copy_ctx);
+ return svn_error_trace(return_response_err(handler));
}
}
@@ -2126,19 +2166,16 @@ close_file(void *file_baton,
if (ctx->stream || put_empty_file)
{
svn_ra_serf__handler_t *handler;
- svn_ra_serf__simple_request_context_t *put_ctx;
- handler = apr_pcalloc(pool, sizeof(*handler));
+ 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;
- put_ctx = apr_pcalloc(pool, sizeof(*put_ctx));
- put_ctx->pool = pool;
-
- handler->response_handler = svn_ra_serf__handle_status_only;
- handler->response_baton = put_ctx;
+ handler->response_handler = svn_ra_serf__expect_empty_body;
+ handler->response_baton = handler;
if (put_empty_file)
{
@@ -2150,25 +2187,22 @@ close_file(void *file_baton,
{
handler->body_delegate = create_put_body;
handler->body_delegate_baton = ctx;
- handler->body_type = "application/vnd.svn-svndiff";
+ handler->body_type = SVN_SVNDIFF_MIME_TYPE;
}
handler->header_delegate = setup_put_headers;
handler->header_delegate_baton = ctx;
- svn_ra_serf__request_create(handler);
+ SVN_ERR(svn_ra_serf__context_run_one(handler, scratch_pool));
- SVN_ERR(svn_ra_serf__context_run_wait(&put_ctx->done,
- ctx->commit->session, pool));
-
- if (put_ctx->status != 204 && put_ctx->status != 201)
+ if (handler->sline.code != 204 && handler->sline.code != 201)
{
- return return_response_err(handler, put_ctx);
+ return svn_error_trace(return_response_err(handler));
}
}
if (ctx->svndiff)
- SVN_ERR(svn_io_file_close(ctx->svndiff, pool));
+ SVN_ERR(svn_io_file_close(ctx->svndiff, scratch_pool));
/* If we had any prop changes, push them via PROPPATCH. */
if (apr_hash_count(ctx->changed_props) ||
@@ -2178,7 +2212,6 @@ close_file(void *file_baton,
proppatch = apr_pcalloc(ctx->pool, sizeof(*proppatch));
proppatch->pool = ctx->pool;
- proppatch->progress.pool = pool;
proppatch->relpath = ctx->relpath;
proppatch->path = ctx->url;
proppatch->commit = ctx->commit;
@@ -2197,61 +2230,61 @@ close_edit(void *edit_baton,
apr_pool_t *pool)
{
commit_context_t *ctx = edit_baton;
- svn_ra_serf__merge_context_t *merge_ctx;
- svn_ra_serf__simple_request_context_t *delete_ctx;
- svn_ra_serf__handler_t *handler;
- svn_boolean_t *merge_done;
const char *merge_target =
ctx->activity_url ? ctx->activity_url : ctx->txn_url;
+ const svn_commit_info_t *commit_info;
+ int response_code;
+ svn_error_t *err = NULL;
/* MERGE our activity */
- SVN_ERR(svn_ra_serf__merge_create_req(&merge_ctx, ctx->session,
- ctx->session->conns[0],
- merge_target,
- ctx->lock_tokens,
- ctx->keep_locks,
- pool));
-
- merge_done = svn_ra_serf__merge_get_done_ptr(merge_ctx);
-
- SVN_ERR(svn_ra_serf__context_run_wait(merge_done, ctx->session, pool));
+ SVN_ERR(svn_ra_serf__run_merge(&commit_info, &response_code,
+ ctx->session,
+ ctx->session->conns[0],
+ merge_target,
+ ctx->lock_tokens,
+ ctx->keep_locks,
+ pool, pool));
- if (svn_ra_serf__merge_get_status(merge_ctx) != 200)
+ if (response_code != 200)
{
return svn_error_createf(SVN_ERR_RA_DAV_REQUEST_FAILED, NULL,
_("MERGE request failed: returned %d "
"(during commit)"),
- svn_ra_serf__merge_get_status(merge_ctx));
+ response_code);
}
+ ctx->txn_url = NULL; /* If HTTPv2, the txn is now done */
+
/* Inform the WC that we did a commit. */
if (ctx->callback)
- SVN_ERR(ctx->callback(svn_ra_serf__merge_get_commit_info(merge_ctx),
- ctx->callback_baton, pool));
+ err = ctx->callback(commit_info, ctx->callback_baton, pool);
/* If we're using activities, DELETE our completed activity. */
if (ctx->activity_url)
{
+ svn_ra_serf__handler_t *handler;
+
handler = apr_pcalloc(pool, sizeof(*handler));
+ handler->handler_pool = pool;
handler->method = "DELETE";
handler->path = ctx->activity_url;
handler->conn = ctx->conn;
handler->session = ctx->session;
- delete_ctx = apr_pcalloc(pool, sizeof(*delete_ctx));
- delete_ctx->pool = pool;
+ handler->response_handler = svn_ra_serf__expect_empty_body;
+ handler->response_baton = handler;
- handler->response_handler = svn_ra_serf__handle_status_only;
- handler->response_baton = delete_ctx;
+ ctx->activity_url = NULL; /* Don't try again in abort_edit() on fail */
- svn_ra_serf__request_create(handler);
+ SVN_ERR(svn_error_compose_create(
+ err,
+ svn_ra_serf__context_run_one(handler, pool)));
- SVN_ERR(svn_ra_serf__context_run_wait(&delete_ctx->done, ctx->session,
- pool));
-
- SVN_ERR_ASSERT(delete_ctx->status == 204);
+ SVN_ERR_ASSERT(handler->sline.code == 204);
}
+ SVN_ERR(err);
+
return SVN_NO_ERROR;
}
@@ -2261,7 +2294,6 @@ abort_edit(void *edit_baton,
{
commit_context_t *ctx = edit_baton;
svn_ra_serf__handler_t *handler;
- svn_ra_serf__simple_request_context_t *delete_ctx;
/* If an activity or transaction wasn't even created, don't bother
trying to delete it. */
@@ -2274,35 +2306,32 @@ abort_edit(void *edit_baton,
/* DELETE our aborted activity */
handler = apr_pcalloc(pool, sizeof(*handler));
+ handler->handler_pool = pool;
handler->method = "DELETE";
handler->conn = ctx->session->conns[0];
handler->session = ctx->session;
- delete_ctx = apr_pcalloc(pool, sizeof(*delete_ctx));
- delete_ctx->pool = pool;
-
- handler->response_handler = svn_ra_serf__handle_status_only;
- handler->response_baton = delete_ctx;
+ handler->response_handler = svn_ra_serf__expect_empty_body;
+ handler->response_baton = handler;
if (USING_HTTPV2_COMMIT_SUPPORT(ctx)) /* HTTP v2 */
handler->path = ctx->txn_url;
else
handler->path = ctx->activity_url;
- svn_ra_serf__request_create(handler);
-
- SVN_ERR(svn_ra_serf__context_run_wait(&delete_ctx->done, ctx->session,
- pool));
+ SVN_ERR(svn_ra_serf__context_run_one(handler, pool));
/* 204 if deleted,
403 if DELETE was forbidden (indicates MKACTIVITY was forbidden too),
404 if the activity wasn't found. */
- if (delete_ctx->status != 204 &&
- delete_ctx->status != 403 &&
- delete_ctx->status != 404
+ if (handler->sline.code != 204
+ && handler->sline.code != 403
+ && handler->sline.code != 404
)
{
- SVN_ERR_MALFUNCTION();
+ return svn_error_createf(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL,
+ _("DELETE returned unexpected status: %d"),
+ handler->sline.code);
}
return SVN_NO_ERROR;
@@ -2322,7 +2351,9 @@ svn_ra_serf__get_commit_editor(svn_ra_session_t *ra_session,
svn_ra_serf__session_t *session = ra_session->priv;
svn_delta_editor_t *editor;
commit_context_t *ctx;
- apr_hash_index_t *hi;
+ const char *repos_root;
+ const char *base_relpath;
+ svn_boolean_t supports_ephemeral_props;
ctx = apr_pcalloc(pool, sizeof(*ctx));
@@ -2331,22 +2362,28 @@ svn_ra_serf__get_commit_editor(svn_ra_session_t *ra_session,
ctx->session = session;
ctx->conn = session->conns[0];
- ctx->revprop_table = apr_hash_make(pool);
- for (hi = apr_hash_first(pool, revprop_table); hi; hi = apr_hash_next(hi))
- {
- const void *key;
- apr_ssize_t klen;
- void *val;
+ ctx->revprop_table = svn_prop_hash_dup(revprop_table, pool);
- apr_hash_this(hi, &key, &klen, &val);
- apr_hash_set(ctx->revprop_table, apr_pstrdup(pool, key), klen,
- svn_string_dup(val, pool));
+ /* If the server supports ephemeral properties, add some carrying
+ interesting version information. */
+ SVN_ERR(svn_ra_serf__has_capability(ra_session, &supports_ephemeral_props,
+ SVN_RA_CAPABILITY_EPHEMERAL_TXNPROPS,
+ pool));
+ if (supports_ephemeral_props)
+ {
+ svn_hash_sets(ctx->revprop_table,
+ apr_pstrdup(pool, SVN_PROP_TXN_CLIENT_COMPAT_VERSION),
+ svn_string_create(SVN_VER_NUMBER, pool));
+ svn_hash_sets(ctx->revprop_table,
+ apr_pstrdup(pool, SVN_PROP_TXN_USER_AGENT),
+ svn_string_create(session->useragent, pool));
}
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);
@@ -2369,6 +2406,14 @@ svn_ra_serf__get_commit_editor(svn_ra_session_t *ra_session,
*ret_editor = editor;
*edit_baton = ctx;
+ SVN_ERR(svn_ra_serf__get_repos_root(ra_session, &repos_root, pool));
+ base_relpath = svn_uri_skip_ancestor(repos_root, session->session_url_str,
+ pool);
+
+ SVN_ERR(svn_editor__insert_shims(ret_editor, edit_baton, *ret_editor,
+ *edit_baton, repos_root, base_relpath,
+ session->shim_callbacks, pool, pool));
+
return SVN_NO_ERROR;
}
@@ -2383,8 +2428,8 @@ svn_ra_serf__change_rev_prop(svn_ra_session_t *ra_session,
svn_ra_serf__session_t *session = ra_session->priv;
proppatch_context_t *proppatch_ctx;
commit_context_t *commit;
- const char *vcc_url, *proppatch_target, *ns;
- apr_hash_t *props;
+ const char *proppatch_target;
+ const char *ns;
svn_error_t *err;
if (old_value_p)
@@ -2411,21 +2456,15 @@ svn_ra_serf__change_rev_prop(svn_ra_session_t *ra_session,
}
else
{
- svn_ra_serf__propfind_context_t *propfind_ctx;
+ const char *vcc_url;
SVN_ERR(svn_ra_serf__discover_vcc(&vcc_url, commit->session,
commit->conn, pool));
- props = apr_hash_make(pool);
-
- /* ### switch to svn_ra_serf__retrieve_props */
- SVN_ERR(svn_ra_serf__deliver_props(&propfind_ctx, props, commit->session,
- commit->conn, vcc_url, rev, "0",
- checked_in_props, NULL, pool));
- SVN_ERR(svn_ra_serf__wait_for_props(propfind_ctx, commit->session, pool));
-
- proppatch_target = svn_ra_serf__get_ver_prop(props, vcc_url, rev,
- "DAV:", "href");
+ SVN_ERR(svn_ra_serf__fetch_dav_prop(&proppatch_target,
+ commit->conn, vcc_url, rev,
+ "href",
+ pool, pool));
}
if (strncmp(name, SVN_PROP_PREFIX, sizeof(SVN_PROP_PREFIX) - 1) == 0)
@@ -2441,7 +2480,6 @@ svn_ra_serf__change_rev_prop(svn_ra_session_t *ra_session,
/* PROPPATCH our log message and pass it along. */
proppatch_ctx = apr_pcalloc(pool, sizeof(*proppatch_ctx));
proppatch_ctx->pool = pool;
- proppatch_ctx->progress.pool = pool;
proppatch_ctx->commit = commit;
proppatch_ctx->path = proppatch_target;
proppatch_ctx->changed_props = apr_hash_make(proppatch_ctx->pool);
@@ -2461,7 +2499,7 @@ svn_ra_serf__change_rev_prop(svn_ra_session_t *ra_session,
}
else if (old_value_p)
{
- svn_string_t *dummy_value = svn_string_create("", proppatch_ctx->pool);
+ svn_string_t *dummy_value = svn_string_create_empty(proppatch_ctx->pool);
svn_ra_serf__set_prop(proppatch_ctx->previous_removed_props,
proppatch_ctx->path,
@@ -2475,7 +2513,7 @@ svn_ra_serf__change_rev_prop(svn_ra_session_t *ra_session,
}
else
{
- value = svn_string_create("", proppatch_ctx->pool);
+ value = svn_string_create_empty(proppatch_ctx->pool);
svn_ra_serf__set_prop(proppatch_ctx->removed_props, proppatch_ctx->path,
ns, name, value, proppatch_ctx->pool);