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.c285
1 files changed, 285 insertions, 0 deletions
diff --git a/subversion/libsvn_ra_serf/inherited_props.c b/subversion/libsvn_ra_serf/inherited_props.c
new file mode 100644
index 0000000..f1172e7
--- /dev/null
+++ b/subversion/libsvn_ra_serf/inherited_props.c
@@ -0,0 +1,285 @@
+/*
+ * 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_hash.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 {
+ INITIAL = 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 property name */
+ svn_stringbuf_t *curr_propname;
+
+ /* Current element in IPROPS. */
+ svn_prop_inherited_item_t *curr_iprop;
+
+ /* 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;
+
+#define S_ SVN_XML_NAMESPACE
+static const svn_ra_serf__xml_transition_t iprops_table[] = {
+ { INITIAL, S_, SVN_DAV__INHERITED_PROPS_REPORT, IPROPS_REPORT,
+ FALSE, { NULL }, FALSE },
+
+ { IPROPS_REPORT, S_, SVN_DAV__IPROP_ITEM, IPROPS_ITEM,
+ FALSE, { NULL }, TRUE },
+
+ { IPROPS_ITEM, S_, SVN_DAV__IPROP_PATH, IPROPS_PATH,
+ TRUE, { NULL }, TRUE },
+
+ { IPROPS_ITEM, S_, SVN_DAV__IPROP_PROPNAME, IPROPS_PROPNAME,
+ TRUE, { NULL }, TRUE },
+
+ { IPROPS_ITEM, S_, SVN_DAV__IPROP_PROPVAL, IPROPS_PROPVAL,
+ TRUE, { "?V:encoding", NULL }, TRUE },
+
+ { 0 }
+};
+
+/* Conforms to svn_ra_serf__xml_opened_t */
+static svn_error_t *
+iprops_opened(svn_ra_serf__xml_estate_t *xes,
+ void *baton,
+ int entered_state,
+ const svn_ra_serf__dav_props_t *tag,
+ apr_pool_t *scratch_pool)
+{
+ iprops_context_t *iprops_ctx = baton;
+
+ if (entered_state == IPROPS_ITEM)
+ {
+ svn_stringbuf_setempty(iprops_ctx->curr_propname);
+
+ iprops_ctx->curr_iprop = apr_pcalloc(iprops_ctx->pool,
+ sizeof(*iprops_ctx->curr_iprop));
+
+ iprops_ctx->curr_iprop->prop_hash = apr_hash_make(iprops_ctx->pool);
+ }
+ return SVN_NO_ERROR;
+}
+
+/* Conforms to svn_ra_serf__xml_closed_t */
+static svn_error_t *
+iprops_closed(svn_ra_serf__xml_estate_t *xes,
+ void *baton,
+ int leaving_state,
+ const svn_string_t *cdata,
+ apr_hash_t *attrs,
+ apr_pool_t *scratch_pool)
+{
+ iprops_context_t *iprops_ctx = baton;
+
+ if (leaving_state == IPROPS_ITEM)
+ {
+ APR_ARRAY_PUSH(iprops_ctx->iprops, svn_prop_inherited_item_t *) =
+ iprops_ctx->curr_iprop;
+
+ iprops_ctx->curr_iprop = NULL;
+ }
+ else if (leaving_state == IPROPS_PATH)
+ {
+ /* Every <iprop-item> has a single <iprop-path> */
+ if (iprops_ctx->curr_iprop->path_or_url)
+ 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);
+ }
+ else if (leaving_state == IPROPS_PROPNAME)
+ {
+ if (iprops_ctx->curr_propname->len)
+ return svn_error_create(SVN_ERR_XML_MALFORMED, NULL, NULL);
+
+ /* Store propname for value */
+ svn_stringbuf_set(iprops_ctx->curr_propname, cdata->data);
+ }
+ else if (leaving_state == IPROPS_PROPVAL)
+ {
+ const char *encoding;
+ const svn_string_t *val_str;
+
+ if (! iprops_ctx->curr_propname->len)
+ return svn_error_create(SVN_ERR_XML_MALFORMED, NULL, NULL);
+
+ encoding = svn_hash_gets(attrs, "V:encoding");
+
+ if (encoding)
+ {
+ if (strcmp(encoding, "base64") != 0)
+ return svn_error_createf(SVN_ERR_XML_MALFORMED,
+ NULL,
+ _("Got unrecognized encoding '%s'"),
+ encoding);
+
+ /* Decode into the right pool. */
+ val_str = svn_base64_decode_string(cdata, iprops_ctx->pool);
+ }
+ else
+ {
+ /* Copy into the right pool. */
+ val_str = svn_string_dup(cdata, iprops_ctx->pool);
+ }
+
+ svn_hash_sets(iprops_ctx->curr_iprop->prop_hash,
+ apr_pstrdup(iprops_ctx->pool,
+ iprops_ctx->curr_propname->data),
+ val_str);
+ /* Clear current propname. */
+ svn_stringbuf_setempty(iprops_ctx->curr_propname);
+ }
+ else
+ SVN_ERR_MALFUNCTION(); /* Invalid transition table */
+
+ 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;
+ 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_ERR(svn_ra_serf__get_stable_url(&req_url,
+ NULL /* latest_revnum */,
+ session,
+ NULL /* conn */,
+ NULL /* url */,
+ revision,
+ result_pool, scratch_pool));
+
+ SVN_ERR_ASSERT(session->repos_root_str);
+
+ iprops_ctx = apr_pcalloc(scratch_pool, sizeof(*iprops_ctx));
+ iprops_ctx->repos_root_url = session->repos_root_str;
+ iprops_ctx->pool = result_pool;
+ iprops_ctx->curr_propname = 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;
+
+ xmlctx = svn_ra_serf__xml_context_create(iprops_table,
+ iprops_opened, iprops_closed, NULL,
+ iprops_ctx,
+ scratch_pool);
+ handler = svn_ra_serf__create_expat_handler(xmlctx, 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));
+
+ *iprops = iprops_ctx->iprops;
+
+ return SVN_NO_ERROR;
+}