You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by as...@apache.org on 2012/11/24 21:29:48 UTC
svn commit: r1413258 [11/33] - in /subversion/branches/compressed-pristines:
./ build/ build/ac-macros/ build/generator/ build/generator/templates/
contrib/client-side/emacs/ contrib/server-side/fsfsfixer/ notes/
notes/directory-index/ subversion/ subv...
Modified: subversion/branches/compressed-pristines/subversion/libsvn_ra_local/split_url.c
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/libsvn_ra_local/split_url.c?rev=1413258&r1=1413257&r2=1413258&view=diff
==============================================================================
--- subversion/branches/compressed-pristines/subversion/libsvn_ra_local/split_url.c (original)
+++ subversion/branches/compressed-pristines/subversion/libsvn_ra_local/split_url.c Sat Nov 24 20:29:11 2012
@@ -74,5 +74,8 @@ svn_ra_local__split_URL(svn_repos_t **re
- svn_path_component_count(repos_root_dirent));
*repos_url = urlbuf->data;
+ /* Configure hook script environment variables. */
+ SVN_ERR(svn_repos_hooks_setenv(*repos, NULL, pool, pool));
+
return SVN_NO_ERROR;
}
Modified: subversion/branches/compressed-pristines/subversion/libsvn_ra_serf/commit.c
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/libsvn_ra_serf/commit.c?rev=1413258&r1=1413257&r2=1413258&view=diff
==============================================================================
--- subversion/branches/compressed-pristines/subversion/libsvn_ra_serf/commit.c (original)
+++ subversion/branches/compressed-pristines/subversion/libsvn_ra_serf/commit.c Sat Nov 24 20:29:11 2012
@@ -38,6 +38,7 @@
#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"
@@ -320,6 +321,49 @@ checkout_node(const char **working_url,
}
+/* 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.
+
+ 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,
apr_pool_t *scratch_pool)
@@ -365,8 +409,8 @@ checkout_dir(dir_context_t *dir,
}
/* Checkout our directory into the activity URL now. */
- err = checkout_node(working, dir->commit, checkout_url,
- dir->pool, scratch_pool);
+ err = retry_checkout_node(working, dir->commit, checkout_url,
+ dir->pool, scratch_pool);
if (err)
{
if (err->apr_err == SVN_ERR_FS_CONFLICT)
@@ -503,8 +547,8 @@ checkout_file(file_context_t *file,
NULL, scratch_pool, scratch_pool));
/* Checkout our file into the activity URL now. */
- err = checkout_node(&file->working_url, file->commit, checkout_url,
- file->pool, scratch_pool);
+ 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)
@@ -718,36 +762,62 @@ 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 *
-setup_proppatch_headers(serf_bucket_t *headers,
- void *baton,
- apr_pool_t *pool)
+maybe_set_lock_token_header(serf_bucket_t *headers,
+ commit_context_t *commit_ctx,
+ const char *relpath,
+ apr_pool_t *pool)
{
- proppatch_context_t *proppatch = baton;
+ const char *token;
- if (SVN_IS_VALID_REVNUM(proppatch->base_revision))
- {
- serf_bucket_headers_set(headers, SVN_DAV_VERSION_NAME_HEADER,
- apr_psprintf(pool, "%ld",
- proppatch->base_revision));
- }
+ if (! (relpath && commit_ctx->lock_tokens))
+ return SVN_NO_ERROR;
- if (proppatch->relpath && proppatch->commit->lock_tokens)
+ if (! apr_hash_get(commit_ctx->deleted_entries, relpath,
+ APR_HASH_KEY_STRING))
{
- const char *token;
-
- token = apr_hash_get(proppatch->commit->lock_tokens, proppatch->relpath,
+ token = apr_hash_get(commit_ctx->lock_tokens, 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);
}
}
+
+ 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;
+
+ if (SVN_IS_VALID_REVNUM(proppatch->base_revision))
+ {
+ serf_bucket_headers_set(headers, SVN_DAV_VERSION_NAME_HEADER,
+ apr_psprintf(pool, "%ld",
+ proppatch->base_revision));
+ }
+
+ SVN_ERR(maybe_set_lock_token_header(headers, proppatch->commit,
+ proppatch->relpath, pool));
return SVN_NO_ERROR;
}
@@ -950,22 +1020,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;
}
@@ -1108,7 +1164,26 @@ create_txn_post_body(serf_bucket_t **bod
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;
}
@@ -1213,12 +1288,15 @@ 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))
{
post_response_ctx_t *prc;
const char *rel_path;
+ svn_boolean_t post_with_revprops =
+ apr_hash_get(ctx->session->supported_posts, "create-txn-with-props",
+ APR_HASH_KEY_STRING) ? TRUE : FALSE;
/* Create our activity URL now on the server. */
handler = apr_pcalloc(ctx->pool, sizeof(*handler));
@@ -1226,7 +1304,8 @@ open_root(void *edit_baton,
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;
@@ -1288,7 +1367,9 @@ 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
{
@@ -1369,45 +1450,50 @@ open_root(void *edit_baton,
proppatch_target = ctx->baseline_url;
}
+ /* 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)
+ {
+ 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;
+
+ for (hi = apr_hash_first(ctx->pool, ctx->revprop_table); hi;
+ hi = apr_hash_next(hi))
+ {
+ 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 our revprops and pass them along. */
- 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;
-
- for (hi = apr_hash_first(ctx->pool, ctx->revprop_table); hi;
- hi = apr_hash_next(hi))
- {
- 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;
+ 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;
+ }
- 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;
@@ -1897,7 +1983,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);
@@ -2027,7 +2114,7 @@ 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;
@@ -2183,6 +2270,7 @@ svn_ra_serf__get_commit_editor(svn_ra_se
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));
@@ -2203,6 +2291,23 @@ svn_ra_serf__get_commit_editor(svn_ra_se
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)
+ {
+ apr_hash_set(ctx->revprop_table,
+ apr_pstrdup(pool, SVN_PROP_TXN_CLIENT_COMPAT_VERSION),
+ APR_HASH_KEY_STRING,
+ svn_string_create(SVN_VER_NUMBER, pool));
+ apr_hash_set(ctx->revprop_table,
+ apr_pstrdup(pool, SVN_PROP_TXN_USER_AGENT),
+ APR_HASH_KEY_STRING,
+ svn_string_create(session->useragent, pool));
+ }
+
ctx->callback = callback;
ctx->callback_baton = callback_baton;
Added: subversion/branches/compressed-pristines/subversion/libsvn_ra_serf/inherited_props.c
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/libsvn_ra_serf/inherited_props.c?rev=1413258&view=auto
==============================================================================
--- subversion/branches/compressed-pristines/subversion/libsvn_ra_serf/inherited_props.c (added)
+++ subversion/branches/compressed-pristines/subversion/libsvn_ra_serf/inherited_props.c Sat Nov 24 20:29:11 2012
@@ -0,0 +1,351 @@
+/*
+ * inherited_props.c : ra_serf implementation of svn_ra_get_inherited_props
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ */
+
+
+#include <apr_tables.h>
+#include <apr_xml.h>
+
+#include "svn_path.h"
+#include "svn_ra.h"
+#include "svn_string.h"
+#include "svn_xml.h"
+#include "svn_props.h"
+#include "svn_base64.h"
+
+#include "private/svn_dav_protocol.h"
+#include "../libsvn_ra/ra_loader.h"
+#include "svn_private_config.h"
+#include "ra_serf.h"
+
+
+/* The current state of our XML parsing. */
+typedef enum iprops_state_e {
+ NONE = 0,
+ IPROPS_REPORT,
+ IPROPS_ITEM,
+ IPROPS_PATH,
+ IPROPS_PROPNAME,
+ IPROPS_PROPVAL
+} iprops_state_e;
+
+/* Struct for accumulating inherited props. */
+typedef struct iprops_context_t {
+ /* The depth-first ordered array of svn_prop_inherited_item_t *
+ structures we are building. */
+ apr_array_header_t *iprops;
+
+ /* Pool in which to allocate elements of IPROPS. */
+ apr_pool_t *pool;
+
+ /* The repository's root URL. */
+ const char *repos_root_url;
+
+ /* Current CDATA values*/
+ svn_stringbuf_t *curr_path;
+ svn_stringbuf_t *curr_propname;
+ svn_stringbuf_t *curr_propval;
+ const char *curr_prop_val_encoding;
+
+ /* Current element in IPROPS. */
+ svn_prop_inherited_item_t *curr_iprop;
+
+ /* Serf context completion flag for svn_ra_serf__context_run_wait() */
+ svn_boolean_t done;
+
+ /* Path we are finding inherited properties for. This is relative to
+ the RA session passed to svn_ra_serf__get_inherited_props. */
+ const char *path;
+ /* The revision of PATH*/
+ svn_revnum_t revision;
+} iprops_context_t;
+
+static svn_error_t *
+start_element(svn_ra_serf__xml_parser_t *parser,
+ svn_ra_serf__dav_props_t name,
+ const char **attrs,
+ apr_pool_t *scratch_pool)
+{
+ iprops_context_t *iprops_ctx = parser->user_data;
+ iprops_state_e state;
+
+ state = parser->state->current_state;
+ if (state == NONE
+ && strcmp(name.name, SVN_DAV__INHERITED_PROPS_REPORT) == 0)
+ {
+ svn_ra_serf__xml_push_state(parser, IPROPS_REPORT);
+ }
+ else if (state == IPROPS_REPORT &&
+ strcmp(name.name, SVN_DAV__IPROP_ITEM) == 0)
+ {
+ svn_stringbuf_setempty(iprops_ctx->curr_path);
+ svn_stringbuf_setempty(iprops_ctx->curr_propname);
+ svn_stringbuf_setempty(iprops_ctx->curr_propval);
+ iprops_ctx->curr_prop_val_encoding = NULL;
+ iprops_ctx->curr_iprop = NULL;
+ svn_ra_serf__xml_push_state(parser, IPROPS_ITEM);
+ }
+ else if (state == IPROPS_ITEM &&
+ strcmp(name.name, SVN_DAV__IPROP_PROPVAL) == 0)
+ {
+ const char *prop_val_encoding = svn_xml_get_attr_value("encoding",
+ attrs);
+ iprops_ctx->curr_prop_val_encoding = apr_pstrdup(iprops_ctx->pool,
+ prop_val_encoding);
+ svn_ra_serf__xml_push_state(parser, IPROPS_PROPVAL);
+ }
+ else if (state == IPROPS_ITEM &&
+ strcmp(name.name, SVN_DAV__IPROP_PATH) == 0)
+ {
+ svn_ra_serf__xml_push_state(parser, IPROPS_PATH);
+ }
+ else if (state == IPROPS_ITEM &&
+ strcmp(name.name, SVN_DAV__IPROP_PROPNAME) == 0)
+ {
+ svn_ra_serf__xml_push_state(parser, IPROPS_PROPNAME);
+ }
+ else if (state == IPROPS_ITEM &&
+ strcmp(name.name, SVN_DAV__IPROP_PROPVAL) == 0)
+ {
+ svn_ra_serf__xml_push_state(parser, IPROPS_PROPVAL);
+ }
+
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+end_element(svn_ra_serf__xml_parser_t *parser,
+ svn_ra_serf__dav_props_t name,
+ apr_pool_t *scratch_pool)
+{
+ iprops_context_t *iprops_ctx = parser->user_data;
+ iprops_state_e state;
+
+ state = parser->state->current_state;
+
+ if (state == IPROPS_REPORT &&
+ strcmp(name.name, SVN_DAV__INHERITED_PROPS_REPORT) == 0)
+ {
+ svn_ra_serf__xml_pop_state(parser);
+ }
+ else if (state == IPROPS_PATH
+ && strcmp(name.name, SVN_DAV__IPROP_PATH) == 0)
+ {
+ iprops_ctx->curr_iprop = apr_palloc(
+ iprops_ctx->pool, sizeof(svn_prop_inherited_item_t));
+
+ iprops_ctx->curr_iprop->path_or_url =
+ svn_path_url_add_component2(iprops_ctx->repos_root_url,
+ iprops_ctx->curr_path->data,
+ iprops_ctx->pool);
+ iprops_ctx->curr_iprop->prop_hash = apr_hash_make(iprops_ctx->pool);
+ svn_ra_serf__xml_pop_state(parser);
+ }
+ else if (state == IPROPS_PROPVAL
+ && strcmp(name.name, SVN_DAV__IPROP_PROPVAL) == 0)
+ {
+ const svn_string_t *prop_val;
+
+ if (iprops_ctx->curr_prop_val_encoding)
+ {
+ svn_string_t encoded_prop_val;
+
+ if (strcmp(iprops_ctx->curr_prop_val_encoding, "base64") != 0)
+ return svn_error_create(SVN_ERR_XML_MALFORMED, NULL, NULL);
+
+ encoded_prop_val.data = iprops_ctx->curr_propval->data;
+ encoded_prop_val.len = iprops_ctx->curr_propval->len;
+ prop_val = svn_base64_decode_string(&encoded_prop_val,
+ iprops_ctx->pool);
+ }
+ else
+ {
+ prop_val = svn_string_create_from_buf(iprops_ctx->curr_propval,
+ iprops_ctx->pool);
+ }
+
+ apr_hash_set(iprops_ctx->curr_iprop->prop_hash,
+ apr_pstrdup(iprops_ctx->pool,
+ iprops_ctx->curr_propname->data),
+ APR_HASH_KEY_STRING,
+ prop_val);
+ /* Clear current propname and propval in the event there are
+ multiple properties on the current path. */
+ svn_stringbuf_setempty(iprops_ctx->curr_propname);
+ svn_stringbuf_setempty(iprops_ctx->curr_propval);
+ svn_ra_serf__xml_pop_state(parser);
+ }
+ else if (state == IPROPS_PROPNAME
+ && strcmp(name.name, SVN_DAV__IPROP_PROPNAME) == 0)
+ {
+ svn_ra_serf__xml_pop_state(parser);
+ }
+ else if (state == IPROPS_ITEM
+ && strcmp(name.name, SVN_DAV__IPROP_ITEM) == 0)
+ {
+ APR_ARRAY_PUSH(iprops_ctx->iprops, svn_prop_inherited_item_t *) =
+ iprops_ctx->curr_iprop;
+ svn_ra_serf__xml_pop_state(parser);
+ }
+ return SVN_NO_ERROR;
+}
+
+
+static svn_error_t *
+cdata_handler(svn_ra_serf__xml_parser_t *parser,
+ const char *data,
+ apr_size_t len,
+ apr_pool_t *scratch_pool)
+{
+ iprops_context_t *iprops_ctx = parser->user_data;
+ iprops_state_e state = parser->state->current_state;
+
+ switch (state)
+ {
+ case IPROPS_PATH:
+ svn_stringbuf_appendbytes(iprops_ctx->curr_path, data, len);
+ break;
+
+ case IPROPS_PROPNAME:
+ svn_stringbuf_appendbytes(iprops_ctx->curr_propname, data, len);
+ break;
+
+ case IPROPS_PROPVAL:
+ svn_stringbuf_appendbytes(iprops_ctx->curr_propval, data, len);
+ break;
+
+ default:
+ break;
+ }
+
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+create_iprops_body(serf_bucket_t **bkt,
+ void *baton,
+ serf_bucket_alloc_t *alloc,
+ apr_pool_t *pool)
+{
+ iprops_context_t *iprops_ctx = baton;
+ serf_bucket_t *body_bkt;
+
+ body_bkt = serf_bucket_aggregate_create(alloc);
+
+ svn_ra_serf__add_open_tag_buckets(body_bkt, alloc,
+ "S:" SVN_DAV__INHERITED_PROPS_REPORT,
+ "xmlns:S", SVN_XML_NAMESPACE,
+ NULL);
+ svn_ra_serf__add_tag_buckets(body_bkt,
+ "S:" SVN_DAV__REVISION,
+ apr_ltoa(pool, iprops_ctx->revision),
+ alloc);
+ svn_ra_serf__add_tag_buckets(body_bkt, "S:" SVN_DAV__PATH,
+ iprops_ctx->path, alloc);
+ svn_ra_serf__add_close_tag_buckets(body_bkt, alloc,
+ "S:" SVN_DAV__INHERITED_PROPS_REPORT);
+ *bkt = body_bkt;
+ 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 *
+svn_ra_serf__get_inherited_props(svn_ra_session_t *ra_session,
+ apr_array_header_t **iprops,
+ const char *path,
+ svn_revnum_t revision,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ svn_error_t *err, *err2;
+
+ iprops_context_t *iprops_ctx;
+ svn_ra_serf__session_t *session = ra_session->priv;
+ svn_ra_serf__handler_t *handler;
+ svn_ra_serf__xml_parser_t *parser_ctx;
+ const char *req_url;
+
+ SVN_ERR(svn_ra_serf__get_stable_url(&req_url,
+ NULL /* latest_revnum */,
+ session,
+ NULL /* conn */,
+ NULL /* url */,
+ revision,
+ result_pool, scratch_pool));
+
+ iprops_ctx = apr_pcalloc(scratch_pool, sizeof(*iprops_ctx));
+ iprops_ctx->done = FALSE;
+ iprops_ctx->repos_root_url = session->repos_root_str;
+ iprops_ctx->pool = result_pool;
+ iprops_ctx->curr_path = svn_stringbuf_create_empty(scratch_pool);
+ iprops_ctx->curr_propname = svn_stringbuf_create_empty(scratch_pool);
+ iprops_ctx->curr_propval = svn_stringbuf_create_empty(scratch_pool);
+ iprops_ctx->curr_iprop = NULL;
+ iprops_ctx->iprops = apr_array_make(result_pool, 1,
+ sizeof(svn_prop_inherited_item_t *));
+ iprops_ctx->path = path;
+ iprops_ctx->revision = revision;
+
+ handler = apr_pcalloc(scratch_pool, sizeof(*handler));
+
+ handler->method = "REPORT";
+ handler->path = req_url;
+ handler->conn = session->conns[0];
+ handler->session = session;
+ handler->body_delegate = create_iprops_body;
+ handler->body_delegate_baton = iprops_ctx;
+ handler->body_type = "text/xml";
+ handler->handler_pool = scratch_pool;
+
+ parser_ctx = apr_pcalloc(scratch_pool, sizeof(*parser_ctx));
+
+ parser_ctx->pool = scratch_pool;
+ parser_ctx->user_data = iprops_ctx;
+ parser_ctx->start = start_element;
+ parser_ctx->end = end_element;
+ parser_ctx->cdata = cdata_handler;
+ parser_ctx->done = &iprops_ctx->done;
+
+ handler->response_handler = svn_ra_serf__handle_xml_parser;
+ handler->response_baton = parser_ctx;
+
+ svn_ra_serf__request_create(handler);
+
+ err = svn_ra_serf__context_run_wait(&iprops_ctx->done, session,
+ scratch_pool);
+
+ err2 = svn_ra_serf__error_on_status(handler->sline.code, handler->path,
+ handler->location);
+ if (err2)
+ {
+ svn_error_clear(err);
+ return err2;
+ }
+
+ SVN_ERR(err);
+
+ if (iprops_ctx->done)
+ *iprops = iprops_ctx->iprops;
+
+ return SVN_NO_ERROR;
+}
Modified: subversion/branches/compressed-pristines/subversion/libsvn_ra_serf/options.c
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/libsvn_ra_serf/options.c?rev=1413258&r1=1413257&r2=1413258&view=diff
==============================================================================
--- subversion/branches/compressed-pristines/subversion/libsvn_ra_serf/options.c (original)
+++ subversion/branches/compressed-pristines/subversion/libsvn_ra_serf/options.c Sat Nov 24 20:29:11 2012
@@ -199,15 +199,38 @@ capabilities_headers_iterator_callback(v
SVN_RA_CAPABILITY_PARTIAL_REPLAY, APR_HASH_KEY_STRING,
capability_yes);
}
+ if (svn_cstring_match_list(SVN_DAV_NS_DAV_SVN_INHERITED_PROPS, vals))
+ {
+ apr_hash_set(session->capabilities,
+ SVN_RA_CAPABILITY_INHERITED_PROPS,
+ APR_HASH_KEY_STRING, capability_yes);
+ }
+ if (svn_cstring_match_list(SVN_DAV_NS_DAV_SVN_EPHEMERAL_TXNPROPS, vals))
+ {
+ apr_hash_set(session->capabilities,
+ SVN_RA_CAPABILITY_EPHEMERAL_TXNPROPS, APR_HASH_KEY_STRING,
+ capability_yes);
+ }
}
/* SVN-specific headers -- if present, server supports HTTP protocol v2 */
else if (strncmp(key, "SVN", 3) == 0)
{
+ /* If we've not yet seen any information about supported POST
+ requests, we'll initialize the list/hash with "create-txn"
+ (which we know is supported by virtue of the server speaking
+ HTTPv2 at all. */
+ if (! session->supported_posts)
+ {
+ session->supported_posts = apr_hash_make(session->pool);
+ apr_hash_set(session->supported_posts, "create-txn", 10, (void *)1);
+ }
+
if (svn_cstring_casecmp(key, SVN_DAV_ROOT_URI_HEADER) == 0)
{
session->repos_root = session->session_url;
- session->repos_root.path = apr_pstrdup(session->pool, val);
+ session->repos_root.path =
+ (char *)svn_fspath__canonicalize(val, session->pool);
session->repos_root_str =
svn_urlpath__canonicalize(
apr_uri_unparse(session->pool, &session->repos_root, 0),
@@ -257,6 +280,21 @@ capabilities_headers_iterator_callback(v
{
opt_ctx->youngest_rev = SVN_STR_TO_REV(val);
}
+ else if (svn_cstring_casecmp(key, SVN_DAV_SUPPORTED_POSTS_HEADER) == 0)
+ {
+ /* May contain multiple values, separated by commas. */
+ int i;
+ apr_array_header_t *vals = svn_cstring_split(val, ",", TRUE,
+ opt_ctx->pool);
+
+ for (i = 0; i < vals->nelts; i++)
+ {
+ const char *post_val = APR_ARRAY_IDX(vals, i, const char *);
+
+ apr_hash_set(session->supported_posts, post_val,
+ APR_HASH_KEY_STRING, (void *)1);
+ }
+ }
}
return 0;
@@ -291,6 +329,10 @@ options_response_handler(serf_request_t
APR_HASH_KEY_STRING, capability_no);
apr_hash_set(session->capabilities, SVN_RA_CAPABILITY_ATOMIC_REVPROPS,
APR_HASH_KEY_STRING, capability_no);
+ apr_hash_set(session->capabilities, SVN_RA_CAPABILITY_INHERITED_PROPS,
+ APR_HASH_KEY_STRING, capability_no);
+ apr_hash_set(session->capabilities, SVN_RA_CAPABILITY_EPHEMERAL_TXNPROPS,
+ APR_HASH_KEY_STRING, capability_no);
/* Then see which ones we can discover. */
serf_bucket_headers_do(hdrs, capabilities_headers_iterator_callback,
@@ -299,7 +341,7 @@ options_response_handler(serf_request_t
opt_ctx->headers_processed = TRUE;
}
- /* Execute the 'real' response handler to XML-parse the repsonse body. */
+ /* Execute the 'real' response handler to XML-parse the response body. */
return opt_ctx->inner_handler(request, response, opt_ctx->inner_baton, pool);
}
Modified: subversion/branches/compressed-pristines/subversion/libsvn_ra_serf/property.c
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/libsvn_ra_serf/property.c?rev=1413258&r1=1413257&r2=1413258&view=diff
==============================================================================
--- subversion/branches/compressed-pristines/subversion/libsvn_ra_serf/property.c (original)
+++ subversion/branches/compressed-pristines/subversion/libsvn_ra_serf/property.c Sat Nov 24 20:29:11 2012
@@ -322,16 +322,11 @@ propfind_closed(svn_ra_serf__xml_estate_
else
{
apr_hash_t *gathered;
- const char *path;
SVN_ERR_ASSERT(leaving_state == PROPSTAT);
gathered = svn_ra_serf__xml_gather_since(xes, PROPSTAT);
- path = apr_hash_get(gathered, "path", APR_HASH_KEY_STRING);
- if (path == NULL)
- path = ctx->path;
-
/* If we've squirreled away a note that says we want to ignore
these properties, we'll do so. Otherwise, we need to copy
them from the temporary hash into the ctx->ret_props hash. */
Modified: subversion/branches/compressed-pristines/subversion/libsvn_ra_serf/ra_serf.h
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/libsvn_ra_serf/ra_serf.h?rev=1413258&r1=1413257&r2=1413258&view=diff
==============================================================================
--- subversion/branches/compressed-pristines/subversion/libsvn_ra_serf/ra_serf.h (original)
+++ subversion/branches/compressed-pristines/subversion/libsvn_ra_serf/ra_serf.h Sat Nov 24 20:29:11 2012
@@ -62,6 +62,10 @@ extern "C" {
APR_STRINGIFY(SERF_MINOR_VERSION) "." \
APR_STRINGIFY(SERF_PATCH_VERSION)
+/** Wait duration (in microseconds) used in calls to serf_context_run() */
+#define SVN_RA_SERF__CONTEXT_RUN_DURATION 500000
+
+
/* Forward declarations. */
typedef struct svn_ra_serf__session_t svn_ra_serf__session_t;
@@ -89,7 +93,9 @@ typedef struct svn_ra_serf__connection_t
} svn_ra_serf__connection_t;
-/** Max. number of connctions we'll open to the server. */
+/** Max. number of connctions we'll open to the server.
+ * Note: minimum 2 connections are required for ra_serf to function correctly!
+ */
#define MAX_NR_OF_CONNS 4
/*
@@ -209,6 +215,10 @@ struct svn_ra_serf__session_t {
const char *vtxn_stub; /* for accessing transactions (i.e. txnprops) */
const char *vtxn_root_stub; /* for accessing TXN/PATH pairs */
+ /* Hash mapping const char * server-supported POST types to
+ disinteresting-but-non-null values. */
+ apr_hash_t *supported_posts;
+
/*** End HTTP v2 stuff ***/
svn_ra_serf__blncache_t *blncache;
@@ -969,12 +979,15 @@ svn_ra_serf__add_xml_header_buckets(serf
serf_bucket_alloc_t *bkt_alloc);
/*
- * Add the appropriate serf buckets to AGG_BUCKET representing xml tag open
- * with name TAG.
+ * Add the appropriate serf buckets to AGG_BUCKET representing the XML
+ * open tag with name TAG.
*
* Take the tag's attributes from varargs, a NULL-terminated list of
- * alternating <tt>char *</tt> key and <tt>char *</tt> val. Do xml-escaping
- * on each val. Attribute will be ignored if it's value is NULL.
+ * alternating <tt>char *</tt> key and <tt>char *</tt> val. Attribute
+ * will be ignored if it's value is NULL.
+ *
+ * NOTE: Callers are responsible for XML-escaping attribute values as
+ * necessary.
*
* The bucket will be allocated from BKT_ALLOC.
*/
@@ -1647,6 +1660,14 @@ svn_ra_serf__get_deleted_rev(svn_ra_sess
svn_revnum_t *revision_deleted,
apr_pool_t *pool);
+/* Implements the get_inherited_props RA layer function. */
+svn_error_t * svn_ra_serf__get_inherited_props(svn_ra_session_t *session,
+ apr_array_header_t **iprops,
+ const char *path,
+ svn_revnum_t revision,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool);
+
/* Implements svn_ra__vtable_t.get_repos_root(). */
svn_error_t *
svn_ra_serf__get_repos_root(svn_ra_session_t *ra_session,
@@ -1658,7 +1679,6 @@ svn_error_t *
svn_ra_serf__register_editor_shim_callbacks(svn_ra_session_t *session,
svn_delta_shim_callbacks_t *callbacks);
-
/*** Authentication handler declarations ***/
/**
@@ -1699,6 +1719,21 @@ svn_ra_serf__create_sb_bucket(svn_spillb
apr_pool_t *result_pool,
apr_pool_t *scratch_pool);
+/** Wrap STATUS from an serf function. If STATUS is not serf error code,
+ * this is equivalent to svn_error_wrap_apr().
+ */
+svn_error_t *
+svn_ra_serf__wrap_err(apr_status_t status,
+ const char *fmt,
+ ...);
+
+
+#if defined(SVN_DEBUG)
+/* Wrapper macros to collect file and line information */
+#define svn_ra_serf__wrap_err \
+ (svn_error__locate(__FILE__,__LINE__), (svn_ra_serf__wrap_err))
+
+#endif
#ifdef __cplusplus
}
Modified: subversion/branches/compressed-pristines/subversion/libsvn_ra_serf/replay.c
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/libsvn_ra_serf/replay.c?rev=1413258&r1=1413257&r2=1413258&view=diff
==============================================================================
--- subversion/branches/compressed-pristines/subversion/libsvn_ra_serf/replay.c (original)
+++ subversion/branches/compressed-pristines/subversion/libsvn_ra_serf/replay.c Sat Nov 24 20:29:11 2012
@@ -732,6 +732,7 @@ svn_ra_serf__replay_range(svn_ra_session
svn_revnum_t rev = start_revision;
const char *report_target;
int active_reports = 0;
+ apr_short_interval_time_t waittime_left = session->timeout;
SVN_ERR(svn_ra_serf__report_resource(&report_target, session, NULL, pool));
@@ -855,18 +856,36 @@ svn_ra_serf__replay_range(svn_ra_session
### ahead and apply it here, too, in case serf eventually uses
### that parameter.
*/
- status = serf_context_run(session->context, session->timeout,
+ status = serf_context_run(session->context,
+ SVN_RA_SERF__CONTEXT_RUN_DURATION,
pool);
err = session->pending_error;
session->pending_error = NULL;
+ /* If the context duration timeout is up, we'll subtract that
+ duration from the total time alloted for such things. If
+ there's no time left, we fail with a message indicating that
+ the connection timed out. */
if (APR_STATUS_IS_TIMEUP(status))
{
svn_error_clear(err);
- return svn_error_create(SVN_ERR_RA_DAV_CONN_TIMEOUT,
- NULL,
- _("Connection timed out"));
+ err = SVN_NO_ERROR;
+ status = 0;
+
+ if (waittime_left > SVN_RA_SERF__CONTEXT_RUN_DURATION)
+ {
+ waittime_left -= SVN_RA_SERF__CONTEXT_RUN_DURATION;
+ }
+ else
+ {
+ return svn_error_create(SVN_ERR_RA_DAV_CONN_TIMEOUT, NULL,
+ _("Connection timed out"));
+ }
+ }
+ else
+ {
+ waittime_left = session->timeout;
}
/* Substract the number of completely handled responses from our
@@ -885,9 +904,8 @@ svn_ra_serf__replay_range(svn_ra_session
SVN_ERR(err);
if (status)
{
- return svn_error_wrap_apr(status,
- _("Error retrieving replay REPORT (%d)"),
- status);
+ return svn_ra_serf__wrap_err(status,
+ _("Error retrieving replay REPORT"));
}
done_reports = NULL;
}
Modified: subversion/branches/compressed-pristines/subversion/libsvn_ra_serf/sb_bucket.c
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/libsvn_ra_serf/sb_bucket.c?rev=1413258&r1=1413257&r2=1413258&view=diff
==============================================================================
--- subversion/branches/compressed-pristines/subversion/libsvn_ra_serf/sb_bucket.c (original)
+++ subversion/branches/compressed-pristines/subversion/libsvn_ra_serf/sb_bucket.c Sat Nov 24 20:29:11 2012
@@ -62,7 +62,7 @@ svn_ra_serf__copy_into_spillbuf(svn_spil
status = serf_bucket_read(bkt, SERF_READ_ALL_AVAIL, &data, &len);
if (status != APR_SUCCESS && status != APR_EOF)
- return svn_error_wrap_apr(status, _("Failed to read the request"));
+ return svn_ra_serf__wrap_err(status, _("Failed to read the request"));
SVN_ERR(svn_spillbuf__write(*spillbuf, data, len, scratch_pool));
Modified: subversion/branches/compressed-pristines/subversion/libsvn_ra_serf/serf.c
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/libsvn_ra_serf/serf.c?rev=1413258&r1=1413257&r2=1413258&view=diff
==============================================================================
--- subversion/branches/compressed-pristines/subversion/libsvn_ra_serf/serf.c (original)
+++ subversion/branches/compressed-pristines/subversion/libsvn_ra_serf/serf.c Sat Nov 24 20:29:11 2012
@@ -307,9 +307,9 @@ load_config(svn_ra_serf__session_t *sess
session->pool);
if (status)
{
- return svn_error_wrap_apr(status,
- _("Could not resolve proxy server '%s'"),
- proxy_host);
+ return svn_ra_serf__wrap_err(
+ status, _("Could not resolve proxy server '%s'"),
+ proxy_host);
}
session->using_proxy = TRUE;
serf_config_proxy(session->context, proxy_addr);
@@ -381,10 +381,12 @@ svn_ra_serf__open(svn_ra_session_t *sess
_("Illegal URL '%s'"),
session_URL);
}
- /* Contrary to what the comment for apr_uri_t.path says in apr-util 1.2.12 and
- older, for root paths url.path will be "", where serf requires "/". */
+ /* Depending the version of apr-util in use, for root paths url.path
+ will be NULL or "", where serf requires "/". */
if (url.path == NULL || url.path[0] == '\0')
- url.path = apr_pstrdup(serf_sess->pool, "/");
+ {
+ url.path = apr_pstrdup(serf_sess->pool, "/");
+ }
if (!url.port)
{
url.port = apr_uri_port_of_scheme(url.scheme);
@@ -397,8 +399,9 @@ svn_ra_serf__open(svn_ra_session_t *sess
serf_sess->capabilities = apr_hash_make(serf_sess->pool);
- serf_sess->http10 = TRUE; /* until we confirm HTTP/1.1 */
- serf_sess->http10 = FALSE; /* ### don't change behavior yet */
+ /* We have to assume that the server only supports HTTP/1.0. Once it's clear
+ HTTP/1.1 is supported, we can upgrade. */
+ serf_sess->http10 = TRUE;
SVN_ERR(load_config(serf_sess, config, serf_sess->pool));
@@ -414,7 +417,7 @@ svn_ra_serf__open(svn_ra_session_t *sess
callbacks->get_client_string(callback_baton, &client_string, pool);
if (client_string)
- serf_sess->useragent = apr_pstrcat(pool, USER_AGENT, "/",
+ serf_sess->useragent = apr_pstrcat(pool, USER_AGENT, " ",
client_string, (char *)NULL);
else
serf_sess->useragent = USER_AGENT;
@@ -428,7 +431,7 @@ svn_ra_serf__open(svn_ra_session_t *sess
svn_ra_serf__conn_closed, serf_sess->conns[0],
serf_sess->pool);
if (status)
- return svn_error_wrap_apr(status, NULL);
+ return svn_ra_serf__wrap_err(status, NULL);
/* Set the progress callback. */
serf_context_set_progress_cb(serf_sess->context, svn_ra_serf__progress,
@@ -478,9 +481,18 @@ svn_ra_serf__reparent(svn_ra_session_t *
_("Illegal repository URL '%s'"), url);
}
- /* Maybe we should use a string buffer for these strings so we don't
- allocate memory in the session on every reparent? */
- session->session_url.path = apr_pstrdup(session->pool, new_url.path);
+ /* Depending the version of apr-util in use, for root paths url.path
+ will be NULL or "", where serf requires "/". */
+ /* ### Maybe we should use a string buffer for these strings so we
+ ### don't allocate memory in the session on every reparent? */
+ if (new_url.path == NULL || new_url.path[0] == '\0')
+ {
+ session->session_url.path = apr_pstrdup(session->pool, "/");
+ }
+ else
+ {
+ session->session_url.path = apr_pstrdup(session->pool, new_url.path);
+ }
session->session_url_str = apr_pstrdup(session->pool, url);
return SVN_NO_ERROR;
@@ -1138,7 +1150,8 @@ static const svn_ra__vtable_t serf_vtabl
svn_ra_serf__has_capability,
svn_ra_serf__replay_range,
svn_ra_serf__get_deleted_rev,
- svn_ra_serf__register_editor_shim_callbacks
+ svn_ra_serf__register_editor_shim_callbacks,
+ svn_ra_serf__get_inherited_props
};
svn_error_t *
Modified: subversion/branches/compressed-pristines/subversion/libsvn_ra_serf/update.c
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/libsvn_ra_serf/update.c?rev=1413258&r1=1413257&r2=1413258&view=diff
==============================================================================
--- subversion/branches/compressed-pristines/subversion/libsvn_ra_serf/update.c (original)
+++ subversion/branches/compressed-pristines/subversion/libsvn_ra_serf/update.c Sat Nov 24 20:29:11 2012
@@ -313,6 +313,10 @@ struct report_context_t {
/* Do we want the server to send copyfrom args or not? */
svn_boolean_t send_copyfrom_args;
+ /* Is the server including properties inline for newly added
+ files/dirs? */
+ svn_boolean_t add_props_included;
+
/* Path -> lock token mapping. */
apr_hash_t *lock_path_tokens;
@@ -358,6 +362,9 @@ struct report_context_t {
/* Are we done parsing the REPORT response? */
svn_boolean_t done;
+ /* Did we get a complete (non-truncated) report? */
+ svn_boolean_t report_completed;
+
/* The XML parser context for the REPORT response. */
svn_ra_serf__xml_parser_t *parser_ctx;
};
@@ -926,12 +933,23 @@ handle_fetch(serf_request_t *request,
return error_fetch(request, fetch_ctx, err);
}
- if (val && svn_cstring_casecmp(val, "application/vnd.svn-svndiff") == 0)
+ if (val && svn_cstring_casecmp(val, SVN_SVNDIFF_MIME_TYPE) == 0)
{
fetch_ctx->delta_stream =
svn_txdelta_parse_svndiff(info->textdelta,
info->textdelta_baton,
TRUE, info->editor_pool);
+
+ /* Validate the delta base claimed by the server matches
+ what we asked for! */
+ val = serf_bucket_headers_get(hdrs, SVN_DAV_DELTA_BASE_HEADER);
+ if (val && (strcmp(val, info->delta_base) != 0))
+ {
+ err = svn_error_createf(SVN_ERR_RA_DAV_REQUEST_FAILED, NULL,
+ _("GET request returned unexpected "
+ "delta base: %s"), val);
+ return error_fetch(request, fetch_ctx, err);
+ }
}
else
{
@@ -961,7 +979,7 @@ handle_fetch(serf_request_t *request,
status = serf_bucket_read(response, 8000, &data, &len);
if (SERF_BUCKET_READ_ERROR(status))
{
- return svn_error_wrap_apr(status, NULL);
+ return svn_ra_serf__wrap_err(status, NULL);
}
fetch_ctx->read_size += len;
@@ -981,7 +999,7 @@ handle_fetch(serf_request_t *request,
/* Skip on to the next iteration of this loop. */
if (APR_STATUS_IS_EAGAIN(status))
{
- return svn_error_wrap_apr(status, NULL);
+ return svn_ra_serf__wrap_err(status, NULL);
}
continue;
}
@@ -1057,11 +1075,11 @@ handle_fetch(serf_request_t *request,
svn_pool_destroy(info->pool);
if (status)
- return svn_error_wrap_apr(status, NULL);
+ return svn_ra_serf__wrap_err(status, NULL);
}
if (APR_STATUS_IS_EAGAIN(status))
{
- return svn_error_wrap_apr(status, NULL);
+ return svn_ra_serf__wrap_err(status, NULL);
}
}
/* not reached */
@@ -1103,7 +1121,7 @@ handle_stream(serf_request_t *request,
status = serf_bucket_read(response, 8000, &data, &len);
if (SERF_BUCKET_READ_ERROR(status))
{
- return svn_error_wrap_apr(status, NULL);
+ return svn_ra_serf__wrap_err(status, NULL);
}
fetch_ctx->read_size += len;
@@ -1122,7 +1140,7 @@ handle_stream(serf_request_t *request,
/* Skip on to the next iteration of this loop. */
if (APR_STATUS_IS_EAGAIN(status))
{
- return svn_error_wrap_apr(status, NULL);
+ return svn_ra_serf__wrap_err(status, NULL);
}
continue;
}
@@ -1152,7 +1170,7 @@ handle_stream(serf_request_t *request,
if (status)
{
- return svn_error_wrap_apr(status, NULL);
+ return svn_ra_serf__wrap_err(status, NULL);
}
}
/* not reached */
@@ -1216,9 +1234,9 @@ fetch_file(report_context_t *ctx, report
if (!info->url)
{
- return svn_error_create(SVN_ERR_RA_DAV_OPTIONS_REQ_FAILED, NULL,
- _("The OPTIONS response did not include the "
- "requested checked-in value"));
+ return svn_error_create(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL,
+ _("The REPORT or PROPFIND response did not "
+ "include the requested checked-in value"));
}
/* If needed, create the PROPFIND to retrieve the file's properties. */
@@ -1388,7 +1406,13 @@ start_report(svn_ra_serf__xml_parser_t *
state = parser->state->current_state;
- if (state == NONE && strcmp(name.name, "target-revision") == 0)
+ if (state == NONE && strcmp(name.name, "update-report") == 0)
+ {
+ const char *val = svn_xml_get_attr_value("inline-props", attrs);
+ if (val && (strcmp(val, "true") == 0))
+ ctx->add_props_included = TRUE;
+ }
+ else if (state == NONE && strcmp(name.name, "target-revision") == 0)
{
const char *rev;
@@ -1528,7 +1552,11 @@ start_report(svn_ra_serf__xml_parser_t *
/* Mark that we don't have a base. */
info->base_rev = SVN_INVALID_REVNUM;
dir->base_rev = info->base_rev;
- dir->fetch_props = TRUE;
+
+ /* If the server isn't included properties for added items,
+ we'll need to fetch them ourselves. */
+ if (! ctx->add_props_included)
+ dir->fetch_props = TRUE;
dir->repos_relpath = svn_relpath_join(dir->parent_dir->repos_relpath,
dir->base_name, dir->pool);
@@ -1585,9 +1613,13 @@ start_report(svn_ra_serf__xml_parser_t *
info = push_state(parser, ctx, ADD_FILE);
info->base_rev = SVN_INVALID_REVNUM;
- info->fetch_props = TRUE;
info->fetch_file = TRUE;
+ /* If the server isn't included properties for added items,
+ we'll need to fetch them ourselves. */
+ if (! ctx->add_props_included)
+ info->fetch_props = TRUE;
+
info->base_name = apr_pstrdup(info->pool, file_name);
info->name = NULL;
@@ -1862,8 +1894,15 @@ end_report(svn_ra_serf__xml_parser_t *pa
if (state == NONE)
{
- /* nothing to close yet. */
- return SVN_NO_ERROR;
+ if (strcmp(name.name, "update-report") == 0)
+ {
+ ctx->report_completed = TRUE;
+ }
+ else
+ {
+ /* nothing to close yet. */
+ return SVN_NO_ERROR;
+ }
}
if (((state == OPEN_DIR && (strcmp(name.name, "open-directory") == 0)) ||
@@ -1886,9 +1925,9 @@ end_report(svn_ra_serf__xml_parser_t *pa
if (!checked_in_url &&
(!SVN_IS_VALID_REVNUM(info->dir->base_rev) || info->dir->fetch_props))
{
- return svn_error_create(SVN_ERR_RA_DAV_OPTIONS_REQ_FAILED, NULL,
- _("The OPTIONS response did not include the "
- "requested checked-in value"));
+ return svn_error_create(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL,
+ _("The REPORT or PROPFIND response did not "
+ "include the requested checked-in value"));
}
info->dir->url = checked_in_url;
@@ -1896,7 +1935,7 @@ end_report(svn_ra_serf__xml_parser_t *pa
/* At this point, we should have the checked-in href.
* If needed, create the PROPFIND to retrieve the dir's properties.
*/
- if (!SVN_IS_VALID_REVNUM(info->dir->base_rev) || info->dir->fetch_props)
+ if (info->dir->fetch_props)
{
/* Unconditionally set fetch_props now. */
info->dir->fetch_props = TRUE;
@@ -2299,7 +2338,7 @@ open_connection_if_needed(svn_ra_serf__s
sess->conns[cur],
sess->pool);
if (status)
- return svn_error_wrap_apr(status, NULL);
+ return svn_ra_serf__wrap_err(status, NULL);
sess->num_conns++;
}
@@ -2353,6 +2392,7 @@ finish_report(void *report_baton,
svn_stringbuf_t *buf = NULL;
apr_pool_t *iterpool = svn_pool_create(pool);
svn_error_t *err;
+ apr_short_interval_time_t waittime_left = sess->timeout;
svn_xml_make_close_tag(&buf, iterpool, "S:update-report");
SVN_ERR(svn_io_file_write_full(report->body_file, buf->data, buf->len,
@@ -2435,7 +2475,9 @@ finish_report(void *report_baton,
and what items are allocated within. */
iterpool_inner = svn_pool_create(iterpool);
- status = serf_context_run(sess->context, sess->timeout, iterpool_inner);
+ status = serf_context_run(sess->context,
+ SVN_RA_SERF__CONTEXT_RUN_DURATION,
+ iterpool_inner);
err = sess->pending_error;
sess->pending_error = SVN_NO_ERROR;
@@ -2445,19 +2487,35 @@ finish_report(void *report_baton,
err = handler->server_error->error;
}
+ /* If the context duration timeout is up, we'll subtract that
+ duration from the total time alloted for such things. If
+ there's no time left, we fail with a message indicating that
+ the connection timed out. */
if (APR_STATUS_IS_TIMEUP(status))
{
svn_error_clear(err);
- return svn_error_create(SVN_ERR_RA_DAV_CONN_TIMEOUT,
- NULL,
- _("Connection timed out"));
+ err = SVN_NO_ERROR;
+ status = 0;
+
+ if (waittime_left > SVN_RA_SERF__CONTEXT_RUN_DURATION)
+ {
+ waittime_left -= SVN_RA_SERF__CONTEXT_RUN_DURATION;
+ }
+ else
+ {
+ return svn_error_create(SVN_ERR_RA_DAV_CONN_TIMEOUT, NULL,
+ _("Connection timed out"));
+ }
+ }
+ else
+ {
+ waittime_left = sess->timeout;
}
SVN_ERR(err);
if (status)
{
- return svn_error_wrap_apr(status, _("Error retrieving REPORT (%d)"),
- status);
+ return svn_ra_serf__wrap_err(status, _("Error retrieving REPORT"));
}
/* Open extra connections if we have enough requests to send. */
@@ -2607,7 +2665,12 @@ finish_report(void *report_baton,
SVN_ERR(close_all_dirs(report->root_dir));
}
- err = report->update_editor->close_edit(report->update_baton, iterpool);
+ /* If we got a complete report, close the edit. Otherwise, abort it. */
+ if (report->report_completed)
+ err = report->update_editor->close_edit(report->update_baton, iterpool);
+ else
+ err = svn_error_create(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL,
+ _("Missing update-report close tag"));
svn_pool_destroy(iterpool);
return svn_error_trace(err);
@@ -2750,6 +2813,10 @@ make_update_reporter(svn_ra_session_t *r
make_simple_xml_tag(&buf, "S:recursive", "no", scratch_pool);
}
+ /* Subversion 1.8+ servers can be told to send properties for newly
+ added items inline even when doing a skelta response. */
+ make_simple_xml_tag(&buf, "S:include-props", "yes", scratch_pool);
+
make_simple_xml_tag(&buf, "S:depth", svn_depth_to_word(depth), scratch_pool);
SVN_ERR(svn_io_file_write_full(report->body_file, buf->data, buf->len,
Modified: subversion/branches/compressed-pristines/subversion/libsvn_ra_serf/util.c
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/libsvn_ra_serf/util.c?rev=1413258&r1=1413257&r2=1413258&view=diff
==============================================================================
--- subversion/branches/compressed-pristines/subversion/libsvn_ra_serf/util.c (original)
+++ subversion/branches/compressed-pristines/subversion/libsvn_ra_serf/util.c Sat Nov 24 20:29:11 2012
@@ -691,6 +691,11 @@ setup_serf_req(serf_request_t *request,
serf_bucket_headers_setn(*hdrs_bkt, "Content-Type", content_type);
}
+#if SERF_VERSION_AT_LEAST(1, 1, 0)
+ if (session->http10)
+ serf_bucket_headers_setn(*hdrs_bkt, "Connection", "keep-alive");
+#endif
+
/* These headers need to be sent with every request; see issue #3255
("mod_dav_svn does not pass client capabilities to start-commit
hooks") for why. */
@@ -707,7 +712,8 @@ svn_ra_serf__context_run_wait(svn_boolea
apr_pool_t *scratch_pool)
{
apr_pool_t *iterpool;
-
+ apr_short_interval_time_t waittime_left = sess->timeout;
+
assert(sess->pending_error == SVN_NO_ERROR);
iterpool = svn_pool_create(scratch_pool);
@@ -722,17 +728,36 @@ svn_ra_serf__context_run_wait(svn_boolea
if (sess->cancel_func)
SVN_ERR((*sess->cancel_func)(sess->cancel_baton));
- status = serf_context_run(sess->context, sess->timeout, iterpool);
+ status = serf_context_run(sess->context,
+ SVN_RA_SERF__CONTEXT_RUN_DURATION,
+ iterpool);
err = sess->pending_error;
sess->pending_error = SVN_NO_ERROR;
+ /* If the context duration timeout is up, we'll subtract that
+ duration from the total time alloted for such things. If
+ there's no time left, we fail with a message indicating that
+ the connection timed out. */
if (APR_STATUS_IS_TIMEUP(status))
{
svn_error_clear(err);
- return svn_error_create(SVN_ERR_RA_DAV_CONN_TIMEOUT,
- NULL,
- _("Connection timed out"));
+ err = SVN_NO_ERROR;
+ status = 0;
+
+ if (waittime_left > SVN_RA_SERF__CONTEXT_RUN_DURATION)
+ {
+ waittime_left -= SVN_RA_SERF__CONTEXT_RUN_DURATION;
+ }
+ else
+ {
+ return svn_error_create(SVN_ERR_RA_DAV_CONN_TIMEOUT, NULL,
+ _("Connection timed out"));
+ }
+ }
+ else
+ {
+ waittime_left = sess->timeout;
}
SVN_ERR(err);
@@ -745,7 +770,7 @@ svn_ra_serf__context_run_wait(svn_boolea
_("Error running context"));
}
- return svn_error_wrap_apr(status, _("Error running context"));
+ return svn_ra_serf__wrap_err(status, _("Error running context"));
}
/* Debugging purposes only! */
@@ -811,7 +836,12 @@ start_error(svn_ra_serf__xml_parser_t *p
SVN_ERR(svn_cstring_atoi64(&val, err_code));
ctx->error->apr_err = (apr_status_t)val;
}
- else
+
+ /* If there's no error code provided, or if the provided code is
+ 0 (which can happen sometimes depending on how the error is
+ constructed on the server-side), just pick a generic error
+ code to run with. */
+ if (! ctx->error->apr_err)
{
ctx->error->apr_err = SVN_ERR_RA_DAV_REQUEST_FAILED;
}
@@ -928,7 +958,7 @@ svn_ra_serf__handle_discard_body(serf_re
status = drain_bucket(response);
if (status)
- return svn_error_wrap_apr(status, NULL);
+ return svn_ra_serf__wrap_err(status, NULL);
return SVN_NO_ERROR;
}
@@ -1467,7 +1497,7 @@ handle_server_error(serf_request_t *requ
surface. */
err = drain_bucket(response);
if (err && !SERF_BUCKET_READ_ERROR(err))
- return svn_error_wrap_apr(err, NULL);
+ return svn_ra_serf__wrap_err(err, NULL);
return SVN_NO_ERROR;
}
@@ -1489,7 +1519,7 @@ svn_ra_serf__handle_xml_parser(serf_requ
status = serf_bucket_response_status(response, &sl);
if (SERF_BUCKET_READ_ERROR(status))
{
- return svn_error_wrap_apr(status, NULL);
+ return svn_ra_serf__wrap_err(status, NULL);
}
/* Woo-hoo. Nothing here to see. */
@@ -1541,7 +1571,7 @@ svn_ra_serf__handle_xml_parser(serf_requ
if (SERF_BUCKET_READ_ERROR(status))
{
- return svn_error_wrap_apr(status, NULL);
+ return svn_ra_serf__wrap_err(status, NULL);
}
ctx->read_size += len;
@@ -1562,7 +1592,7 @@ svn_ra_serf__handle_xml_parser(serf_requ
/* Skip on to the next iteration of this loop. */
if (APR_STATUS_IS_EAGAIN(status))
{
- return svn_error_wrap_apr(status, NULL);
+ return svn_ra_serf__wrap_err(status, NULL);
}
continue;
}
@@ -1606,7 +1636,7 @@ svn_ra_serf__handle_xml_parser(serf_requ
if (APR_STATUS_IS_EAGAIN(status))
{
- return svn_error_wrap_apr(status, NULL);
+ return svn_ra_serf__wrap_err(status, NULL);
}
if (APR_STATUS_IS_EOF(status))
@@ -1627,7 +1657,7 @@ svn_ra_serf__handle_xml_parser(serf_requ
add_done_item(ctx);
}
- return svn_error_wrap_apr(status, NULL);
+ return svn_ra_serf__wrap_err(status, NULL);
}
/* feed me! */
@@ -1817,7 +1847,7 @@ handle_response(serf_request_t *request,
&& handler->sline.code != 304)
{
err = svn_error_createf(SVN_ERR_RA_DAV_MALFORMED_DATA,
- svn_error_wrap_apr(status, NULL),
+ svn_ra_serf__wrap_err(status, NULL),
_("Premature EOF seen from server"
" (http status=%d)"),
handler->sline.code);
@@ -1966,7 +1996,8 @@ handle_response(serf_request_t *request,
if (err
&& (!SERF_BUCKET_READ_ERROR(err->apr_err)
- || APR_STATUS_IS_ECONNRESET(err->apr_err)))
+ || APR_STATUS_IS_ECONNRESET(err->apr_err)
+ || APR_STATUS_IS_ECONNABORTED(err->apr_err)))
{
/* These errors are special cased in serf
### We hope no handler returns these by accident. */
@@ -2212,7 +2243,8 @@ svn_ra_serf__discover_vcc(const char **v
/* Now recreate the root_url. */
session->repos_root = session->session_url;
- session->repos_root.path = apr_pstrdup(session->pool, url_buf->data);
+ session->repos_root.path =
+ (char *)svn_fspath__canonicalize(url_buf->data, session->pool);
session->repos_root_str =
svn_urlpath__canonicalize(apr_uri_unparse(session->pool,
&session->repos_root, 0),
@@ -2397,9 +2429,8 @@ expat_response_handler(serf_request_t *r
XML_SetCharacterDataHandler(ectx->parser, expat_cdata);
}
- /* ### should we bail on anything < 200 or >= 300 ??
- ### actually: < 200 should really be handled by the core. */
- if (ectx->handler->sline.code == 404)
+ /* ### TODO: sline.code < 200 should really be handled by the core */
+ if ((ectx->handler->sline.code < 200) || (ectx->handler->sline.code >= 300))
{
/* By deferring to expect_empty_body(), it will make a choice on
how to handle the body. Whatever the decision, the core handler
@@ -2418,7 +2449,7 @@ expat_response_handler(serf_request_t *r
status = serf_bucket_read(response, PARSE_CHUNK_SIZE, &data, &len);
if (SERF_BUCKET_READ_ERROR(status))
- return svn_error_wrap_apr(status, NULL);
+ return svn_ra_serf__wrap_err(status, NULL);
#if 0
/* ### move restart/skip into the core handler */
@@ -2472,7 +2503,7 @@ expat_response_handler(serf_request_t *r
if (status && !SERF_BUCKET_READ_ERROR(status))
{
- return svn_error_wrap_apr(status, NULL);
+ return svn_ra_serf__wrap_err(status, NULL);
}
}
Added: subversion/branches/compressed-pristines/subversion/libsvn_ra_serf/util_error.c
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/libsvn_ra_serf/util_error.c?rev=1413258&view=auto
==============================================================================
--- subversion/branches/compressed-pristines/subversion/libsvn_ra_serf/util_error.c (added)
+++ subversion/branches/compressed-pristines/subversion/libsvn_ra_serf/util_error.c Sat Nov 24 20:29:11 2012
@@ -0,0 +1,100 @@
+/*
+ * util_error.c : serf utility routines for wrapping serf status codes
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ */
+#include <serf.h>
+
+#include "svn_utf.h"
+#include "private/svn_error_private.h"
+
+#include "ra_serf.h"
+
+/*
+ * Undefine the helpers for creating errors.
+ *
+ * *NOTE*: Any use of these functions in any other function may need
+ * to call svn_error__locate() because the macro that would otherwise
+ * do this is being undefined and the filename and line number will
+ * not be properly set in the static error_file and error_line
+ * variables.
+ */
+#undef svn_error_create
+#undef svn_error_createf
+#undef svn_error_quick_wrap
+#undef svn_error_wrap_apr
+#undef svn_ra_serf__wrap_err
+
+svn_error_t *
+svn_ra_serf__wrap_err(apr_status_t status,
+ const char *fmt,
+ ...)
+{
+ const char *serf_err_msg = serf_error_string(status);
+ svn_error_t *err;
+ va_list ap;
+
+ err = svn_error_create(status, NULL, NULL);
+
+ if (serf_err_msg || fmt)
+ {
+ const char *msg;
+ const char *err_msg;
+ char errbuf[255]; /* Buffer for APR error message. */
+
+ if (serf_err_msg)
+ {
+ err_msg = serf_err_msg;
+ }
+ else
+ {
+ svn_error_t *utf8_err;
+
+ /* Grab the APR error message. */
+ apr_strerror(status, errbuf, sizeof(errbuf));
+ utf8_err = svn_utf_cstring_to_utf8(&err_msg, errbuf, err->pool);
+ if (utf8_err)
+ err_msg = NULL;
+ svn_error_clear(utf8_err);
+ }
+
+ /* Append it to the formatted message. */
+ if (fmt)
+ {
+ va_start(ap, fmt);
+ msg = apr_pvsprintf(err->pool, fmt, ap);
+ va_end(ap);
+ }
+ else
+ {
+ msg = "ra_serf";
+ }
+ if (err_msg)
+ {
+ err->message = apr_pstrcat(err->pool, msg, ": ", err_msg, NULL);
+ }
+ else
+ {
+ err->message = msg;
+ }
+ }
+
+ return err;
+}
Modified: subversion/branches/compressed-pristines/subversion/libsvn_ra_serf/xml.c
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/libsvn_ra_serf/xml.c?rev=1413258&r1=1413257&r2=1413258&view=diff
==============================================================================
--- subversion/branches/compressed-pristines/subversion/libsvn_ra_serf/xml.c (original)
+++ subversion/branches/compressed-pristines/subversion/libsvn_ra_serf/xml.c Sat Nov 24 20:29:11 2012
@@ -205,9 +205,23 @@ svn_ra_serf__expand_ns(svn_ra_serf__dav_
}
}
}
+ else
+ {
+ const svn_ra_serf__ns_t *ns;
+
+ for (ns = ns_list; ns; ns = ns->next)
+ {
+ if (! ns->namespace[0])
+ {
+ returned_prop_name->namespace = ns->url;
+ returned_prop_name->name = name;
+ return;
+ }
+ }
+ }
- /* If there is no prefix, or if the prefix is not found, then the
- name is NOT within a namespace. */
+ /* If the prefix is not found, then the name is NOT within a
+ namespace. */
returned_prop_name->namespace = "";
returned_prop_name->name = name;
}