1251881Speter/* 2251881Speter * inherited_props.c : ra_serf implementation of svn_ra_get_inherited_props 3251881Speter * 4251881Speter * ==================================================================== 5251881Speter * Licensed to the Apache Software Foundation (ASF) under one 6251881Speter * or more contributor license agreements. See the NOTICE file 7251881Speter * distributed with this work for additional information 8251881Speter * regarding copyright ownership. The ASF licenses this file 9251881Speter * to you under the Apache License, Version 2.0 (the 10251881Speter * "License"); you may not use this file except in compliance 11251881Speter * with the License. You may obtain a copy of the License at 12251881Speter * 13251881Speter * http://www.apache.org/licenses/LICENSE-2.0 14251881Speter * 15251881Speter * Unless required by applicable law or agreed to in writing, 16251881Speter * software distributed under the License is distributed on an 17251881Speter * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 18251881Speter * KIND, either express or implied. See the License for the 19251881Speter * specific language governing permissions and limitations 20251881Speter * under the License. 21251881Speter * ==================================================================== 22251881Speter */ 23251881Speter 24251881Speter 25251881Speter#include <apr_tables.h> 26251881Speter#include <apr_xml.h> 27251881Speter 28251881Speter#include "svn_hash.h" 29251881Speter#include "svn_path.h" 30251881Speter#include "svn_ra.h" 31251881Speter#include "svn_string.h" 32251881Speter#include "svn_xml.h" 33251881Speter#include "svn_props.h" 34251881Speter#include "svn_base64.h" 35251881Speter 36251881Speter#include "private/svn_dav_protocol.h" 37251881Speter#include "../libsvn_ra/ra_loader.h" 38251881Speter#include "svn_private_config.h" 39251881Speter#include "ra_serf.h" 40251881Speter 41251881Speter 42251881Speter/* The current state of our XML parsing. */ 43251881Spetertypedef enum iprops_state_e { 44269847Speter INITIAL = 0, 45251881Speter IPROPS_REPORT, 46251881Speter IPROPS_ITEM, 47251881Speter IPROPS_PATH, 48251881Speter IPROPS_PROPNAME, 49251881Speter IPROPS_PROPVAL 50251881Speter} iprops_state_e; 51251881Speter 52251881Speter/* Struct for accumulating inherited props. */ 53251881Spetertypedef struct iprops_context_t { 54251881Speter /* The depth-first ordered array of svn_prop_inherited_item_t * 55251881Speter structures we are building. */ 56251881Speter apr_array_header_t *iprops; 57251881Speter 58251881Speter /* Pool in which to allocate elements of IPROPS. */ 59251881Speter apr_pool_t *pool; 60251881Speter 61251881Speter /* The repository's root URL. */ 62251881Speter const char *repos_root_url; 63251881Speter 64269847Speter /* Current property name */ 65251881Speter svn_stringbuf_t *curr_propname; 66251881Speter 67251881Speter /* Current element in IPROPS. */ 68251881Speter svn_prop_inherited_item_t *curr_iprop; 69251881Speter 70251881Speter /* Path we are finding inherited properties for. This is relative to 71251881Speter the RA session passed to svn_ra_serf__get_inherited_props. */ 72251881Speter const char *path; 73251881Speter /* The revision of PATH*/ 74251881Speter svn_revnum_t revision; 75251881Speter} iprops_context_t; 76251881Speter 77269847Speter#define S_ SVN_XML_NAMESPACE 78269847Speterstatic const svn_ra_serf__xml_transition_t iprops_table[] = { 79269847Speter { INITIAL, S_, SVN_DAV__INHERITED_PROPS_REPORT, IPROPS_REPORT, 80269847Speter FALSE, { NULL }, FALSE }, 81269847Speter 82269847Speter { IPROPS_REPORT, S_, SVN_DAV__IPROP_ITEM, IPROPS_ITEM, 83269847Speter FALSE, { NULL }, TRUE }, 84269847Speter 85269847Speter { IPROPS_ITEM, S_, SVN_DAV__IPROP_PATH, IPROPS_PATH, 86269847Speter TRUE, { NULL }, TRUE }, 87269847Speter 88269847Speter { IPROPS_ITEM, S_, SVN_DAV__IPROP_PROPNAME, IPROPS_PROPNAME, 89269847Speter TRUE, { NULL }, TRUE }, 90269847Speter 91269847Speter { IPROPS_ITEM, S_, SVN_DAV__IPROP_PROPVAL, IPROPS_PROPVAL, 92269847Speter TRUE, { "?V:encoding", NULL }, TRUE }, 93269847Speter 94269847Speter { 0 } 95269847Speter}; 96269847Speter 97269847Speter/* Conforms to svn_ra_serf__xml_opened_t */ 98251881Speterstatic svn_error_t * 99269847Speteriprops_opened(svn_ra_serf__xml_estate_t *xes, 100269847Speter void *baton, 101269847Speter int entered_state, 102269847Speter const svn_ra_serf__dav_props_t *tag, 103251881Speter apr_pool_t *scratch_pool) 104251881Speter{ 105269847Speter iprops_context_t *iprops_ctx = baton; 106251881Speter 107269847Speter if (entered_state == IPROPS_ITEM) 108251881Speter { 109251881Speter svn_stringbuf_setempty(iprops_ctx->curr_propname); 110269847Speter 111269847Speter iprops_ctx->curr_iprop = apr_pcalloc(iprops_ctx->pool, 112269847Speter sizeof(*iprops_ctx->curr_iprop)); 113269847Speter 114269847Speter iprops_ctx->curr_iprop->prop_hash = apr_hash_make(iprops_ctx->pool); 115251881Speter } 116251881Speter return SVN_NO_ERROR; 117251881Speter} 118251881Speter 119269847Speter/* Conforms to svn_ra_serf__xml_closed_t */ 120251881Speterstatic svn_error_t * 121269847Speteriprops_closed(svn_ra_serf__xml_estate_t *xes, 122269847Speter void *baton, 123269847Speter int leaving_state, 124269847Speter const svn_string_t *cdata, 125269847Speter apr_hash_t *attrs, 126269847Speter apr_pool_t *scratch_pool) 127251881Speter{ 128269847Speter iprops_context_t *iprops_ctx = baton; 129251881Speter 130269847Speter if (leaving_state == IPROPS_ITEM) 131269847Speter { 132269847Speter APR_ARRAY_PUSH(iprops_ctx->iprops, svn_prop_inherited_item_t *) = 133269847Speter iprops_ctx->curr_iprop; 134251881Speter 135269847Speter iprops_ctx->curr_iprop = NULL; 136251881Speter } 137269847Speter else if (leaving_state == IPROPS_PATH) 138251881Speter { 139269847Speter /* Every <iprop-item> has a single <iprop-path> */ 140269847Speter if (iprops_ctx->curr_iprop->path_or_url) 141269847Speter return svn_error_create(SVN_ERR_XML_MALFORMED, NULL, NULL); 142251881Speter 143251881Speter iprops_ctx->curr_iprop->path_or_url = 144251881Speter svn_path_url_add_component2(iprops_ctx->repos_root_url, 145269847Speter cdata->data, 146251881Speter iprops_ctx->pool); 147251881Speter } 148269847Speter else if (leaving_state == IPROPS_PROPNAME) 149251881Speter { 150269847Speter if (iprops_ctx->curr_propname->len) 151269847Speter return svn_error_create(SVN_ERR_XML_MALFORMED, NULL, NULL); 152251881Speter 153269847Speter /* Store propname for value */ 154269847Speter svn_stringbuf_set(iprops_ctx->curr_propname, cdata->data); 155269847Speter } 156269847Speter else if (leaving_state == IPROPS_PROPVAL) 157269847Speter { 158269847Speter const char *encoding; 159269847Speter const svn_string_t *val_str; 160269847Speter 161269847Speter if (! iprops_ctx->curr_propname->len) 162269847Speter return svn_error_create(SVN_ERR_XML_MALFORMED, NULL, NULL); 163269847Speter 164269847Speter encoding = svn_hash_gets(attrs, "V:encoding"); 165269847Speter 166269847Speter if (encoding) 167251881Speter { 168269847Speter if (strcmp(encoding, "base64") != 0) 169269847Speter return svn_error_createf(SVN_ERR_XML_MALFORMED, 170269847Speter NULL, 171269847Speter _("Got unrecognized encoding '%s'"), 172269847Speter encoding); 173251881Speter 174269847Speter /* Decode into the right pool. */ 175269847Speter val_str = svn_base64_decode_string(cdata, iprops_ctx->pool); 176251881Speter } 177251881Speter else 178251881Speter { 179269847Speter /* Copy into the right pool. */ 180269847Speter val_str = svn_string_dup(cdata, iprops_ctx->pool); 181251881Speter } 182251881Speter 183251881Speter svn_hash_sets(iprops_ctx->curr_iprop->prop_hash, 184251881Speter apr_pstrdup(iprops_ctx->pool, 185251881Speter iprops_ctx->curr_propname->data), 186269847Speter val_str); 187269847Speter /* Clear current propname. */ 188251881Speter svn_stringbuf_setempty(iprops_ctx->curr_propname); 189251881Speter } 190269847Speter else 191269847Speter SVN_ERR_MALFUNCTION(); /* Invalid transition table */ 192251881Speter 193251881Speter return SVN_NO_ERROR; 194251881Speter} 195251881Speter 196251881Speterstatic svn_error_t * 197251881Spetercreate_iprops_body(serf_bucket_t **bkt, 198251881Speter void *baton, 199251881Speter serf_bucket_alloc_t *alloc, 200251881Speter apr_pool_t *pool) 201251881Speter{ 202251881Speter iprops_context_t *iprops_ctx = baton; 203251881Speter serf_bucket_t *body_bkt; 204251881Speter 205251881Speter body_bkt = serf_bucket_aggregate_create(alloc); 206251881Speter 207251881Speter svn_ra_serf__add_open_tag_buckets(body_bkt, alloc, 208251881Speter "S:" SVN_DAV__INHERITED_PROPS_REPORT, 209251881Speter "xmlns:S", SVN_XML_NAMESPACE, 210251881Speter NULL); 211251881Speter svn_ra_serf__add_tag_buckets(body_bkt, 212251881Speter "S:" SVN_DAV__REVISION, 213251881Speter apr_ltoa(pool, iprops_ctx->revision), 214251881Speter alloc); 215251881Speter svn_ra_serf__add_tag_buckets(body_bkt, "S:" SVN_DAV__PATH, 216251881Speter iprops_ctx->path, alloc); 217251881Speter svn_ra_serf__add_close_tag_buckets(body_bkt, alloc, 218251881Speter "S:" SVN_DAV__INHERITED_PROPS_REPORT); 219251881Speter *bkt = body_bkt; 220251881Speter return SVN_NO_ERROR; 221251881Speter} 222251881Speter 223251881Speter/* Request a inherited-props-report from the URL attached to RA_SESSION, 224251881Speter and fill the IPROPS array hash with the results. */ 225251881Spetersvn_error_t * 226251881Spetersvn_ra_serf__get_inherited_props(svn_ra_session_t *ra_session, 227251881Speter apr_array_header_t **iprops, 228251881Speter const char *path, 229251881Speter svn_revnum_t revision, 230251881Speter apr_pool_t *result_pool, 231251881Speter apr_pool_t *scratch_pool) 232251881Speter{ 233251881Speter svn_error_t *err; 234251881Speter iprops_context_t *iprops_ctx; 235251881Speter svn_ra_serf__session_t *session = ra_session->priv; 236251881Speter svn_ra_serf__handler_t *handler; 237269847Speter svn_ra_serf__xml_context_t *xmlctx; 238251881Speter const char *req_url; 239251881Speter 240251881Speter SVN_ERR(svn_ra_serf__get_stable_url(&req_url, 241251881Speter NULL /* latest_revnum */, 242251881Speter session, 243251881Speter NULL /* conn */, 244251881Speter NULL /* url */, 245251881Speter revision, 246251881Speter result_pool, scratch_pool)); 247251881Speter 248251881Speter SVN_ERR_ASSERT(session->repos_root_str); 249251881Speter 250251881Speter iprops_ctx = apr_pcalloc(scratch_pool, sizeof(*iprops_ctx)); 251251881Speter iprops_ctx->repos_root_url = session->repos_root_str; 252251881Speter iprops_ctx->pool = result_pool; 253251881Speter iprops_ctx->curr_propname = svn_stringbuf_create_empty(scratch_pool); 254251881Speter iprops_ctx->curr_iprop = NULL; 255251881Speter iprops_ctx->iprops = apr_array_make(result_pool, 1, 256251881Speter sizeof(svn_prop_inherited_item_t *)); 257251881Speter iprops_ctx->path = path; 258251881Speter iprops_ctx->revision = revision; 259251881Speter 260269847Speter xmlctx = svn_ra_serf__xml_context_create(iprops_table, 261269847Speter iprops_opened, iprops_closed, NULL, 262269847Speter iprops_ctx, 263269847Speter scratch_pool); 264269847Speter handler = svn_ra_serf__create_expat_handler(xmlctx, scratch_pool); 265251881Speter 266251881Speter handler->method = "REPORT"; 267251881Speter handler->path = req_url; 268251881Speter handler->conn = session->conns[0]; 269251881Speter handler->session = session; 270251881Speter handler->body_delegate = create_iprops_body; 271251881Speter handler->body_delegate_baton = iprops_ctx; 272251881Speter handler->body_type = "text/xml"; 273251881Speter handler->handler_pool = scratch_pool; 274251881Speter 275251881Speter err = svn_ra_serf__context_run_one(handler, scratch_pool); 276251881Speter SVN_ERR(svn_error_compose_create( 277253734Speter svn_ra_serf__error_on_status(handler->sline, 278251881Speter handler->path, 279251881Speter handler->location), 280251881Speter err)); 281251881Speter 282269847Speter *iprops = iprops_ctx->iprops; 283251881Speter 284251881Speter return SVN_NO_ERROR; 285251881Speter} 286