1 /*
2 * getlocations.c : entry point for get_locations RA functions for ra_serf
3 *
4 * ====================================================================
5 * Licensed to the Apache Software Foundation (ASF) under one
6 * or more contributor license agreements. See the NOTICE file
7 * distributed with this work for additional information
8 * regarding copyright ownership. The ASF licenses this file
9 * to you under the Apache License, Version 2.0 (the
10 * "License"); you may not use this file except in compliance
11 * with the License. You may obtain a copy of the License at
12 *
13 * http://www.apache.org/licenses/LICENSE-2.0
14 *
15 * Unless required by applicable law or agreed to in writing,
16 * software distributed under the License is distributed on an
17 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18 * KIND, either express or implied. See the License for the
19 * specific language governing permissions and limitations
20 * under the License.
21 * ====================================================================
22 */
23
24
25
26 #include <apr_uri.h>
27
28 #include <serf.h>
29
30 #include "svn_hash.h"
31 #include "svn_path.h"
32 #include "svn_pools.h"
33 #include "svn_ra.h"
34 #include "svn_xml.h"
35 #include "svn_private_config.h"
36
37 #include "../libsvn_ra/ra_loader.h"
38
39 #include "ra_serf.h"
40
41
42 /*
43 * This enum represents the current state of our XML parsing for a REPORT.
44 */
45 enum loc_state_e {
46 INITIAL = XML_STATE_INITIAL,
47 REPORT,
48 LOCATION
49 };
50
51 typedef struct loc_context_t {
52 /* pool to allocate memory from */
53 apr_pool_t *pool;
54
55 /* parameters set by our caller */
56 const char *path;
57 const apr_array_header_t *location_revisions;
58 svn_revnum_t peg_revision;
59
60 /* Returned location hash */
61 apr_hash_t *paths;
62
63 } loc_context_t;
64
65 #define D_ "DAV:"
66 #define S_ SVN_XML_NAMESPACE
67 static const svn_ra_serf__xml_transition_t getloc_ttable[] = {
68 { INITIAL, S_, "get-locations-report", REPORT,
69 FALSE, { NULL }, FALSE },
70
71 { REPORT, S_, "location", LOCATION,
72 FALSE, { "?rev", "?path", NULL }, TRUE },
73
74 { 0 }
75 };
76
77
78 /* Conforms to svn_ra_serf__xml_closed_t */
79 static svn_error_t *
getloc_closed(svn_ra_serf__xml_estate_t * xes,void * baton,int leaving_state,const svn_string_t * cdata,apr_hash_t * attrs,apr_pool_t * scratch_pool)80 getloc_closed(svn_ra_serf__xml_estate_t *xes,
81 void *baton,
82 int leaving_state,
83 const svn_string_t *cdata,
84 apr_hash_t *attrs,
85 apr_pool_t *scratch_pool)
86 {
87 loc_context_t *loc_ctx = baton;
88 const char *revstr;
89 const char *path;
90
91 SVN_ERR_ASSERT(leaving_state == LOCATION);
92
93 revstr = svn_hash_gets(attrs, "rev");
94 path = svn_hash_gets(attrs, "path");
95 if (revstr != NULL && path != NULL)
96 {
97 apr_int64_t rev_val;
98 svn_revnum_t rev;
99
100 SVN_ERR(svn_cstring_atoi64(&rev_val, revstr));
101 rev = (svn_revnum_t)rev_val;
102
103 apr_hash_set(loc_ctx->paths,
104 apr_pmemdup(loc_ctx->pool, &rev, sizeof(rev)), sizeof(rev),
105 apr_pstrdup(loc_ctx->pool, path));
106 }
107
108 return SVN_NO_ERROR;
109 }
110
111
112 /* Implements svn_ra_serf__request_body_delegate_t */
113 static svn_error_t *
create_get_locations_body(serf_bucket_t ** body_bkt,void * baton,serf_bucket_alloc_t * alloc,apr_pool_t * pool,apr_pool_t * scratch_pool)114 create_get_locations_body(serf_bucket_t **body_bkt,
115 void *baton,
116 serf_bucket_alloc_t *alloc,
117 apr_pool_t *pool /* request pool */,
118 apr_pool_t *scratch_pool)
119 {
120 serf_bucket_t *buckets;
121 loc_context_t *loc_ctx = baton;
122 int i;
123
124 buckets = serf_bucket_aggregate_create(alloc);
125
126 svn_ra_serf__add_open_tag_buckets(buckets, alloc,
127 "S:get-locations",
128 "xmlns:S", SVN_XML_NAMESPACE,
129 "xmlns:D", "DAV:",
130 SVN_VA_NULL);
131
132 svn_ra_serf__add_tag_buckets(buckets,
133 "S:path", loc_ctx->path,
134 alloc);
135
136 svn_ra_serf__add_tag_buckets(buckets,
137 "S:peg-revision", apr_ltoa(pool, loc_ctx->peg_revision),
138 alloc);
139
140 for (i = 0; i < loc_ctx->location_revisions->nelts; i++)
141 {
142 svn_revnum_t rev = APR_ARRAY_IDX(loc_ctx->location_revisions, i, svn_revnum_t);
143 svn_ra_serf__add_tag_buckets(buckets,
144 "S:location-revision", apr_ltoa(pool, rev),
145 alloc);
146 }
147
148 svn_ra_serf__add_close_tag_buckets(buckets, alloc,
149 "S:get-locations");
150
151 *body_bkt = buckets;
152 return SVN_NO_ERROR;
153 }
154
155 svn_error_t *
svn_ra_serf__get_locations(svn_ra_session_t * ra_session,apr_hash_t ** locations,const char * path,svn_revnum_t peg_revision,const apr_array_header_t * location_revisions,apr_pool_t * pool)156 svn_ra_serf__get_locations(svn_ra_session_t *ra_session,
157 apr_hash_t **locations,
158 const char *path,
159 svn_revnum_t peg_revision,
160 const apr_array_header_t *location_revisions,
161 apr_pool_t *pool)
162 {
163 loc_context_t *loc_ctx;
164 svn_ra_serf__session_t *session = ra_session->priv;
165 svn_ra_serf__handler_t *handler;
166 svn_ra_serf__xml_context_t *xmlctx;
167 const char *req_url;
168
169 loc_ctx = apr_pcalloc(pool, sizeof(*loc_ctx));
170 loc_ctx->pool = pool;
171 loc_ctx->path = path;
172 loc_ctx->peg_revision = peg_revision;
173 loc_ctx->location_revisions = location_revisions;
174 loc_ctx->paths = apr_hash_make(loc_ctx->pool);
175
176 *locations = loc_ctx->paths;
177
178 SVN_ERR(svn_ra_serf__get_stable_url(&req_url, NULL /* latest_revnum */,
179 session, NULL /* url */, peg_revision,
180 pool, pool));
181
182 xmlctx = svn_ra_serf__xml_context_create(getloc_ttable,
183 NULL, getloc_closed, NULL,
184 loc_ctx,
185 pool);
186 handler = svn_ra_serf__create_expat_handler(session, xmlctx, NULL, pool);
187
188 handler->method = "REPORT";
189 handler->path = req_url;
190 handler->body_delegate = create_get_locations_body;
191 handler->body_delegate_baton = loc_ctx;
192 handler->body_type = "text/xml";
193
194 SVN_ERR(svn_ra_serf__context_run_one(handler, pool));
195
196 SVN_ERR(svn_ra_serf__error_on_status(handler->sline,
197 handler->path,
198 handler->location));
199
200 return SVN_NO_ERROR;
201 }
202