2
2
* options.c : routines for performing OPTIONS server requests
4
4
* ====================================================================
5
* Copyright (c) 2000-2006, 2009 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/.
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
13
* http://www.apache.org/licenses/LICENSE-2.0
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
16
21
* ====================================================================
135
132
static const char *capability_server_yes = "server-yes";
138
/* Store in RAS the capabilities discovered from REQ's headers.
139
Use POOL for temporary allocation only. */
135
/* Store in RAS the capabilities and other interesting tidbits of
136
information discovered from REQ's headers. Use POOL for temporary
139
Also, if YOUNGEST_REV is not NULL, set *YOUNGEST_REV to the current
140
youngest revision if we can detect that from the OPTIONS exchange, or
141
to SVN_INVALID_REVNUM otherwise. */
141
143
parse_capabilities(ne_request *req,
142
144
svn_ra_neon__session_t *ras,
145
svn_revnum_t *youngest_rev,
143
146
apr_pool_t *pool)
145
const char *header_value;
151
*youngest_rev = SVN_INVALID_REVNUM;
147
153
/* Start out assuming all capabilities are unsupported. */
154
apr_hash_set(ras->capabilities, SVN_RA_CAPABILITY_PARTIAL_REPLAY,
155
APR_HASH_KEY_STRING, capability_no);
148
156
apr_hash_set(ras->capabilities, SVN_RA_CAPABILITY_DEPTH,
149
157
APR_HASH_KEY_STRING, capability_no);
150
158
apr_hash_set(ras->capabilities, SVN_RA_CAPABILITY_MERGEINFO,
151
159
APR_HASH_KEY_STRING, capability_no);
152
160
apr_hash_set(ras->capabilities, SVN_RA_CAPABILITY_LOG_REVPROPS,
153
161
APR_HASH_KEY_STRING, capability_no);
162
apr_hash_set(ras->capabilities, SVN_RA_CAPABILITY_ATOMIC_REVPROPS,
163
APR_HASH_KEY_STRING, capability_no);
155
165
/* Then find out which ones are supported. */
156
header_value = ne_get_response_header(req, "dav");
166
val = ne_get_response_header(req, "dav");
159
169
/* Multiple headers of the same name will have been merged
160
170
together by the time we see them (either by an intermediary,
171
181
Here we might see:
173
header_value == "1,2, version-control,checkout,working-resource, merge,baseline,activity,version-controlled-collection, http://subversion.tigris.org/xmlns/dav/svn/depth, <http://apache.org/dav/propset/fs/1>"
183
val == "1,2, version-control,checkout,working-resource, merge,baseline,activity,version-controlled-collection, http://subversion.tigris.org/xmlns/dav/svn/depth, <http://apache.org/dav/propset/fs/1>"
175
185
(Deliberately not line-wrapping that, so you can see what
176
186
we're about to parse.)
179
189
apr_array_header_t *vals =
180
svn_cstring_split(header_value, ",", TRUE, pool);
190
svn_cstring_split(val, ",", TRUE, pool);
182
192
/* Right now we only have a few capabilities to detect, so
183
193
just seek for them directly. This could be written
184
194
slightly more efficiently, but that wouldn't be worth it
185
195
until we have many more capabilities. */
187
if (match_list(SVN_DAV_NS_DAV_SVN_DEPTH, vals))
197
if (svn_cstring_match_list(SVN_DAV_NS_DAV_SVN_DEPTH, vals))
188
198
apr_hash_set(ras->capabilities, SVN_RA_CAPABILITY_DEPTH,
189
199
APR_HASH_KEY_STRING, capability_yes);
191
if (match_list(SVN_DAV_NS_DAV_SVN_MERGEINFO, vals))
201
if (svn_cstring_match_list(SVN_DAV_NS_DAV_SVN_MERGEINFO, vals))
192
202
/* The server doesn't know what repository we're referring
193
203
to, so it can't just say capability_yes. */
194
204
apr_hash_set(ras->capabilities, SVN_RA_CAPABILITY_MERGEINFO,
195
205
APR_HASH_KEY_STRING, capability_server_yes);
197
if (match_list(SVN_DAV_NS_DAV_SVN_LOG_REVPROPS, vals))
207
if (svn_cstring_match_list(SVN_DAV_NS_DAV_SVN_LOG_REVPROPS, vals))
198
208
apr_hash_set(ras->capabilities, SVN_RA_CAPABILITY_LOG_REVPROPS,
199
209
APR_HASH_KEY_STRING, capability_yes);
201
if (match_list(SVN_DAV_NS_DAV_SVN_PARTIAL_REPLAY, vals))
211
if (svn_cstring_match_list(SVN_DAV_NS_DAV_SVN_ATOMIC_REVPROPS, vals))
212
apr_hash_set(ras->capabilities, SVN_RA_CAPABILITY_ATOMIC_REVPROPS,
213
APR_HASH_KEY_STRING, capability_yes);
215
if (svn_cstring_match_list(SVN_DAV_NS_DAV_SVN_PARTIAL_REPLAY, vals))
202
216
apr_hash_set(ras->capabilities, SVN_RA_CAPABILITY_PARTIAL_REPLAY,
203
217
APR_HASH_KEY_STRING, capability_yes);
220
/* Not strictly capabilities, but while we're here, we might as well... */
221
if ((val = ne_get_response_header(req, SVN_DAV_YOUNGEST_REV_HEADER)))
224
*youngest_rev = SVN_STR_TO_REV(val);
226
if ((val = ne_get_response_header(req, SVN_DAV_REPOS_UUID_HEADER)))
228
ras->uuid = apr_pstrdup(ras->pool, val);
230
if ((val = ne_get_response_header(req, SVN_DAV_ROOT_URI_HEADER)))
232
ne_uri root_uri = ras->root;
234
root_uri.path = (char *)val;
235
ras->repos_root = svn_ra_neon__uri_unparse(&root_uri, ras->pool);
239
if ((val = ne_get_response_header(req, SVN_DAV_ME_RESOURCE_HEADER)))
242
char *ignore_v2_env_var = getenv(SVN_IGNORE_V2_ENV_VAR);
244
if (! (ignore_v2_env_var
245
&& apr_strnatcasecmp(ignore_v2_env_var, "yes") == 0))
246
ras->me_resource = apr_pstrdup(ras->pool, val);
248
ras->me_resource = apr_pstrdup(ras->pool, val);
251
if ((val = ne_get_response_header(req, SVN_DAV_REV_ROOT_STUB_HEADER)))
253
ras->rev_root_stub = apr_pstrdup(ras->pool, val);
255
if ((val = ne_get_response_header(req, SVN_DAV_REV_STUB_HEADER)))
257
ras->rev_stub = apr_pstrdup(ras->pool, val);
259
if ((val = ne_get_response_header(req, SVN_DAV_TXN_ROOT_STUB_HEADER)))
261
ras->txn_root_stub = apr_pstrdup(ras->pool, val);
263
if ((val = ne_get_response_header(req, SVN_DAV_TXN_STUB_HEADER)))
265
ras->txn_stub = apr_pstrdup(ras->pool, val);
267
if ((val = ne_get_response_header(req, SVN_DAV_VTXN_ROOT_STUB_HEADER)))
269
ras->vtxn_root_stub = apr_pstrdup(ras->pool, val);
271
if ((val = ne_get_response_header(req, SVN_DAV_VTXN_STUB_HEADER)))
273
ras->vtxn_stub = apr_pstrdup(ras->pool, val);
209
279
svn_ra_neon__exchange_capabilities(svn_ra_neon__session_t *ras,
280
const char **relocation_location,
281
svn_revnum_t *youngest_rev,
210
282
apr_pool_t *pool)
212
284
svn_ra_neon__request_t* req;
213
285
svn_error_t *err = SVN_NO_ERROR;
214
286
ne_xml_parser *parser = NULL;
215
287
options_ctx_t oc = { 0 };
220
291
oc.cdata = svn_stringbuf_create("", pool);
222
req = svn_ra_neon__request_create(ras, "OPTIONS", ras->url->data, pool);
294
*youngest_rev = SVN_INVALID_REVNUM;
295
if (relocation_location)
296
*relocation_location = NULL;
298
SVN_ERR(svn_ra_neon__request_create(&req, ras, "OPTIONS", ras->url->data,
224
301
/* ### Use a symbolic name somewhere for this MIME type? */
225
302
ne_add_request_header(req->ne_req, "Content-Type", "text/xml");