2 * property.c : property routines for ra_serf
4 * ====================================================================
5 * Copyright (c) 2006-2007 CollabNet. All rights reserved.
7 * This software is licensed as described in the file COPYING, which
8 * you should have received as part of this distribution. The terms
9 * are also available at http://subversion.tigris.org/license-1.html.
10 * If newer versions of this license are posted there, you may use a
11 * newer version instead, at your option.
13 * This software consists of voluntary contributions made by many
14 * individuals. For exact contribution history, see the revision
15 * history and logs, available at http://subversion.tigris.org/.
16 * ====================================================================
24 #include "svn_base64.h"
27 #include "private/svn_dav_protocol.h"
28 #include "svn_private_config.h"
33 /* Our current parsing state we're in for the PROPFIND response. */
44 /* Current ns, attribute name, and value of the property we're parsing */
57 * This structure represents a pending PROPFIND response.
59 struct svn_ra_serf__propfind_context_t
{
60 /* pool to issue allocations from */
63 svn_ra_serf__handler_t
*handler
;
65 /* associated serf session */
66 svn_ra_serf__session_t
*sess
;
67 svn_ra_serf__connection_t
*conn
;
69 /* the requested path */
72 /* the requested version (number and string form) */
76 /* the request depth */
79 /* the list of requested properties */
80 const svn_ra_serf__dav_props_t
*find_props
;
82 /* should we cache the values of this propfind in our session? */
83 svn_boolean_t cache_props
;
85 /* hash table that will be updated with the properties
87 * This can be shared between multiple svn_ra_serf__propfind_context_t
90 apr_hash_t
*ret_props
;
92 /* If we're dealing with a Depth: 1 response,
93 * we may be dealing with multiple paths.
95 const char *current_path
;
97 /* Returned status code. */
100 /* Are we done issuing the PROPFIND? */
103 /* Context from XML stream */
104 svn_ra_serf__xml_parser_t
*parser_ctx
;
106 /* If not-NULL, add us to this list when we're done. */
107 svn_ra_serf__list_t
**done_list
;
109 svn_ra_serf__list_t done_item
;
113 svn_ra_serf__get_ver_prop_string(apr_hash_t
*props
,
119 apr_hash_t
*ver_props
, *path_props
, *ns_props
;
122 ver_props
= apr_hash_get(props
, &rev
, sizeof(rev
));
125 path_props
= apr_hash_get(ver_props
, path
, APR_HASH_KEY_STRING
);
129 ns_props
= apr_hash_get(path_props
, ns
, APR_HASH_KEY_STRING
);
132 val
= apr_hash_get(ns_props
, name
, APR_HASH_KEY_STRING
);
141 svn_ra_serf__get_ver_prop(apr_hash_t
*props
,
147 const svn_string_t
*val
;
149 val
= svn_ra_serf__get_ver_prop_string(props
, path
, rev
, ns
, name
);
160 svn_ra_serf__get_prop(apr_hash_t
*props
,
165 return svn_ra_serf__get_ver_prop(props
, path
, SVN_INVALID_REVNUM
, ns
, name
);
169 svn_ra_serf__set_ver_prop(apr_hash_t
*props
,
170 const char *path
, svn_revnum_t rev
,
171 const char *ns
, const char *name
,
172 const svn_string_t
*val
, apr_pool_t
*pool
)
174 apr_hash_t
*ver_props
, *path_props
, *ns_props
;
176 ver_props
= apr_hash_get(props
, &rev
, sizeof(rev
));
179 ver_props
= apr_hash_make(pool
);
180 apr_hash_set(props
, apr_pmemdup(pool
, &rev
, sizeof(rev
)), sizeof(rev
),
184 path_props
= apr_hash_get(ver_props
, path
, APR_HASH_KEY_STRING
);
188 path_props
= apr_hash_make(pool
);
189 path
= apr_pstrdup(pool
, path
);
190 apr_hash_set(ver_props
, path
, APR_HASH_KEY_STRING
, path_props
);
192 /* todo: we know that we'll fail the next check, but fall through
193 * for now for simplicity's sake.
197 ns_props
= apr_hash_get(path_props
, ns
, APR_HASH_KEY_STRING
);
200 ns_props
= apr_hash_make(pool
);
201 ns
= apr_pstrdup(pool
, ns
);
202 apr_hash_set(path_props
, ns
, APR_HASH_KEY_STRING
, ns_props
);
205 apr_hash_set(ns_props
, name
, APR_HASH_KEY_STRING
, val
);
209 svn_ra_serf__set_prop(apr_hash_t
*props
,
211 const char *ns
, const char *name
,
212 const svn_string_t
*val
, apr_pool_t
*pool
)
214 svn_ra_serf__set_ver_prop(props
, path
, SVN_INVALID_REVNUM
, ns
, name
,
219 push_state(svn_ra_serf__xml_parser_t
*parser
,
220 svn_ra_serf__propfind_context_t
*propfind
,
223 svn_ra_serf__xml_push_state(parser
, state
);
225 if (state
== PROPVAL
)
229 info
= apr_pcalloc(parser
->state
->pool
, sizeof(*info
));
230 info
->pool
= parser
->state
->pool
;
232 parser
->state
->private = info
;
235 return parser
->state
->private;
239 * Expat callback invoked on a start element tag for a PROPFIND response.
242 start_propfind(svn_ra_serf__xml_parser_t
*parser
,
244 svn_ra_serf__dav_props_t name
,
247 svn_ra_serf__propfind_context_t
*ctx
= userData
;
251 state
= parser
->state
->current_state
;
253 if (state
== NONE
&& strcmp(name
.name
, "response") == 0)
255 svn_ra_serf__xml_push_state(parser
, RESPONSE
);
257 else if (state
== RESPONSE
&& strcmp(name
.name
, "href") == 0)
259 info
= push_state(parser
, ctx
, PROPVAL
);
260 info
->ns
= name
.namespace;
261 info
->name
= apr_pstrdup(info
->pool
, name
.name
);
263 else if (state
== RESPONSE
&& strcmp(name
.name
, "prop") == 0)
265 push_state(parser
, ctx
, PROP
);
267 else if (state
== PROP
)
269 info
= push_state(parser
, ctx
, PROPVAL
);
270 info
->ns
= name
.namespace;
271 info
->name
= apr_pstrdup(info
->pool
, name
.name
);
272 info
->encoding
= apr_pstrdup(info
->pool
,
273 svn_xml_get_attr_value("V:encoding", attrs
));
280 * Expat callback invoked on an end element tag for a PROPFIND response.
283 end_propfind(svn_ra_serf__xml_parser_t
*parser
,
285 svn_ra_serf__dav_props_t name
)
287 svn_ra_serf__propfind_context_t
*ctx
= userData
;
291 state
= parser
->state
->current_state
;
292 info
= parser
->state
->private;
294 if (state
== RESPONSE
&& strcmp(name
.name
, "response") == 0)
296 svn_ra_serf__xml_pop_state(parser
);
298 else if (state
== PROP
&& strcmp(name
.name
, "prop") == 0)
300 svn_ra_serf__xml_pop_state(parser
);
302 else if (state
== PROPVAL
)
304 const char *ns
, *pname
, *val
;
305 svn_string_t
*val_str
;
307 /* if we didn't see a CDATA element, we may want the tag name
308 * as long as it isn't equivalent to the property name.
312 if (strcmp(info
->name
, name
.name
) != 0)
314 info
->val
= name
.name
;
315 info
->val_len
= strlen(info
->val
);
324 if (parser
->state
->prev
->current_state
== RESPONSE
&&
325 strcmp(name
.name
, "href") == 0)
327 if (strcmp(ctx
->depth
, "1") == 0)
329 ctx
->current_path
= svn_path_canonicalize(info
->val
, ctx
->pool
);
333 ctx
->current_path
= ctx
->path
;
336 else if (info
->encoding
)
338 if (strcmp(info
->encoding
, "base64") == 0)
340 svn_string_t encoded
;
341 const svn_string_t
*decoded
;
343 encoded
.data
= info
->val
;
344 encoded
.len
= info
->val_len
;
346 decoded
= svn_base64_decode_string(&encoded
, parser
->state
->pool
);
347 info
->val
= decoded
->data
;
348 info
->val_len
= decoded
->len
;
352 return svn_error_createf(SVN_ERR_RA_DAV_MALFORMED_DATA
,
354 _("Got unrecognized encoding '%s'"),
359 ns
= apr_pstrdup(ctx
->pool
, info
->ns
);
360 pname
= apr_pstrdup(ctx
->pool
, info
->name
);
361 val
= apr_pmemdup(ctx
->pool
, info
->val
, info
->val_len
);
362 val_str
= svn_string_ncreate(val
, info
->val_len
, ctx
->pool
);
364 /* set the return props and update our cache too. */
365 svn_ra_serf__set_ver_prop(ctx
->ret_props
,
366 ctx
->current_path
, ctx
->rev
,
369 if (ctx
->cache_props
)
371 ns
= apr_pstrdup(ctx
->sess
->pool
, info
->ns
);
372 pname
= apr_pstrdup(ctx
->sess
->pool
, info
->name
);
373 val
= apr_pmemdup(ctx
->sess
->pool
, info
->val
, info
->val_len
);
374 val_str
= svn_string_ncreate(val
, info
->val_len
, ctx
->sess
->pool
);
376 svn_ra_serf__set_ver_prop(ctx
->sess
->cached_props
,
377 ctx
->current_path
, ctx
->rev
,
382 svn_ra_serf__xml_pop_state(parser
);
389 * Expat callback invoked on CDATA elements in a PROPFIND response.
391 * This callback can be called multiple times.
394 cdata_propfind(svn_ra_serf__xml_parser_t
*parser
,
399 svn_ra_serf__propfind_context_t
*ctx
= userData
;
405 state
= parser
->state
->current_state
;
406 info
= parser
->state
->private;
408 if (state
== PROPVAL
)
410 svn_ra_serf__expand_string(&info
->val
, &info
->val_len
, data
, len
,
418 setup_propfind(serf_request_t
*request
,
420 serf_bucket_t
**req_bkt
,
421 serf_response_acceptor_t
*acceptor
,
422 void **acceptor_baton
,
423 serf_response_handler_t
*handler
,
424 void **handler_baton
,
427 svn_ra_serf__propfind_context_t
*ctx
= setup_baton
;
428 svn_ra_serf__xml_parser_t
*parser_ctx
= ctx
->parser_ctx
;
431 svn_ra_serf__bucket_propfind_create(ctx
->conn
, ctx
->path
, ctx
->label
,
432 ctx
->depth
, ctx
->find_props
,
433 serf_request_get_alloc(request
));
435 if (ctx
->conn
->using_ssl
)
438 serf_bucket_ssl_encrypt_create(*req_bkt
, ctx
->conn
->ssl_context
,
439 serf_request_get_alloc(request
));
441 if (!ctx
->conn
->ssl_context
)
443 ctx
->conn
->ssl_context
=
444 serf_bucket_ssl_encrypt_context_get(*req_bkt
);
448 parser_ctx
->pool
= pool
;
449 parser_ctx
->user_data
= ctx
;
450 parser_ctx
->start
= start_propfind
;
451 parser_ctx
->end
= end_propfind
;
452 parser_ctx
->cdata
= cdata_propfind
;
453 parser_ctx
->status_code
= &ctx
->status_code
;
454 parser_ctx
->done
= &ctx
->done
;
455 parser_ctx
->done_list
= ctx
->done_list
;
456 parser_ctx
->done_item
= &ctx
->done_item
;
458 *handler
= svn_ra_serf__handle_xml_parser
;
459 *handler_baton
= parser_ctx
;
465 check_cache(apr_hash_t
*ret_props
,
466 svn_ra_serf__session_t
*sess
,
469 const svn_ra_serf__dav_props_t
*find_props
,
472 svn_boolean_t cache_hit
= TRUE
;
473 const svn_ra_serf__dav_props_t
*prop
;
475 /* check to see if we have any of this information cached */
477 while (prop
&& prop
->namespace)
479 const svn_string_t
*val
;
481 val
= svn_ra_serf__get_ver_prop_string(sess
->cached_props
, path
, rev
,
482 prop
->namespace, prop
->name
);
485 svn_ra_serf__set_ver_prop(ret_props
, path
, rev
,
486 prop
->namespace, prop
->name
, val
, pool
);
499 * This function will deliver a PROP_CTX PROPFIND request in the SESS
500 * serf context for the properties listed in LOOKUP_PROPS at URL for
501 * DEPTH ("0","1","infinity").
503 * This function will not block waiting for the response. If the
504 * request can be satisfied from a local cache, set PROP_CTX to NULL
505 * as a signal to callers of that fact. Otherwise, callers are
506 * expected to call svn_ra_serf__wait_for_props().
509 svn_ra_serf__deliver_props(svn_ra_serf__propfind_context_t
**prop_ctx
,
510 apr_hash_t
*ret_props
,
511 svn_ra_serf__session_t
*sess
,
512 svn_ra_serf__connection_t
*conn
,
516 const svn_ra_serf__dav_props_t
*find_props
,
517 svn_boolean_t cache_props
,
518 svn_ra_serf__list_t
**done_list
,
521 svn_ra_serf__propfind_context_t
*new_prop_ctx
;
525 svn_ra_serf__handler_t
*handler
;
527 if (cache_props
== TRUE
)
529 svn_boolean_t cache_satisfy
;
531 cache_satisfy
= check_cache(ret_props
, sess
, path
, rev
, find_props
,
541 new_prop_ctx
= apr_pcalloc(pool
, sizeof(*new_prop_ctx
));
543 new_prop_ctx
->pool
= apr_hash_pool_get(ret_props
);
544 new_prop_ctx
->path
= path
;
545 new_prop_ctx
->cache_props
= cache_props
;
546 new_prop_ctx
->find_props
= find_props
;
547 new_prop_ctx
->ret_props
= ret_props
;
548 new_prop_ctx
->depth
= depth
;
549 new_prop_ctx
->done
= FALSE
;
550 new_prop_ctx
->sess
= sess
;
551 new_prop_ctx
->conn
= conn
;
552 new_prop_ctx
->rev
= rev
;
553 new_prop_ctx
->done_list
= done_list
;
555 if (SVN_IS_VALID_REVNUM(rev
))
557 new_prop_ctx
->label
= apr_ltoa(pool
, rev
);
561 new_prop_ctx
->label
= NULL
;
564 handler
= apr_pcalloc(pool
, sizeof(*handler
));
566 handler
->method
= "PROPFIND";
567 handler
->delegate
= setup_propfind
;
568 handler
->delegate_baton
= new_prop_ctx
;
569 handler
->session
= new_prop_ctx
->sess
;
570 handler
->conn
= new_prop_ctx
->conn
;
572 new_prop_ctx
->handler
= handler
;
574 new_prop_ctx
->parser_ctx
= apr_pcalloc(pool
,
575 sizeof(*new_prop_ctx
->parser_ctx
));
577 *prop_ctx
= new_prop_ctx
;
581 svn_ra_serf__request_create((*prop_ctx
)->handler
);
587 svn_ra_serf__propfind_is_done(svn_ra_serf__propfind_context_t
*ctx
)
593 svn_ra_serf__propfind_status_code(svn_ra_serf__propfind_context_t
*ctx
)
595 return ctx
->status_code
;
599 * This helper function will block until the PROP_CTX indicates that is done
600 * or another error is returned.
603 svn_ra_serf__wait_for_props(svn_ra_serf__propfind_context_t
*prop_ctx
,
604 svn_ra_serf__session_t
*sess
,
609 err
= svn_ra_serf__context_run_wait(&prop_ctx
->done
, sess
, pool
);
610 if (prop_ctx
->parser_ctx
->error
)
612 svn_error_clear(err
);
613 SVN_ERR(prop_ctx
->parser_ctx
->error
);
619 * This is a blocking version of deliver_props.
622 svn_ra_serf__retrieve_props(apr_hash_t
*prop_vals
,
623 svn_ra_serf__session_t
*sess
,
624 svn_ra_serf__connection_t
*conn
,
628 const svn_ra_serf__dav_props_t
*props
,
631 svn_ra_serf__propfind_context_t
*prop_ctx
= NULL
;
633 SVN_ERR(svn_ra_serf__deliver_props(&prop_ctx
, prop_vals
, sess
, conn
, url
,
634 rev
, depth
, props
, TRUE
, NULL
, pool
));
637 SVN_ERR(svn_ra_serf__wait_for_props(prop_ctx
, sess
, pool
));
644 svn_ra_serf__search_for_base_props(apr_hash_t
*props
,
645 const char **remaining_path
,
646 const char **missing_path
,
647 svn_ra_serf__session_t
*session
,
648 svn_ra_serf__connection_t
*conn
,
652 const char *path
= url
, *present_path
= "";
657 SVN_ERR(svn_ra_serf__retrieve_props(props
, session
, conn
,
658 path
, SVN_INVALID_REVNUM
,
659 "0", base_props
, pool
));
661 svn_ra_serf__get_ver_prop(props
, path
,
664 "version-controlled-configuration");
668 /* This happens when the file is missing in HEAD. */
670 /* Okay, strip off. */
671 present_path
= svn_path_join(svn_path_basename(path
, pool
),
673 path
= svn_path_dirname(path
, pool
);
675 while (!svn_path_is_empty(path
));
677 /* Error out if entire URL was bogus (not a single part of it exists
678 in the repository!) */
679 if (svn_path_is_empty(path
))
680 return svn_error_createf(SVN_ERR_RA_ILLEGAL_URL
, NULL
,
681 _("No part of path '%s' was found in "
682 "repository HEAD"), url
);
684 *missing_path
= present_path
;
685 *remaining_path
= path
;
691 svn_ra_serf__walk_all_props(apr_hash_t
*props
,
694 svn_ra_serf__walker_visitor_t walker
,
698 apr_hash_index_t
*ns_hi
;
699 apr_hash_t
*ver_props
, *path_props
;
701 ver_props
= apr_hash_get(props
, &rev
, sizeof(rev
));
708 path_props
= apr_hash_get(ver_props
, name
, strlen(name
));
715 for (ns_hi
= apr_hash_first(pool
, path_props
); ns_hi
;
716 ns_hi
= apr_hash_next(ns_hi
))
721 apr_hash_index_t
*name_hi
;
722 apr_hash_this(ns_hi
, &ns_name
, &ns_len
, &ns_val
);
723 for (name_hi
= apr_hash_first(pool
, ns_val
); name_hi
;
724 name_hi
= apr_hash_next(name_hi
))
727 const void *prop_name
;
728 apr_ssize_t prop_len
;
730 apr_hash_this(name_hi
, &prop_name
, &prop_len
, &prop_val
);
732 walker(baton
, ns_name
, ns_len
, prop_name
, prop_len
, prop_val
, pool
);
738 svn_ra_serf__walk_all_paths(apr_hash_t
*props
,
740 svn_ra_serf__path_rev_walker_t walker
,
744 apr_hash_index_t
*path_hi
;
745 apr_hash_t
*ver_props
;
747 ver_props
= apr_hash_get(props
, &rev
, sizeof(rev
));
754 for (path_hi
= apr_hash_first(pool
, ver_props
); path_hi
;
755 path_hi
= apr_hash_next(path_hi
))
758 const void *path_name
;
759 apr_ssize_t path_len
;
760 apr_hash_index_t
*ns_hi
;
762 apr_hash_this(path_hi
, &path_name
, &path_len
, &path_props
);
763 for (ns_hi
= apr_hash_first(pool
, path_props
); ns_hi
;
764 ns_hi
= apr_hash_next(ns_hi
))
769 apr_hash_index_t
*name_hi
;
770 apr_hash_this(ns_hi
, &ns_name
, &ns_len
, &ns_val
);
771 for (name_hi
= apr_hash_first(pool
, ns_val
); name_hi
;
772 name_hi
= apr_hash_next(name_hi
))
775 const void *prop_name
;
776 apr_ssize_t prop_len
;
778 apr_hash_this(name_hi
, &prop_name
, &prop_len
, &prop_val
);
780 walker(baton
, path_name
, path_len
, ns_name
, ns_len
,
781 prop_name
, prop_len
, prop_val
, pool
);
788 set_bare_props(svn_ra_serf__prop_set_t setprop
, void *baton
,
789 const char *ns
, apr_ssize_t ns_len
,
790 const char *name
, apr_ssize_t name_len
,
791 const svn_string_t
*val
,
794 const char *prop_name
;
796 if (strcmp(ns
, SVN_DAV_PROP_NS_CUSTOM
) == 0)
798 else if (strcmp(ns
, SVN_DAV_PROP_NS_SVN
) == 0)
799 prop_name
= apr_pstrcat(pool
, SVN_PROP_PREFIX
, name
, NULL
);
800 else if (strcmp(ns
, SVN_PROP_PREFIX
) == 0)
801 prop_name
= apr_pstrcat(pool
, SVN_PROP_PREFIX
, name
, NULL
);
802 else if (strcmp(ns
, "") == 0)
806 /* do nothing for now? */
810 return setprop(baton
, prop_name
, val
, pool
);
814 svn_ra_serf__set_baton_props(svn_ra_serf__prop_set_t setprop
, void *baton
,
815 const char *ns
, apr_ssize_t ns_len
,
816 const char *name
, apr_ssize_t name_len
,
817 const svn_string_t
*val
,
820 const char *prop_name
;
822 if (strcmp(ns
, SVN_DAV_PROP_NS_CUSTOM
) == 0)
824 else if (strcmp(ns
, SVN_DAV_PROP_NS_SVN
) == 0)
825 prop_name
= apr_pstrcat(pool
, SVN_PROP_PREFIX
, name
, NULL
);
826 else if (strcmp(ns
, SVN_PROP_PREFIX
) == 0)
827 prop_name
= apr_pstrcat(pool
, SVN_PROP_PREFIX
, name
, NULL
);
828 else if (strcmp(ns
, "") == 0)
830 else if (strcmp(name
, SVN_DAV__VERSION_NAME
) == 0)
831 prop_name
= SVN_PROP_ENTRY_COMMITTED_REV
;
832 else if (strcmp(name
, SVN_DAV__CREATIONDATE
) == 0)
833 prop_name
= SVN_PROP_ENTRY_COMMITTED_DATE
;
834 else if (strcmp(name
, "creator-displayname") == 0)
835 prop_name
= SVN_PROP_ENTRY_LAST_AUTHOR
;
836 else if (strcmp(name
, "repository-uuid") == 0)
837 prop_name
= SVN_PROP_ENTRY_UUID
;
838 else if (strcmp(name
, "lock-token") == 0)
839 prop_name
= SVN_PROP_ENTRY_LOCK_TOKEN
;
840 else if (strcmp(name
, "checked-in") == 0)
841 prop_name
= SVN_RA_SERF__WC_CHECKED_IN_URL
;
844 /* do nothing for now? */
848 return setprop(baton
, prop_name
, val
, pool
);
852 set_hash_props(void *baton
,
854 const svn_string_t
*value
,
857 apr_hash_t
*props
= baton
;
859 apr_hash_set(props
, name
, APR_HASH_KEY_STRING
, value
);
865 svn_ra_serf__set_flat_props(void *baton
,
866 const char *ns
, apr_ssize_t ns_len
,
867 const char *name
, apr_ssize_t name_len
,
868 const svn_string_t
*val
,
871 return svn_ra_serf__set_baton_props(set_hash_props
, baton
,
872 ns
, ns_len
, name
, name_len
, val
, pool
);
876 svn_ra_serf__set_bare_props(void *baton
,
877 const char *ns
, apr_ssize_t ns_len
,
878 const char *name
, apr_ssize_t name_len
,
879 const svn_string_t
*val
,
882 return set_bare_props(set_hash_props
, baton
,
883 ns
, ns_len
, name
, name_len
, val
, pool
);
888 svn_ra_serf__get_baseline_info(const char **bc_url
,
889 const char **bc_relative
,
890 svn_ra_serf__session_t
*session
,
892 svn_revnum_t revision
,
895 const char *vcc_url
, *relative_url
, *basecoll_url
, *baseline_url
;
896 apr_hash_t
*props
= apr_hash_make(pool
);
898 /* No URL? No sweat. We'll use the session URL. */
900 url
= session
->repos_url
.path
;
902 SVN_ERR(svn_ra_serf__discover_root(&vcc_url
, &relative_url
,
903 session
, session
->conns
[0], url
, pool
));
905 if (revision
!= SVN_INVALID_REVNUM
)
907 SVN_ERR(svn_ra_serf__retrieve_props(props
, session
, session
->conns
[0],
908 vcc_url
, revision
, "0",
909 baseline_props
, pool
));
910 basecoll_url
= svn_ra_serf__get_ver_prop(props
, vcc_url
, revision
,
911 "DAV:", "baseline-collection");
915 SVN_ERR(svn_ra_serf__retrieve_props(props
, session
, session
->conns
[0],
916 vcc_url
, revision
, "0",
917 checked_in_props
, pool
));
918 baseline_url
= svn_ra_serf__get_ver_prop(props
, vcc_url
, revision
,
919 "DAV:", "checked-in");
922 return svn_error_create(SVN_ERR_RA_DAV_OPTIONS_REQ_FAILED
, NULL
,
923 _("The OPTIONS response did not include the "
924 "requested checked-in value"));
927 SVN_ERR(svn_ra_serf__retrieve_props(props
, session
, session
->conns
[0],
928 baseline_url
, revision
, "0",
929 baseline_props
, pool
));
930 basecoll_url
= svn_ra_serf__get_ver_prop(props
, baseline_url
, revision
,
931 "DAV:", "baseline-collection");
936 return svn_error_create(SVN_ERR_RA_DAV_OPTIONS_REQ_FAILED
, NULL
,
937 _("The OPTIONS response did not include the "
938 "requested baseline-collection value"));
940 *bc_url
= basecoll_url
;
941 *bc_relative
= relative_url
;