Alien-SVN
view release on metacpan or search on metacpan
src/subversion/subversion/libsvn_ra_serf/commit.c view on Meta::CPAN
/* Changed and removed properties. */
apr_hash_t *changed_props;
apr_hash_t *removed_props;
/* URL to PUT the file at. */
const char *url;
} 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,
void *baton,
serf_bucket_alloc_t *alloc,
apr_pool_t *pool)
{
const char *activity_url = baton;
serf_bucket_t *body_bkt;
body_bkt = serf_bucket_aggregate_create(alloc);
svn_ra_serf__add_xml_header_buckets(body_bkt, alloc);
svn_ra_serf__add_open_tag_buckets(body_bkt, alloc, "D:checkout",
"xmlns:D", "DAV:",
NULL);
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,
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");
svn_ra_serf__add_tag_buckets(body_bkt, "D:apply-to-version", NULL, alloc);
svn_ra_serf__add_close_tag_buckets(body_bkt, alloc, "D:checkout");
*bkt = body_bkt;
return SVN_NO_ERROR;
}
/* 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 *
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_ra_serf__handler_t handler = { 0 };
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.response_handler = svn_ra_serf__expect_empty_body;
handler.response_baton = &handler;
handler.method = "CHECKOUT";
handler.path = node_url;
SVN_ERR(svn_ra_serf__context_run_one(&handler, scratch_pool));
src/subversion/subversion/libsvn_ra_serf/commit.c view on Meta::CPAN
_("Path '%s' not present"),
session->session_url.path);
root_checkout = svn_urlpath__canonicalize(root_checkout, scratch_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,
apr_pool_t *scratch_pool)
{
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.
*/
while (parent_dir)
{
if (parent_dir->added)
{
/* Implicitly checkout this file now. */
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;
}
SVN_ERR(get_version_url(&checkout_url,
file->commit->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;
}
/* Helper function for proppatch_walker() below. */
static svn_error_t *
get_encoding_and_cdata(const char **encoding_p,
const svn_string_t **encoded_value_p,
serf_bucket_alloc_t *alloc,
const svn_string_t *value,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
if (value == NULL)
{
*encoding_p = NULL;
*encoded_value_p = NULL;
return SVN_NO_ERROR;
}
/* If a property is XML-safe, XML-encode it. Else, base64-encode
it. */
if (svn_xml_is_xml_safe(value->data, value->len))
{
svn_stringbuf_t *xml_esc = NULL;
svn_xml_escape_cdata_string(&xml_esc, value, scratch_pool);
*encoding_p = NULL;
*encoded_value_p = svn_string_create_from_buf(xml_esc, result_pool);
}
else
{
*encoding_p = "base64";
*encoded_value_p = svn_base64_encode_string2(value, TRUE, result_pool);
}
return SVN_NO_ERROR;
}
typedef struct walker_baton_t {
serf_bucket_t *body_bkt;
apr_pool_t *body_pool;
apr_hash_t *previous_changed_props;
apr_hash_t *previous_removed_props;
const char *path;
/* Hack, since change_rev_prop(old_value_p != NULL, value = NULL) uses D:set
rather than D:remove... (see notes/http-and-webdav/webdav-protocol) */
enum {
filter_all_props,
filter_props_with_old_value,
filter_props_without_old_value
} filter;
/* Is the property being deleted? */
svn_boolean_t deleting;
} walker_baton_t;
/* If we have (recorded in WB) the old value of the property named NS:NAME,
* then set *HAVE_OLD_VAL to TRUE and set *OLD_VAL_P to that old value
* (which may be NULL); else set *HAVE_OLD_VAL to FALSE. */
static svn_error_t *
derive_old_val(svn_boolean_t *have_old_val,
const svn_string_t **old_val_p,
walker_baton_t *wb,
const char *ns,
const char *name)
{
*have_old_val = FALSE;
if (wb->previous_changed_props)
{
const svn_string_t *val;
val = svn_ra_serf__get_prop_string(wb->previous_changed_props,
wb->path, ns, name);
if (val)
{
*have_old_val = TRUE;
*old_val_p = val;
}
}
if (wb->previous_removed_props)
{
const svn_string_t *val;
val = svn_ra_serf__get_prop_string(wb->previous_removed_props,
wb->path, ns, name);
if (val)
{
*have_old_val = TRUE;
*old_val_p = NULL;
}
}
return SVN_NO_ERROR;
}
static svn_error_t *
proppatch_walker(void *baton,
const char *ns,
const char *name,
const svn_string_t *val,
apr_pool_t *scratch_pool)
{
walker_baton_t *wb = baton;
serf_bucket_t *body_bkt = wb->body_bkt;
serf_bucket_t *cdata_bkt;
serf_bucket_alloc_t *alloc;
const char *encoding;
svn_boolean_t have_old_val;
const svn_string_t *old_val;
const svn_string_t *encoded_value;
const char *prop_name;
SVN_ERR(derive_old_val(&have_old_val, &old_val, wb, ns, name));
/* Jump through hoops to work with D:remove and its val = (""-for-NULL)
* representation. */
if (wb->filter != filter_all_props)
{
if (wb->filter == filter_props_with_old_value && ! have_old_val)
return SVN_NO_ERROR;
if (wb->filter == filter_props_without_old_value && have_old_val)
return SVN_NO_ERROR;
}
if (wb->deleting)
val = NULL;
alloc = body_bkt->allocator;
SVN_ERR(get_encoding_and_cdata(&encoding, &encoded_value, alloc, val,
wb->body_pool, scratch_pool));
if (encoded_value)
{
cdata_bkt = SERF_BUCKET_SIMPLE_STRING_LEN(encoded_value->data,
encoded_value->len,
alloc);
}
else
{
cdata_bkt = NULL;
}
/* Use the namespace prefix instead of adding the xmlns attribute to support
property names containing ':' */
if (strcmp(ns, SVN_DAV_PROP_NS_SVN) == 0)
prop_name = apr_pstrcat(wb->body_pool, "S:", name, (char *)NULL);
else if (strcmp(ns, SVN_DAV_PROP_NS_CUSTOM) == 0)
prop_name = apr_pstrcat(wb->body_pool, "C:", name, (char *)NULL);
if (cdata_bkt)
svn_ra_serf__add_open_tag_buckets(body_bkt, alloc, prop_name,
"V:encoding", encoding,
NULL);
else
svn_ra_serf__add_open_tag_buckets(body_bkt, alloc, prop_name,
"V:" SVN_DAV__OLD_VALUE__ABSENT, "1",
NULL);
if (have_old_val)
{
const char *encoding2;
const svn_string_t *encoded_value2;
serf_bucket_t *cdata_bkt2;
SVN_ERR(get_encoding_and_cdata(&encoding2, &encoded_value2,
alloc, old_val,
wb->body_pool, scratch_pool));
if (encoded_value2)
{
cdata_bkt2 = SERF_BUCKET_SIMPLE_STRING_LEN(encoded_value2->data,
encoded_value2->len,
alloc);
}
else
{
cdata_bkt2 = NULL;
}
if (cdata_bkt2)
svn_ra_serf__add_open_tag_buckets(body_bkt, alloc,
"V:" SVN_DAV__OLD_VALUE,
"V:encoding", encoding2,
NULL);
else
svn_ra_serf__add_open_tag_buckets(body_bkt, alloc,
"V:" SVN_DAV__OLD_VALUE,
"V:" SVN_DAV__OLD_VALUE__ABSENT, "1",
NULL);
if (cdata_bkt2)
serf_bucket_aggregate_append(body_bkt, cdata_bkt2);
svn_ra_serf__add_close_tag_buckets(body_bkt, alloc,
"V:" SVN_DAV__OLD_VALUE);
}
if (cdata_bkt)
serf_bucket_aggregate_append(body_bkt, cdata_bkt);
svn_ra_serf__add_close_tag_buckets(body_bkt, alloc, prop_name);
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,
apr_pool_t *pool)
{
proppatch_context_t *proppatch = baton;
( run in 0.514 second using v1.01-cache-2.11-cpan-62beec7d96d )