~ubuntu-branches/ubuntu/trusty/subversion/trusty-proposed

« back to all changes in this revision

Viewing changes to subversion/libsvn_ra_neon/options.c

  • Committer: Package Import Robot
  • Author(s): Andy Whitcroft
  • Date: 2012-06-21 15:36:36 UTC
  • mfrom: (0.4.13 sid)
  • Revision ID: package-import@ubuntu.com-20120621153636-amqqmuidgwgxz1ly
Tags: 1.7.5-1ubuntu1
* Merge from Debian unstable.  Remaining changes:
  - Create pot file on build.
  - Build a python-subversion-dbg package.
  - Build-depend on python-dbg.
  - Build-depend on default-jre-headless/-jdk.
  - Do not apply java-build patch.
  - debian/rules: Manually create the doxygen output directory, otherwise
    we get weird build failures when running parallel builds.

Show diffs side-by-side

added added

removed removed

Lines of Context:
2
2
 * options.c :  routines for performing OPTIONS server requests
3
3
 *
4
4
 * ====================================================================
5
 
 * Copyright (c) 2000-2006, 2009 CollabNet.  All rights reserved.
6
 
 *
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.
12
 
 *
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
 
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.
16
21
 * ====================================================================
17
22
 */
18
23
 
20
25
 
21
26
#include "svn_pools.h"
22
27
#include "svn_error.h"
 
28
#include "svn_dirent_uri.h"
23
29
#include "svn_private_config.h"
24
30
#include "../libsvn_ra/ra_loader.h"
25
31
 
 
32
#include "private/svn_fspath.h"
 
33
 
26
34
#include "ra_neon.h"
27
35
 
28
36
 
 
37
/* In a debug build, setting this environment variable to "yes" will force
 
38
   the client to speak v1, even if the server is capable of speaking v2. */
 
39
#define SVN_IGNORE_V2_ENV_VAR "SVN_I_LIKE_LATENCY_SO_IGNORE_HTTPV2"
 
40
 
29
41
static const svn_ra_neon__xml_elm_t options_elements[] =
30
42
{
31
43
  { "DAV:", "activity-collection-set", ELEM_activity_coll_set, 0 },
35
47
  { NULL }
36
48
};
37
49
 
38
 
typedef struct {
 
50
typedef struct options_ctx_t {
39
51
  /*WARNING: WANT_CDATA should stay the first element in the baton:
40
52
    svn_ra_neon__xml_collect_cdata() assumes the baton starts with a stringbuf.
41
53
  */
102
114
  options_ctx_t *oc = baton;
103
115
 
104
116
  if (state == ELEM_href)
105
 
    oc->activity_coll = svn_string_create_from_buf(oc->cdata, oc->pool);
 
117
    oc->activity_coll =
 
118
      svn_string_create(svn_urlpath__canonicalize(oc->cdata->data, oc->pool),
 
119
                        oc->pool);
106
120
 
107
121
  return SVN_NO_ERROR;
108
122
}
110
124
 
111
125
/** Capabilities exchange. */
112
126
 
113
 
/* Return TRUE iff STR exactly matches any of the elements of LIST. */
114
 
static svn_boolean_t
115
 
match_list(const char *str, const apr_array_header_t *list)
116
 
{
117
 
  int i;
118
 
 
119
 
  for (i = 0; i < list->nelts; i++)
120
 
    {
121
 
      const char *this_str = APR_ARRAY_IDX(list, i, char *);
122
 
 
123
 
      if (strcmp(this_str, str) == 0)
124
 
        return TRUE;
125
 
    }
126
 
 
127
 
  return FALSE;
128
 
}
129
 
 
130
127
/* Both server and repository support the capability. */
131
128
static const char *capability_yes = "yes";
132
129
/* Either server or repository does not support the capability. */
135
132
static const char *capability_server_yes = "server-yes";
136
133
 
137
134
 
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
 
137
   allocation only.
 
138
 
 
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.  */
140
142
static void
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)
144
147
{
145
 
  const char *header_value;
 
148
  const char *val;
 
149
 
 
150
  if (youngest_rev)
 
151
    *youngest_rev = SVN_INVALID_REVNUM;
146
152
 
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);
154
164
 
155
165
  /* Then find out which ones are supported. */
156
 
  header_value = ne_get_response_header(req, "dav");
157
 
  if (header_value)
 
166
  val = ne_get_response_header(req, "dav");
 
