2 * get-location-segments.c: mod_dav_svn versioning provider functions
3 * for Subversion's get-location-segments RA API.
5 * ====================================================================
6 * Copyright (c) 2007 CollabNet. All rights reserved.
8 * This software is licensed as described in the file COPYING, which
9 * you should have received as part of this distribution. The terms
10 * are also available at http://subversion.tigris.org/license-1.html.
11 * If newer versions of this license are posted there, you may use a
12 * newer version instead, at your option.
14 * This software consists of voluntary contributions made by many
15 * individuals. For exact contribution history, see the revision
16 * history and logs, available at http://subversion.tigris.org/.
17 * ====================================================================
20 #include <apr_tables.h>
29 #include "svn_repos.h"
32 #include "svn_pools.h"
33 #include "svn_props.h"
35 #include "svn_base64.h"
37 #include "../dav_svn.h"
40 struct location_segment_baton
43 apr_bucket_brigade
*bb
;
44 dav_svn__authz_read_baton arb
;
48 /* Implements `svn_location_segment_receiver_t'; helper for
49 dav_svn__get_location_segments_report(). */
51 location_segment_receiver(svn_location_segment_t
*segment
,
55 struct location_segment_baton
*b
= baton
;
60 const char *path_quoted
= apr_xml_quote_string(pool
, segment
->path
, 1);
61 apr_err
= ap_fprintf(b
->output
, b
->bb
,
62 "<S:location-segment path=\"%s\" "
63 "range-start=\"%ld\" range-end=\"%ld\"/>" DEBUG_CR
,
65 segment
->range_start
, segment
->range_end
);
69 apr_err
= ap_fprintf(b
->output
, b
->bb
,
70 "<S:location-segment "
71 "range-start=\"%ld\" range-end=\"%ld\"/>" DEBUG_CR
,
72 segment
->range_start
, segment
->range_end
);
75 return svn_error_create(apr_err
, 0, NULL
);
80 /* Drive svn_repos_node_location_segments() with PATH, START_REV, and
81 END_REV as inputs. This helper exists for simplification of error
82 handing (what with APR status, Subversion errors, and DAV error
83 types all flying about...). */
85 send_get_location_segments_report(ap_filter_t
*output
,
86 apr_bucket_brigade
*bb
,
87 const dav_resource
*resource
,
89 svn_revnum_t start_rev
,
94 dav_svn__authz_read_baton arb
;
95 struct location_segment_baton location_segment_baton
;
97 if ((apr_err
= ap_fprintf(output
, bb
, DAV_XML_HEADER DEBUG_CR
98 "<S:get-location-segments-report xmlns:S=\""
99 SVN_XML_NAMESPACE
"\" xmlns:D=\"DAV:\">"
101 return svn_error_create(apr_err
, 0, NULL
);
103 /* Build an authz read baton. */
104 arb
.r
= resource
->info
->r
;
105 arb
.repos
= resource
->info
->repos
;
107 /* Do what we came here for. */
108 location_segment_baton
.output
= output
;
109 location_segment_baton
.bb
= bb
;
110 SVN_ERR(svn_repos_node_location_segments(resource
->info
->repos
->repos
,
113 location_segment_receiver
,
114 &location_segment_baton
,
115 dav_svn__authz_read_func(&arb
),
116 &arb
, resource
->pool
));
118 if ((apr_err
= ap_fprintf(output
, bb
,
119 "</S:get-location-segments-report>" DEBUG_CR
)))
120 return svn_error_create(apr_err
, 0, NULL
);
127 dav_svn__get_location_segments_report(const dav_resource
*resource
,
128 const apr_xml_doc
*doc
,
132 dav_error
*derr
= NULL
;
133 apr_status_t apr_err
;
134 apr_bucket_brigade
*bb
;
137 const char *path
= NULL
;
138 svn_revnum_t peg_revision
= SVN_INVALID_REVNUM
;
139 svn_revnum_t start_rev
= SVN_INVALID_REVNUM
;
140 svn_revnum_t end_rev
= SVN_INVALID_REVNUM
;
143 ns
= dav_svn__find_ns(doc
->namespaces
, SVN_XML_NAMESPACE
);
146 return dav_svn__new_error_tag(resource
->pool
, HTTP_BAD_REQUEST
, 0,
147 "The request does not contain the 'svn:' "
148 "namespace, so it is not going to have "
149 "certain required elements.",
150 SVN_DAV_ERROR_NAMESPACE
,
154 /* Gather the parameters. */
155 for (child
= doc
->root
->first_child
; child
!= NULL
; child
= child
->next
)
157 /* If this element isn't one of ours, then skip it. */
161 if (strcmp(child
->name
, "peg-revision") == 0)
163 peg_revision
= SVN_STR_TO_REV(dav_xml_get_cdata(child
,
166 else if (strcmp(child
->name
, "start-revision") == 0)
168 start_rev
= SVN_STR_TO_REV(dav_xml_get_cdata(child
,
171 else if (strcmp(child
->name
, "end-revision") == 0)
173 end_rev
= SVN_STR_TO_REV(dav_xml_get_cdata(child
,
176 else if (strcmp(child
->name
, "path") == 0)
178 path
= dav_xml_get_cdata(child
, resource
->pool
, 0);
179 if ((derr
= dav_svn__test_canonical(path
, resource
->pool
)))
181 path
= svn_path_join(resource
->info
->repos_path
, path
,
186 /* Check our inputs. */
188 return dav_svn__new_error_tag(resource
->pool
, HTTP_BAD_REQUEST
, 0,
189 "Not all parameters passed.",
190 SVN_DAV_ERROR_NAMESPACE
,
192 if (SVN_IS_VALID_REVNUM(start_rev
)
193 && SVN_IS_VALID_REVNUM(end_rev
)
194 && (end_rev
> start_rev
))
195 return dav_svn__new_error_tag(resource
->pool
, HTTP_BAD_REQUEST
, 0,
196 "End revision must not be younger than "
198 SVN_DAV_ERROR_NAMESPACE
,
200 if (SVN_IS_VALID_REVNUM(peg_revision
)
201 && SVN_IS_VALID_REVNUM(start_rev
)
202 && (start_rev
> peg_revision
))
203 return dav_svn__new_error_tag(resource
->pool
, HTTP_BAD_REQUEST
, 0,
204 "Start revision must not be younger than "
206 SVN_DAV_ERROR_NAMESPACE
,
209 /* Build the bucket brigade we'll use for output. */
210 bb
= apr_brigade_create(resource
->pool
, output
->c
->bucket_alloc
);
212 /* Alright, time to drive the response. */
213 if ((serr
= send_get_location_segments_report(output
, bb
, resource
,
214 peg_revision
, start_rev
,
216 derr
= dav_svn__convert_err(serr
, HTTP_INTERNAL_SERVER_ERROR
,
217 "Error writing REPORT response.",
220 /* Flush the contents of the brigade (returning an error only if we
221 don't already have one). */
222 if (((apr_err
= ap_fflush(output
, bb
))) && (! derr
))
223 return dav_svn__convert_err(svn_error_create(apr_err
, 0, NULL
),
224 HTTP_INTERNAL_SERVER_ERROR
,
225 "Error flushing brigade.",