summaryrefslogtreecommitdiff
path: root/subversion/libsvn_ra_serf/inherited_props.c
diff options
context:
space:
mode:
Diffstat (limited to 'subversion/libsvn_ra_serf/inherited_props.c')
-rw-r--r--subversion/libsvn_ra_serf/inherited_props.c199
1 files changed, 178 insertions, 21 deletions
diff --git a/subversion/libsvn_ra_serf/inherited_props.c b/subversion/libsvn_ra_serf/inherited_props.c
index f1172e7..6edafb1 100644
--- a/subversion/libsvn_ra_serf/inherited_props.c
+++ b/subversion/libsvn_ra_serf/inherited_props.c
@@ -28,12 +28,14 @@
#include "svn_hash.h"
#include "svn_path.h"
#include "svn_ra.h"
+#include "svn_sorts.h"
#include "svn_string.h"
#include "svn_xml.h"
#include "svn_props.h"
#include "svn_base64.h"
#include "private/svn_dav_protocol.h"
+#include "private/svn_sorts_private.h"
#include "../libsvn_ra/ra_loader.h"
#include "svn_private_config.h"
#include "ra_serf.h"
@@ -41,7 +43,7 @@
/* The current state of our XML parsing. */
typedef enum iprops_state_e {
- INITIAL = 0,
+ INITIAL = XML_STATE_INITIAL,
IPROPS_REPORT,
IPROPS_ITEM,
IPROPS_PATH,
@@ -141,9 +143,7 @@ iprops_closed(svn_ra_serf__xml_estate_t *xes,
return svn_error_create(SVN_ERR_XML_MALFORMED, NULL, NULL);
iprops_ctx->curr_iprop->path_or_url =
- svn_path_url_add_component2(iprops_ctx->repos_root_url,
- cdata->data,
- iprops_ctx->pool);
+ apr_pstrdup(iprops_ctx->pool, cdata->data);
}
else if (leaving_state == IPROPS_PROPNAME)
{
@@ -197,7 +197,8 @@ static svn_error_t *
create_iprops_body(serf_bucket_t **bkt,
void *baton,
serf_bucket_alloc_t *alloc,
- apr_pool_t *pool)
+ apr_pool_t *pool /* request pool */,
+ apr_pool_t *scratch_pool)
{
iprops_context_t *iprops_ctx = baton;
serf_bucket_t *body_bkt;
@@ -207,7 +208,7 @@ create_iprops_body(serf_bucket_t **bkt,
svn_ra_serf__add_open_tag_buckets(body_bkt, alloc,
"S:" SVN_DAV__INHERITED_PROPS_REPORT,
"xmlns:S", SVN_XML_NAMESPACE,
- NULL);
+ SVN_VA_NULL);
svn_ra_serf__add_tag_buckets(body_bkt,
"S:" SVN_DAV__REVISION,
apr_ltoa(pool, iprops_ctx->revision),
@@ -220,6 +221,131 @@ create_iprops_body(serf_bucket_t **bkt,
return SVN_NO_ERROR;
}
+/* Per request information for get_iprops_via_more_requests */
+typedef struct iprop_rq_info_t
+{
+ const char *relpath;
+ const char *urlpath;
+ apr_hash_t *props;
+ svn_ra_serf__handler_t *handler;
+} iprop_rq_info_t;
+
+
+/* Assumes session reparented to the repository root. The old session
+ root is passed as session_url */
+static svn_error_t *
+get_iprops_via_more_requests(svn_ra_session_t *ra_session,
+ apr_array_header_t **iprops,
+ const char *session_url,
+ const char *path,
+ svn_revnum_t revision,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ svn_ra_serf__session_t *session = ra_session->priv;
+ const char *url;
+ const char *relpath;
+ apr_array_header_t *rq_info;
+ apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+ apr_interval_time_t waittime_left = session->timeout;
+ const svn_revnum_t rev_marker = SVN_INVALID_REVNUM;
+ int i;
+
+ rq_info = apr_array_make(scratch_pool, 16, sizeof(iprop_rq_info_t *));
+
+ if (!svn_path_is_empty(path))
+ url = svn_path_url_add_component2(session_url, path, scratch_pool);
+ else
+ url = session_url;
+
+ relpath = svn_uri_skip_ancestor(session->repos_root_str, url, scratch_pool);
+
+ /* Create all requests */
+ while (relpath[0] != '\0')
+ {
+ iprop_rq_info_t *rq = apr_pcalloc(scratch_pool, sizeof(*rq));
+
+ relpath = svn_relpath_dirname(relpath, scratch_pool);
+
+ rq->relpath = relpath;
+ rq->props = apr_hash_make(scratch_pool);
+
+ SVN_ERR(svn_ra_serf__get_stable_url(&rq->urlpath, NULL, session,
+ svn_path_url_add_component2(
+ session->repos_root.path,
+ relpath, scratch_pool),
+ revision,
+ scratch_pool, scratch_pool));
+
+ SVN_ERR(svn_ra_serf__create_propfind_handler(
+ &rq->handler, session,
+ rq->urlpath,
+ rev_marker, "0", all_props,
+ svn_ra_serf__deliver_svn_props,
+ rq->props,
+ scratch_pool));
+
+ /* Allow ignoring authz problems */
+ rq->handler->no_fail_on_http_failure_status = TRUE;
+
+ svn_ra_serf__request_create(rq->handler);
+
+ APR_ARRAY_PUSH(rq_info, iprop_rq_info_t *) = rq;
+ }
+
+ while (TRUE)
+ {
+ svn_pool_clear(iterpool);
+
+ SVN_ERR(svn_ra_serf__context_run(session, &waittime_left, iterpool));
+
+ for (i = 0; i < rq_info->nelts; i++)
+ {
+ iprop_rq_info_t *rq = APR_ARRAY_IDX(rq_info, i, iprop_rq_info_t *);
+
+ if (!rq->handler->done)
+ break;
+ }
+
+ if (i >= rq_info->nelts)
+ break; /* All requests done */
+ }
+
+ *iprops = apr_array_make(result_pool, rq_info->nelts,
+ sizeof(svn_prop_inherited_item_t *));
+
+ /* And now create the result set */
+ for (i = 0; i < rq_info->nelts; i++)
+ {
+ iprop_rq_info_t *rq = APR_ARRAY_IDX(rq_info, i, iprop_rq_info_t *);
+ apr_hash_t *node_props;
+ svn_prop_inherited_item_t *new_iprop;
+
+ if (rq->handler->sline.code != 207 && rq->handler->sline.code != 403)
+ {
+ if (rq->handler->server_error)
+ SVN_ERR(svn_ra_serf__server_error_create(rq->handler,
+ scratch_pool));
+
+ return svn_error_trace(svn_ra_serf__unexpected_status(rq->handler));
+ }
+
+ node_props = rq->props;
+
+ svn_ra_serf__keep_only_regular_props(node_props, scratch_pool);
+
+ if (!apr_hash_count(node_props))
+ continue;
+
+ new_iprop = apr_palloc(result_pool, sizeof(*new_iprop));
+ new_iprop->path_or_url = apr_pstrdup(result_pool, rq->relpath);
+ new_iprop->prop_hash = svn_prop_hash_dup(node_props, result_pool);
+ svn_sort__array_insert(*iprops, &new_iprop, 0);
+ }
+
+ return SVN_NO_ERROR;
+}
+
/* Request a inherited-props-report from the URL attached to RA_SESSION,
and fill the IPROPS array hash with the results. */
svn_error_t *
@@ -230,20 +356,53 @@ svn_ra_serf__get_inherited_props(svn_ra_session_t *ra_session,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
- svn_error_t *err;
iprops_context_t *iprops_ctx;
svn_ra_serf__session_t *session = ra_session->priv;
svn_ra_serf__handler_t *handler;
svn_ra_serf__xml_context_t *xmlctx;
const char *req_url;
+ svn_boolean_t iprop_capable;
+
+ SVN_ERR(svn_ra_serf__has_capability(ra_session, &iprop_capable,
+ SVN_RA_CAPABILITY_INHERITED_PROPS,
+ scratch_pool));
+
+ if (!iprop_capable)
+ {
+ svn_error_t *err;
+ const char *reparent_uri = NULL;
+ const char *session_uri;
+ const char *repos_root_url;
+
+ SVN_ERR(svn_ra_serf__get_repos_root(ra_session, &repos_root_url,
+ scratch_pool));
+
+ session_uri = apr_pstrdup(scratch_pool, session->session_url_str);
+ if (strcmp(repos_root_url, session->session_url_str) != 0)
+ {
+ reparent_uri = session_uri;
+ SVN_ERR(svn_ra_serf__reparent(ra_session, repos_root_url,
+ scratch_pool));
+ }
+
+ err = get_iprops_via_more_requests(ra_session, iprops, session_uri, path,
+ revision, result_pool, scratch_pool);
+
+ if (reparent_uri)
+ err = svn_error_compose_create(err,
+ svn_ra_serf__reparent(ra_session,
+ reparent_uri ,
+ scratch_pool));
+
+ return svn_error_trace(err);
+ }
SVN_ERR(svn_ra_serf__get_stable_url(&req_url,
NULL /* latest_revnum */,
session,
- NULL /* conn */,
NULL /* url */,
revision,
- result_pool, scratch_pool));
+ scratch_pool, scratch_pool));
SVN_ERR_ASSERT(session->repos_root_str);
@@ -258,26 +417,24 @@ svn_ra_serf__get_inherited_props(svn_ra_session_t *ra_session,
iprops_ctx->revision = revision;
xmlctx = svn_ra_serf__xml_context_create(iprops_table,
- iprops_opened, iprops_closed, NULL,
+ iprops_opened, iprops_closed,
+ NULL,
iprops_ctx,
scratch_pool);
- handler = svn_ra_serf__create_expat_handler(xmlctx, scratch_pool);
+ handler = svn_ra_serf__create_expat_handler(session, xmlctx, NULL,
+ scratch_pool);
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;
-
- err = svn_ra_serf__context_run_one(handler, scratch_pool);
- SVN_ERR(svn_error_compose_create(
- svn_ra_serf__error_on_status(handler->sline,
- handler->path,
- handler->location),
- err));
+
+ SVN_ERR(svn_ra_serf__context_run_one(handler, scratch_pool));
+
+ if (handler->sline.code != 200)
+ return svn_error_trace(svn_ra_serf__unexpected_status(handler));
*iprops = iprops_ctx->iprops;