167
  if (val)
158
168
    {
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,
170
180
 
171
181
          Here we might see:
172
182
 
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>"
174
184
 
175
185
          (Deliberately not line-wrapping that, so you can see what
176
186
          we're about to parse.)
177
187
      */
178
188
 
179
189
      apr_array_header_t *vals =
180
 
        svn_cstring_split(header_value, ",", TRUE, pool);
 
190
        svn_cstring_split(val, ",", TRUE, pool);
181
191
 
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. */
186
196
 
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);
190
200
 
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);
196
206
 
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);
200
210
 
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);
 
214
 
 
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);
204
218
    }
 
219
 
 
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)))
 
222
    {
 
223
      if (youngest_rev)
 
224
        *youngest_rev = SVN_STR_TO_REV(val);
 
225
    }
 
226
  if ((val = ne_get_response_header(req, SVN_DAV_REPOS_UUID_HEADER)))
 
227
    {
 
228
      ras->uuid = apr_pstrdup(ras->pool, val);
 
229
    }
 
230
  if ((val = ne_get_response_header(req, SVN_DAV_ROOT_URI_HEADER)))
 
231
    {
 
232
      ne_uri root_uri = ras->root;
 
233
 
 
234
      root_uri.path = (char *)val;
 
235
      ras->repos_root = svn_ra_neon__uri_unparse(&root_uri, ras->pool);
 
236
    }
 
237
 
 
238
  /* HTTP v2 stuff */
 
239
  if ((val = ne_get_response_header(req, SVN_DAV_ME_RESOURCE_HEADER)))
 
240
    {
 
241
#ifdef SVN_DEBUG
 
242
      char *ignore_v2_env_var = getenv(SVN_IGNORE_V2_ENV_VAR);
 
243
 
 
244
      if (! (ignore_v2_env_var
 
245
             && apr_strnatcasecmp(ignore_v2_env_var, "yes") == 0))
 
246
        ras->me_resource = apr_pstrdup(ras->pool, val);
 
247
#else
 
248
      ras->me_resource = apr_pstrdup(ras->pool, val);
 
249
#endif
 
250
    }
 
251
  if ((val = ne_get_response_header(req, SVN_DAV_REV_ROOT_STUB_HEADER)))
 
252
    {
 
253
      ras->rev_root_stub = apr_pstrdup(ras->pool, val);
 
254
    }
 
255
  if ((val = ne_get_response_header(req, SVN_DAV_REV_STUB_HEADER)))
 
256
    {
 
257
      ras->rev_stub = apr_pstrdup(ras->pool, val);
 
258
    }
 
259
  if ((val = ne_get_response_header(req, SVN_DAV_TXN_ROOT_STUB_HEADER)))
 
260
    {
 
261
      ras->txn_root_stub = apr_pstrdup(ras->pool, val);
 
262
    }
 
263
  if ((val = ne_get_response_header(req, SVN_DAV_TXN_STUB_HEADER)))
 
264
    {
 
265
      ras->txn_stub = apr_pstrdup(ras->pool, val);
 
266
    }
 
267
  if ((val = ne_get_response_header(req, SVN_DAV_VTXN_ROOT_STUB_HEADER)))
 
268
    {
 
269
      ras->vtxn_root_stub = apr_pstrdup(ras->pool, val);
 
270
    }
 
271
  if ((val = ne_get_response_header(req, SVN_DAV_VTXN_STUB_HEADER)))
 
272
    {
 
273
      ras->vtxn_stub = apr_pstrdup(ras->pool, val);
 
274
    }
205
275
}
206
276
 
207
277
 
208
278
svn_error_t *
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)
211
283
{
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 };
216
 
  const char *msg;
217
288
  int status_code;
218
289
 
219
290
  oc.pool = pool;
220
291
  oc.cdata = svn_stringbuf_create("", pool);
221
292
 
222
 
  req = svn_ra_neon__request_create(ras, "OPTIONS", ras->url->data, pool);
 
293
  if (youngest_rev)
 
294
    *youngest_rev = SVN_INVALID_REVNUM;
 
295
  if (relocation_location)
 
296
    *relocation_location = NULL;
 
297
 
 
298
  SVN_ERR(svn_ra_neon__request_create(&req, ras, "OPTIONS", ras->url->data,
 
299
                                      pool));
223
300
 
224
301
  /* ### Use a symbolic name somewhere for this MIME type? */
