2 * get_locations.c : RA get-locations API implementation
4 * ====================================================================
5 * Copyright (c) 2004-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 * ====================================================================
21 #define APR_WANT_STRFUNC
22 #include <apr_want.h> /* for strcmp() */
24 #include <apr_pools.h>
25 #include <apr_tables.h>
26 #include <apr_strings.h>
32 #include "svn_error.h"
33 #include "svn_pools.h"
35 #include "../libsvn_ra/ra_loader.h"
40 #include "private/svn_dav_protocol.h"
41 #include "svn_private_config.h"
47 * Plan for processing the XML. The XML will be of the form:
49 * <S:get-locations-report xmlns...>
50 * <S:location rev="..." path="..."/>
52 * </S:get-locations-report>
54 * We extract what we want at the start of <S:location>.
57 /* Elements used in a get-locations response */
58 static const svn_ra_neon__xml_elm_t gloc_report_elements
[] =
60 { SVN_XML_NAMESPACE
, "get-locations-report", ELEM_get_locations_report
, 0 },
61 { SVN_XML_NAMESPACE
, "location", ELEM_location
, 0 },
66 svn_ra_neon__session_t
*ras
;
69 } get_locations_baton_t
;
72 /* This implements the `svn_ra_neon__startelem_cb_t' prototype. */
74 gloc_start_element(int *elem
, void *userdata
, int parent_state
,
75 const char *ns
, const char *ln
, const char **atts
)
77 get_locations_baton_t
*baton
= userdata
;
78 const svn_ra_neon__xml_elm_t
*elm
;
80 elm
= svn_ra_neon__lookup_xml_elem(gloc_report_elements
, ns
, ln
);
82 /* Just skip unknown elements. */
85 *elem
= NE_XML_DECLINE
;
89 if (parent_state
== ELEM_get_locations_report
90 && elm
->id
== ELEM_location
)
92 svn_revnum_t rev
= SVN_INVALID_REVNUM
;
96 r
= svn_xml_get_attr_value("rev", atts
);
98 rev
= SVN_STR_TO_REV(r
);
100 path
= svn_xml_get_attr_value("path", atts
);
102 if (SVN_IS_VALID_REVNUM(rev
) && path
)
103 apr_hash_set(baton
->hash
,
104 apr_pmemdup(baton
->pool
, &rev
, sizeof(rev
)),
105 sizeof(rev
), apr_pstrdup(baton
->pool
, path
));
107 return svn_error_create(SVN_ERR_RA_DAV_MALFORMED_DATA
, NULL
,
108 _("Expected a valid revnum and path"));
117 svn_ra_neon__get_locations(svn_ra_session_t
*session
,
118 apr_hash_t
**locations
,
119 const char *relative_path
,
120 svn_revnum_t peg_revision
,
121 apr_array_header_t
*location_revisions
,
124 svn_ra_neon__session_t
*ras
= session
->priv
;
125 svn_stringbuf_t
*request_body
;
127 get_locations_baton_t request_baton
;
128 const char *relative_path_quoted
;
129 svn_string_t bc_url
, bc_relative
;
130 const char *final_bc_url
;
134 *locations
= apr_hash_make(pool
);
136 request_body
= svn_stringbuf_create("", pool
);
137 svn_stringbuf_appendcstr(request_body
,
138 "<?xml version=\"1.0\" encoding=\"utf-8\"?>" DEBUG_CR
139 "<S:get-locations xmlns:S=\"" SVN_XML_NAMESPACE
140 "\" xmlns:D=\"DAV:\">" DEBUG_CR
);
142 svn_stringbuf_appendcstr(request_body
, "<S:path>");
143 /* We need to escape the path XML-wise. */
144 relative_path_quoted
= apr_xml_quote_string(pool
, relative_path
, 0);
145 svn_stringbuf_appendcstr(request_body
, relative_path_quoted
);
146 svn_stringbuf_appendcstr(request_body
, "</S:path>" DEBUG_CR
);
147 svn_stringbuf_appendcstr(request_body
,
149 "<S:peg-revision>%ld"
150 "</S:peg-revision>" DEBUG_CR
,
153 for (i
= 0; i
< location_revisions
->nelts
; ++i
)
155 svn_revnum_t rev
= APR_ARRAY_IDX(location_revisions
, i
, svn_revnum_t
);
156 svn_stringbuf_appendcstr(request_body
,
158 "<S:location-revision>%ld"
159 "</S:location-revision>" DEBUG_CR
,
163 svn_stringbuf_appendcstr(request_body
, "</S:get-locations>");
165 request_baton
.ras
= ras
;
166 request_baton
.hash
= *locations
;
167 request_baton
.pool
= pool
;
169 /* ras's URL may not exist in HEAD, and thus it's not safe to send
170 it as the main argument to the REPORT request; it might cause
171 dav_get_resource() to choke on the server. So instead, we pass a
172 baseline-collection URL, which we get from the peg revision. */
173 SVN_ERR(svn_ra_neon__get_baseline_info(NULL
, &bc_url
, &bc_relative
, NULL
,
177 final_bc_url
= svn_path_url_add_component(bc_url
.data
, bc_relative
.data
,
180 err
= svn_ra_neon__parsed_request(ras
, "REPORT", final_bc_url
,
181 request_body
->data
, NULL
, NULL
,
182 gloc_start_element
, NULL
, NULL
,
183 &request_baton
, NULL
, &status_code
,
186 /* Map status 501: Method Not Implemented to our not implemented error.
187 1.0.x servers and older don't support this report. */
188 if (status_code
== 501)
189 return svn_error_create(SVN_ERR_RA_NOT_IMPLEMENTED
, err
,
190 _("'get-locations' REPORT not implemented"));