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 CDATA values*/
65 svn_stringbuf_t *curr_path;
66 svn_stringbuf_t *curr_propname;
67 svn_stringbuf_t *curr_propval;
68 const char *curr_prop_val_encoding;
70 /* Current element in IPROPS. */
71 svn_prop_inherited_item_t *curr_iprop;
73 /* Serf context completion flag for svn_ra_serf__context_run_wait() */
76 /* Path we are finding inherited properties for. This is relative to
77 the RA session passed to svn_ra_serf__get_inherited_props. */
79 /* The revision of PATH*/
80 svn_revnum_t revision;
84 start_element(svn_ra_serf__xml_parser_t *parser,
85 svn_ra_serf__dav_props_t name,
87 apr_pool_t *scratch_pool)
89 iprops_context_t *iprops_ctx = parser->user_data;
92 state = parser->state->current_state;
94 && strcmp(name.name, SVN_DAV__INHERITED_PROPS_REPORT) == 0)
96 svn_ra_serf__xml_push_state(parser, IPROPS_REPORT);
98 else if (state == IPROPS_REPORT &&
99 strcmp(name.name, SVN_DAV__IPROP_ITEM) == 0)
101 svn_stringbuf_setempty(iprops_ctx->curr_path);
102 svn_stringbuf_setempty(iprops_ctx->curr_propname);
103 svn_stringbuf_setempty(iprops_ctx->curr_propval);
104 iprops_ctx->curr_prop_val_encoding = NULL;
105 iprops_ctx->curr_iprop = NULL;
106 svn_ra_serf__xml_push_state(parser, IPROPS_ITEM);
108 else if (state == IPROPS_ITEM &&
109 strcmp(name.name, SVN_DAV__IPROP_PROPVAL) == 0)
111 const char *prop_val_encoding = svn_xml_get_attr_value("encoding",
113 iprops_ctx->curr_prop_val_encoding = apr_pstrdup(iprops_ctx->pool,
115 svn_ra_serf__xml_push_state(parser, IPROPS_PROPVAL);
117 else if (state == IPROPS_ITEM &&
118 strcmp(name.name, SVN_DAV__IPROP_PATH) == 0)
120 svn_ra_serf__xml_push_state(parser, IPROPS_PATH);
122 else if (state == IPROPS_ITEM &&
123 strcmp(name.name, SVN_DAV__IPROP_PROPNAME) == 0)
125 svn_ra_serf__xml_push_state(parser, IPROPS_PROPNAME);
127 else if (state == IPROPS_ITEM &&
128 strcmp(name.name, SVN_DAV__IPROP_PROPVAL) == 0)
130 svn_ra_serf__xml_push_state(parser, IPROPS_PROPVAL);
137 end_element(svn_ra_serf__xml_parser_t *parser,
138 svn_ra_serf__dav_props_t name,
139 apr_pool_t *scratch_pool)
141 iprops_context_t *iprops_ctx = parser->user_data;
142 iprops_state_e state;
144 state = parser->state->current_state;
146 if (state == IPROPS_REPORT &&
147 strcmp(name.name, SVN_DAV__INHERITED_PROPS_REPORT) == 0)
149 svn_ra_serf__xml_pop_state(parser);
151 else if (state == IPROPS_PATH
152 && strcmp(name.name, SVN_DAV__IPROP_PATH) == 0)
154 iprops_ctx->curr_iprop = apr_palloc(
155 iprops_ctx->pool, sizeof(svn_prop_inherited_item_t));
157 iprops_ctx->curr_iprop->path_or_url =
158 svn_path_url_add_component2(iprops_ctx->repos_root_url,
159 iprops_ctx->curr_path->data,
161 iprops_ctx->curr_iprop->prop_hash = apr_hash_make(iprops_ctx->pool);
162 svn_ra_serf__xml_pop_state(parser);
164 else if (state == IPROPS_PROPVAL
165 && strcmp(name.name, SVN_DAV__IPROP_PROPVAL) == 0)
167 const svn_string_t *prop_val;
169 if (iprops_ctx->curr_prop_val_encoding)
171 svn_string_t encoded_prop_val;
173 if (strcmp(iprops_ctx->curr_prop_val_encoding, "base64") != 0)
174 return svn_error_create(SVN_ERR_XML_MALFORMED, NULL, NULL);
176 encoded_prop_val.data = iprops_ctx->curr_propval->data;
177 encoded_prop_val.len = iprops_ctx->curr_propval->len;
178 prop_val = svn_base64_decode_string(&encoded_prop_val,
183 prop_val = svn_string_create_from_buf(iprops_ctx->curr_propval,
187 svn_hash_sets(iprops_ctx->curr_iprop->prop_hash,
188 apr_pstrdup(iprops_ctx->pool,
189 iprops_ctx->curr_propname->data),
191 /* Clear current propname and propval in the event there are
192 multiple properties on the current path. */
193 svn_stringbuf_setempty(iprops_ctx->curr_propname);
194 svn_stringbuf_setempty(iprops_ctx->curr_propval);
195 svn_ra_serf__xml_pop_state(parser);
197 else if (state == IPROPS_PROPNAME
198 && strcmp(name.name, SVN_DAV__IPROP_PROPNAME) == 0)
200 svn_ra_serf__xml_pop_state(parser);
202 else if (state == IPROPS_ITEM
203 && strcmp(name.name, SVN_DAV__IPROP_ITEM) == 0)
205 APR_ARRAY_PUSH(iprops_ctx->iprops, svn_prop_inherited_item_t *) =
206 iprops_ctx->curr_iprop;
207 svn_ra_serf__xml_pop_state(parser);
214 cdata_handler(svn_ra_serf__xml_parser_t *parser,
217 apr_pool_t *scratch_pool)
219 iprops_context_t *iprops_ctx = parser->user_data;
220 iprops_state_e state = parser->state->current_state;
225 svn_stringbuf_appendbytes(iprops_ctx->curr_path, data, len);
228 case IPROPS_PROPNAME:
229 svn_stringbuf_appendbytes(iprops_ctx->curr_propname, data, len);
233 svn_stringbuf_appendbytes(iprops_ctx->curr_propval, data, len);
244 create_iprops_body(serf_bucket_t **bkt,
246 serf_bucket_alloc_t *alloc,
249 iprops_context_t *iprops_ctx = baton;
250 serf_bucket_t *body_bkt;
252 body_bkt = serf_bucket_aggregate_create(alloc);
254 svn_ra_serf__add_open_tag_buckets(body_bkt, alloc,
255 "S:" SVN_DAV__INHERITED_PROPS_REPORT,
256 "xmlns:S", SVN_XML_NAMESPACE,
258 svn_ra_serf__add_tag_buckets(body_bkt,
259 "S:" SVN_DAV__REVISION,
260 apr_ltoa(pool, iprops_ctx->revision),
262 svn_ra_serf__add_tag_buckets(body_bkt, "S:" SVN_DAV__PATH,
263 iprops_ctx->path, alloc);
264 svn_ra_serf__add_close_tag_buckets(body_bkt, alloc,
265 "S:" SVN_DAV__INHERITED_PROPS_REPORT);
270 /* Request a inherited-props-report from the URL attached to RA_SESSION,
271 and fill the IPROPS array hash with the results. */
273 svn_ra_serf__get_inherited_props(svn_ra_session_t *ra_session,
274 apr_array_header_t **iprops,
276 svn_revnum_t revision,
277 apr_pool_t *result_pool,
278 apr_pool_t *scratch_pool)
281 iprops_context_t *iprops_ctx;
282 svn_ra_serf__session_t *session = ra_session->priv;
283 svn_ra_serf__handler_t *handler;
284 svn_ra_serf__xml_parser_t *parser_ctx;
287 SVN_ERR(svn_ra_serf__get_stable_url(&req_url,
288 NULL /* latest_revnum */,
293 result_pool, scratch_pool));
295 SVN_ERR_ASSERT(session->repos_root_str);
297 iprops_ctx = apr_pcalloc(scratch_pool, sizeof(*iprops_ctx));
298 iprops_ctx->done = FALSE;
299 iprops_ctx->repos_root_url = session->repos_root_str;
300 iprops_ctx->pool = result_pool;
301 iprops_ctx->curr_path = svn_stringbuf_create_empty(scratch_pool);
302 iprops_ctx->curr_propname = svn_stringbuf_create_empty(scratch_pool);
303 iprops_ctx->curr_propval = svn_stringbuf_create_empty(scratch_pool);
304 iprops_ctx->curr_iprop = NULL;
305 iprops_ctx->iprops = apr_array_make(result_pool, 1,
306 sizeof(svn_prop_inherited_item_t *));
307 iprops_ctx->path = path;
308 iprops_ctx->revision = revision;
310 handler = apr_pcalloc(scratch_pool, sizeof(*handler));
312 handler->method = "REPORT";
313 handler->path = req_url;
314 handler->conn = session->conns[0];
315 handler->session = session;
316 handler->body_delegate = create_iprops_body;
317 handler->body_delegate_baton = iprops_ctx;
318 handler->body_type = "text/xml";
319 handler->handler_pool = scratch_pool;
321 parser_ctx = apr_pcalloc(scratch_pool, sizeof(*parser_ctx));
323 parser_ctx->pool = scratch_pool;
324 parser_ctx->user_data = iprops_ctx;
325 parser_ctx->start = start_element;
326 parser_ctx->end = end_element;
327 parser_ctx->cdata = cdata_handler;
328 parser_ctx->done = &iprops_ctx->done;
330 handler->response_handler = svn_ra_serf__handle_xml_parser;
331 handler->response_baton = parser_ctx;
333 err = svn_ra_serf__context_run_one(handler, scratch_pool);
334 SVN_ERR(svn_error_compose_create(
335 svn_ra_serf__error_on_status(handler->sline,
340 if (iprops_ctx->done)
341 *iprops = iprops_ctx->iprops;