225
302
  ne_add_request_header(req->ne_req, "Content-Type", "text/xml");
236
313
                                           "<D:options xmlns:D=\"DAV:\">"
237
314
                                           "<D:activity-collection-set/>"
238
315
                                           "</D:options>",
239
 
                                           200, 0, pool)))
 
316
                                           200,
 
317
                                           relocation_location ? 301 : 0,
 
318
                                           pool)))
240
319
    goto cleanup;
241
320
 
 
321
  if (req->code == 301)
 
322
    {
 
323
      *relocation_location = svn_ra_neon__request_get_location(req, pool);
 
324
      goto cleanup;
 
325
    }
 
326
 
242
327
  /* Was there an XML parse error somewhere? */
243
 
  msg = ne_xml_get_error(parser);
244
 
  if (msg && *msg)
245
 
    {
246
 
      err = svn_error_createf(SVN_ERR_RA_DAV_REQUEST_FAILED, NULL,
247
 
                              _("The %s request returned invalid XML "
248
 
                                "in the response: %s (%s)"),
249
 
                              "OPTIONS", msg, ras->url->data);
250
 
      goto cleanup;
251
 
    }
 
328
  err = svn_ra_neon__check_parse_error("OPTIONS", parser, ras->url->data);
 
329
  if (err)
 
330
    goto cleanup;
252
331
 
253
332
  /* We asked for, and therefore expect, to have found an activity
254
333
     collection in the response.  */
262
341
    }
263
342
 
264
343
  ras->act_coll = apr_pstrdup(ras->pool, oc.activity_coll->data);
265
 
  parse_capabilities(req->ne_req, ras, pool);
 
344
  parse_capabilities(req->ne_req, ras, youngest_rev, pool);
266
345
 
267
346
 cleanup:
268
347
  svn_ra_neon__request_destroy(req);
277
356
                                     apr_pool_t *pool)
278
357
{
279
358
  if (! ras->act_coll)
280
 
    SVN_ERR(svn_ra_neon__exchange_capabilities(ras, pool));
 
359
    SVN_ERR(svn_ra_neon__exchange_capabilities(ras, NULL, NULL, pool));
281
360
  *activity_coll = svn_string_create(ras->act_coll, pool);
282
361
  return SVN_NO_ERROR;
283
362
}
305
384
 
306
385
  /* If any capability is unknown, they're all unknown, so ask. */
307
386
  if (cap_result == NULL)
308
 
    SVN_ERR(svn_ra_neon__exchange_capabilities(ras, pool));
 
387
    {
 
388
      SVN_ERR(svn_ra_neon__exchange_capabilities(ras, NULL, NULL, pool));
 
389
    }
309
390
 
310
391
 
311
392
  /* Try again, now that we've fetched the capabilities. */
313
394
                            capability, APR_HASH_KEY_STRING);
314
395
 
315
396
  /* Some capabilities depend on the repository as well as the server.
316
 
     NOTE: ../libsvn_ra_serf/serf.c:svn_ra_serf__has_capability()
317
 
     has a very similar code block.  If you change something here,
318
 
     check there as well. */
 
397
     NOTE: svn_ra_serf__has_capability() has a very similar code block.  If
 
398
     you change something here, check there as well. */
319
399
  if (cap_result == capability_server_yes)
320
400
    {
321
401
      if (strcmp(capability, SVN_RA_CAPABILITY_MERGEINFO) == 0)
326
406
             above didn't even know which repository we were interested in
327
407
             -- it just told us whether the server supports mergeinfo.
328
408
             If the answer was 'no', there's no point checking the
329
 
             particular repository; but if it was 'yes, we still must
 
409
             particular repository; but if it was 'yes', we still must
330
410
             change it to 'no' iff the repository itself doesn't
331
411
             support mergeinfo. */
332
412
          svn_mergeinfo_catalog_t ignored;
360
440
          else
361
441
            cap_result = capability_yes;
362
442
 
363
 
          apr_hash_set(ras->capabilities,
364
 
                       SVN_RA_CAPABILITY_MERGEINFO, APR_HASH_KEY_STRING,
365
 
                       cap_result);
 
443
            apr_hash_set(ras->capabilities,
 
444
                         SVN_RA_CAPABILITY_MERGEINFO, APR_HASH_KEY_STRING,
 
445
                         cap_result);
366
446
        }
367
447
      else
368
448
        {