2 * inherited_props.c : ra_serf implementation of svn_ra_get_inherited_props
4 * ====================================================================
5 * Licensed to the Apache Software Foundation (ASF) under one
6 * or more contributor license agreements. See the NOTICE file
7 * distributed with this work for additional information
8 * regarding copyright ownership. The ASF licenses this file
9 * to you under the Apache License, Version 2.0 (the
10 * "License"); you may not use this file except in compliance
11 * with the License. You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing,
16 * software distributed under the License is distributed on an
17 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18 * KIND, either express or implied. See the License for the
19 * specific language governing permissions and limitations
21 * ====================================================================
25 #include <apr_tables.h>
31 #include "svn_string.h"
33 #include "svn_props.h"
34 #include "svn_base64.h"
36 #include "private/svn_dav_protocol.h"
37 #include "../libsvn_ra/ra_loader.h"
38 #include "svn_private_config.h"
42 /* The current state of our XML parsing. */
43 typedef enum iprops_state_e {
52 /* Struct for accumulating inherited props. */
53 typedef struct iprops_context_t {
54 /* The depth-first ordered array of svn_prop_inherited_item_t *
55 structures we are building. */
56 apr_array_header_t *iprops;
58 /* Pool in which to allocate elements of IPROPS. */
61 /* The repository's root URL. */
62 const char *repos_root_url;
64 /* Current property name */
65 svn_stringbuf_t *curr_propname;
67 /* Current element in IPROPS. */
68 svn_prop_inherited_item_t *curr_iprop;
70 /* Path we are finding inherited properties for. This is relative to
71 the RA session passed to svn_ra_serf__get_inherited_props. */
73 /* The revision of PATH*/
74 svn_revnum_t revision;
77 #define S_ SVN_XML_NAMESPACE
78 static const svn_ra_serf__xml_transition_t iprops_table[] = {
79 { INITIAL, S_, SVN_DAV__INHERITED_PROPS_REPORT, IPROPS_REPORT,
80 FALSE, { NULL }, FALSE },
82 { IPROPS_REPORT, S_, SVN_DAV__IPROP_ITEM, IPROPS_ITEM,
83 FALSE, { NULL }, TRUE },
85 { IPROPS_ITEM, S_, SVN_DAV__IPROP_PATH, IPROPS_PATH,
86 TRUE, { NULL }, TRUE },
88 { IPROPS_ITEM, S_, SVN_DAV__IPROP_PROPNAME, IPROPS_PROPNAME,
89 TRUE, { NULL }, TRUE },
91 { IPROPS_ITEM, S_, SVN_DAV__IPROP_PROPVAL, IPROPS_PROPVAL,
92 TRUE, { "?V:encoding", NULL }, TRUE },
97 /* Conforms to svn_ra_serf__xml_opened_t */
99 iprops_opened(svn_ra_serf__xml_estate_t *xes,
102 const svn_ra_serf__dav_props_t *tag,
103 apr_pool_t *scratch_pool)
105 iprops_context_t *iprops_ctx = baton;
107 if (entered_state == IPROPS_ITEM)
109 svn_stringbuf_setempty(iprops_ctx->curr_propname);
111 iprops_ctx->curr_iprop = apr_pcalloc(iprops_ctx->pool,
112 sizeof(*iprops_ctx->curr_iprop));
114 iprops_ctx->curr_iprop->prop_hash = apr_hash_make(iprops_ctx->pool);
119 /* Conforms to svn_ra_serf__xml_closed_t */
121 iprops_closed(svn_ra_serf__xml_estate_t *xes,
124 const svn_string_t *cdata,
126 apr_pool_t *scratch_pool)
128 iprops_context_t *iprops_ctx = baton;
130 if (leaving_state == IPROPS_ITEM)
132 APR_ARRAY_PUSH(iprops_ctx->iprops, svn_prop_inherited_item_t *) =
133 iprops_ctx->curr_iprop;
135 iprops_ctx->curr_iprop = NULL;
137 else if (leaving_state == IPROPS_PATH)
139 /* Every <iprop-item> has a single <iprop-path> */
140 if (iprops_ctx->curr_iprop->path_or_url)
141 return svn_error_create(SVN_ERR_XML_MALFORMED, NULL, NULL);
143 iprops_ctx->curr_iprop->path_or_url =
144 svn_path_url_add_component2(iprops_ctx->repos_root_url,
148 else if (leaving_state == IPROPS_PROPNAME)
150 if (iprops_ctx->curr_propname->len)
151 return svn_error_create(SVN_ERR_XML_MALFORMED, NULL, NULL);
153 /* Store propname for value */
154 svn_stringbuf_set(iprops_ctx->curr_propname, cdata->data);
156 else if (leaving_state == IPROPS_PROPVAL)
158 const char *encoding;
159 const svn_string_t *val_str;
161 if (! iprops_ctx->curr_propname->len)
162 return svn_error_create(SVN_ERR_XML_MALFORMED, NULL, NULL);
164 encoding = svn_hash_gets(attrs, "V:encoding");
168 if (strcmp(encoding, "base64") != 0)
169 return svn_error_createf(SVN_ERR_XML_MALFORMED,
171 _("Got unrecognized encoding '%s'"),
174 /* Decode into the right pool. */
175 val_str = svn_base64_decode_string(cdata, iprops_ctx->pool);
179 /* Copy into the right pool. */
180 val_str = svn_string_dup(cdata, iprops_ctx->pool);
183 svn_hash_sets(iprops_ctx->curr_iprop->prop_hash,
184 apr_pstrdup(iprops_ctx->pool,
185 iprops_ctx->curr_propname->data),
187 /* Clear current propname. */
188 svn_stringbuf_setempty(iprops_ctx->curr_propname);
191 SVN_ERR_MALFUNCTION(); /* Invalid transition table */
197 create_iprops_body(serf_bucket_t **bkt,
199 serf_bucket_alloc_t *alloc,
202 iprops_context_t *iprops_ctx = baton;
203 serf_bucket_t *body_bkt;
205 body_bkt = serf_bucket_aggregate_create(alloc);
207 svn_ra_serf__add_open_tag_buckets(body_bkt, alloc,
208 "S:" SVN_DAV__INHERITED_PROPS_REPORT,
209 "xmlns:S", SVN_XML_NAMESPACE,
211 svn_ra_serf__add_tag_buckets(body_bkt,
212 "S:" SVN_DAV__REVISION,
213 apr_ltoa(pool, iprops_ctx->revision),
215 svn_ra_serf__add_tag_buckets(body_bkt, "S:" SVN_DAV__PATH,
216 iprops_ctx->path, alloc);
217 svn_ra_serf__add_close_tag_buckets(body_bkt, alloc,
218 "S:" SVN_DAV__INHERITED_PROPS_REPORT);
223 /* Request a inherited-props-report from the URL attached to RA_SESSION,
224 and fill the IPROPS array hash with the results. */
226 svn_ra_serf__get_inherited_props(svn_ra_session_t *ra_session,
227 apr_array_header_t **iprops,
229 svn_revnum_t revision,
230 apr_pool_t *result_pool,
231 apr_pool_t *scratch_pool)
234 iprops_context_t *iprops_ctx;
235 svn_ra_serf__session_t *session = ra_session->priv;
236 svn_ra_serf__handler_t *handler;
237 svn_ra_serf__xml_context_t *xmlctx;
240 SVN_ERR(svn_ra_serf__get_stable_url(&req_url,
241 NULL /* latest_revnum */,
246 result_pool, scratch_pool));
248 SVN_ERR_ASSERT(session->repos_root_str);
250 iprops_ctx = apr_pcalloc(scratch_pool, sizeof(*iprops_ctx));
251 iprops_ctx->repos_root_url = session->repos_root_str;
252 iprops_ctx->pool = result_pool;
253 iprops_ctx->curr_propname = svn_stringbuf_create_empty(scratch_pool);
254 iprops_ctx->curr_iprop = NULL;
255 iprops_ctx->iprops = apr_array_make(result_pool, 1,
256 sizeof(svn_prop_inherited_item_t *));
257 iprops_ctx->path = path;
258 iprops_ctx->revision = revision;
260 xmlctx = svn_ra_serf__xml_context_create(iprops_table,
261 iprops_opened, iprops_closed, NULL,
264 handler = svn_ra_serf__create_expat_handler(xmlctx, scratch_pool);
266 handler->method = "REPORT";
267 handler->path = req_url;
268 handler->conn = session->conns[0];
269 handler->session = session;
270 handler->body_delegate = create_iprops_body;
271 handler->body_delegate_baton = iprops_ctx;
272 handler->body_type = "text/xml";
273 handler->handler_pool = scratch_pool;
275 err = svn_ra_serf__context_run_one(handler, scratch_pool);
276 SVN_ERR(svn_error_compose_create(
277 svn_ra_serf__error_on_status(handler->sline,
282 *iprops = iprops_ctx->iprops;