2 * get_location_segments.c : RA get-location-segments API implementation
4 * ====================================================================
5 * Copyright (c) 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-location-segments-report xmlns...>
50 * <S:location [path="..."] range_start="..." range_end="..."/>
52 * </S:get-location-segments-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 gls_report_elements
[] =
60 { SVN_XML_NAMESPACE
, "get-location-segments-report",
61 ELEM_get_location_segments_report
, 0 },
62 { SVN_XML_NAMESPACE
, "location-segment", ELEM_location_segment
, 0 },
67 svn_location_segment_receiver_t receiver
;
70 } get_location_segments_baton_t
;
72 /* This implements the `svn_ra_neon__startelem_cb_t' prototype. */
74 gls_start_element(int *elem
, void *userdata
, int parent_state
,
75 const char *ns
, const char *ln
, const char **atts
)
77 get_location_segments_baton_t
*baton
= userdata
;
78 const svn_ra_neon__xml_elm_t
*elm
;
80 /* Just skip unknown elements. */
81 if (! ((elm
= svn_ra_neon__lookup_xml_elem(gls_report_elements
, ns
, ln
))))
83 *elem
= NE_XML_DECLINE
;
87 if (parent_state
== ELEM_get_location_segments_report
88 && elm
->id
== ELEM_location_segment
)
91 svn_revnum_t range_start
= SVN_INVALID_REVNUM
;
92 svn_revnum_t range_end
= SVN_INVALID_REVNUM
;
93 const char *path
= NULL
;
95 path
= svn_xml_get_attr_value("path", atts
);
96 rev_str
= svn_xml_get_attr_value("range-start", atts
);
98 range_start
= SVN_STR_TO_REV(rev_str
);
99 rev_str
= svn_xml_get_attr_value("range-end", atts
);
101 range_end
= SVN_STR_TO_REV(rev_str
);
103 if (SVN_IS_VALID_REVNUM(range_start
) && SVN_IS_VALID_REVNUM(range_end
))
105 svn_location_segment_t
*segment
= apr_pcalloc(baton
->subpool
,
107 segment
->path
= path
;
108 segment
->range_start
= range_start
;
109 segment
->range_end
= range_end
;
110 SVN_ERR(baton
->receiver(segment
,
111 baton
->receiver_baton
,
113 svn_pool_clear(baton
->subpool
);
117 return svn_error_create(SVN_ERR_RA_DAV_MALFORMED_DATA
, NULL
,
118 _("Expected valid revision range"));
128 svn_ra_neon__get_location_segments(svn_ra_session_t
*session
,
130 svn_revnum_t peg_revision
,
131 svn_revnum_t start_rev
,
132 svn_revnum_t end_rev
,
133 svn_location_segment_receiver_t receiver
,
134 void *receiver_baton
,
138 svn_ra_neon__session_t
*ras
= session
->priv
;
139 svn_stringbuf_t
*request_body
;
141 get_location_segments_baton_t request_baton
;
142 svn_string_t bc_url
, bc_relative
;
145 apr_pool_t
*subpool
= svn_pool_create(pool
);
147 /* Build the request body. */
148 request_body
= svn_stringbuf_create("", subpool
);
149 svn_stringbuf_appendcstr(request_body
,
150 "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
151 DEBUG_CR
"<S:get-location-segments xmlns:S=\""
152 SVN_XML_NAMESPACE
"\" xmlns:D=\"DAV:\">" DEBUG_CR
);
154 /* Tack on the path... */
155 svn_stringbuf_appendcstr(request_body
, "<S:path>");
156 svn_stringbuf_appendcstr(request_body
, apr_xml_quote_string(subpool
, path
, 0));
157 svn_stringbuf_appendcstr(request_body
, "</S:path>" DEBUG_CR
);
159 /* ...and maybe a peg revision... */
160 if (SVN_IS_VALID_REVNUM(peg_revision
))
161 svn_stringbuf_appendcstr
162 (request_body
, apr_psprintf(subpool
,
163 "<S:peg-revision>%ld</S:peg-revision>"
164 DEBUG_CR
, peg_revision
));
166 /* ...and maybe a start revision... */
167 if (SVN_IS_VALID_REVNUM(start_rev
))
168 svn_stringbuf_appendcstr
169 (request_body
, apr_psprintf(subpool
,
170 "<S:start-revision>%ld</S:start-revision>"
171 DEBUG_CR
, start_rev
));
173 /* ...and maybe an end revision. */
174 if (SVN_IS_VALID_REVNUM(end_rev
))
175 svn_stringbuf_appendcstr
176 (request_body
, apr_psprintf(subpool
,
177 "<S:end-revision>%ld</S:end-revision>"
180 svn_stringbuf_appendcstr(request_body
, "</S:get-location-segments>");
182 request_baton
.receiver
= receiver
;
183 request_baton
.receiver_baton
= receiver_baton
;
184 request_baton
.subpool
= svn_pool_create(subpool
);
186 /* ras's URL may not exist in HEAD, and thus it's not safe to send
187 it as the main argument to the REPORT request; it might cause
188 dav_get_resource() to choke on the server. So instead, we pass a
189 baseline-collection URL, which we get from the PEG_REVISION. */
190 SVN_ERR(svn_ra_neon__get_baseline_info(NULL
, &bc_url
, &bc_relative
, NULL
,
192 peg_revision
, subpool
));
193 bc
= svn_path_url_add_component(bc_url
.data
, bc_relative
.data
, subpool
);
195 err
= svn_ra_neon__parsed_request(ras
, "REPORT", bc
,
196 request_body
->data
, NULL
, NULL
,
197 gls_start_element
, NULL
, NULL
,
198 &request_baton
, NULL
, &status_code
,
200 svn_pool_destroy(request_baton
.subpool
);
201 svn_pool_destroy(subpool
);
203 /* Map status 501: Method Not Implemented to our not implemented error.
204 1.0.x servers and older don't support this report. */
205 if (status_code
== 501)
206 return svn_error_create(SVN_ERR_RA_NOT_IMPLEMENTED
, err
,
207 _("'get-location-segments' REPORT "