~ubuntu-branches/debian/sid/subversion/sid

« back to all changes in this revision

Viewing changes to subversion/libsvn_ra_serf/options.c

  • Committer: Package Import Robot
  • Author(s): James McCoy, Peter Samuelson, James McCoy
  • Date: 2014-01-12 19:48:33 UTC
  • mfrom: (0.2.10)
  • Revision ID: package-import@ubuntu.com-20140112194833-w3axfwksn296jn5x
Tags: 1.8.5-1
[ Peter Samuelson ]
* New upstream release.  (Closes: #725787) Rediff patches:
  - Remove apr-abi1 (applied upstream), rename apr-abi2 to apr-abi
  - Remove loosen-sqlite-version-check (shouldn't be needed)
  - Remove java-osgi-metadata (applied upstream)
  - svnmucc prompts for a changelog if none is provided. (Closes: #507430)
  - Remove fix-bdb-version-detection, upstream uses "apu-config --dbm-libs"
  - Remove ruby-test-wc (applied upstream)
  - Fix “svn diff -r N file” when file has svn:mime-type set.
    (Closes: #734163)
  - Support specifying an encoding for mod_dav_svn's environment in which
    hooks are run.  (Closes: #601544)
  - Fix ordering of “svnadmin dump” paths with certain APR versions.
    (Closes: #687291)
  - Provide a better error message when authentication fails with an
    svn+ssh:// URL.  (Closes: #273874)
  - Updated Polish translations.  (Closes: #690815)

[ James McCoy ]
* Remove all traces of libneon, replaced by libserf.
* patches/sqlite_3.8.x_workaround: Upstream fix for wc-queries-test test
  failurse.
* Run configure with --with-apache-libexecdir, which allows removing part of
  patches/rpath.
* Re-enable auth-test as upstream has fixed the problem of picking up
  libraries from the environment rather than the build tree.
  (Closes: #654172)
* Point LD_LIBRARY_PATH at the built auth libraries when running the svn
  command during the build.  (Closes: #678224)
* Add a NEWS entry describing how to configure mod_dav_svn to understand
  UTF-8.  (Closes: #566148)
* Remove ancient transitional package, libsvn-ruby.
* Enable compatibility with Sqlite3 versions back to Wheezy.
* Enable hardening flags.  (Closes: #734918)
* patches/build-fixes: Enable verbose build logs.
* Build against the default ruby version.  (Closes: #722393)

Show diffs side-by-side

added added

removed removed

Lines of Context:
28
28
#include <serf.h>
29
29
 
30
30
#include "svn_dirent_uri.h"
 
31
#include "svn_hash.h"
31
32
#include "svn_pools.h"
32
33
#include "svn_ra.h"
33
34
#include "svn_dav.h"
48
49
/*
49
50
 * This enum represents the current state of our XML parsing for an OPTIONS.
50
51
 */
51
 
typedef enum options_state_e {
 
52
enum options_state_e {
 
53
  INITIAL = 0,
52
54
  OPTIONS,
53
55
  ACTIVITY_COLLECTION,
54
56
  HREF
55
 
} options_state_e;
56
 
 
57
 
typedef struct options_state_list_t {
58
 
  /* The current state that we are in now. */
59
 
  options_state_e state;
60
 
 
61
 
  /* The previous state we were in. */
62
 
  struct options_state_list_t *prev;
63
 
} options_state_list_t;
64
 
 
65
 
struct svn_ra_serf__options_context_t {
 
57
};
 
58
 
 
59
typedef struct options_context_t {
66
60
  /* pool to allocate memory from */
67
61
  apr_pool_t *pool;
68
62
 
69
 
  const char *attr_val;
70
 
  apr_size_t attr_val_len;
71
 
  svn_boolean_t collect_cdata;
72
 
 
73
 
  /* Current state we're in */
74
 
  options_state_list_t *state;
75
 
  options_state_list_t *free_state;
76
 
 
77
 
  /* HTTP Status code */
78
 
  int status_code;
79
 
 
80
 
  /* are we done? */
81
 
  svn_boolean_t done;
 
63
  /* Have we extracted options values from the headers already?  */
 
64
  svn_boolean_t headers_processed;
82
65
 
83
66
  svn_ra_serf__session_t *session;
84
67
  svn_ra_serf__connection_t *conn;
 
68
  svn_ra_serf__handler_t *handler;
85
69
 
86
 
  const char *path;
 
70
  svn_ra_serf__response_handler_t inner_handler;
 
71
  void *inner_baton;
87
72
 
88
73
  const char *activity_collection;
89
74
  svn_revnum_t youngest_rev;
90
75
 
91
 
  serf_response_acceptor_t acceptor;
92
 
  serf_response_handler_t handler;
93
 
  svn_ra_serf__xml_parser_t *parser_ctx;
94
 
 
 
76
} options_context_t;
 
77
 
 
78
#define D_ "DAV:"
 
79
#define S_ SVN_XML_NAMESPACE
 
80
static const svn_ra_serf__xml_transition_t options_ttable[] = {
 
81
  { INITIAL, D_, "options-response", OPTIONS,
 
82
    FALSE, { NULL }, FALSE },
 
83
 
 
84
  { OPTIONS, D_, "activity-collection-set", ACTIVITY_COLLECTION,
 
85
    FALSE, { NULL }, FALSE },
 
86
 
 
87
  { ACTIVITY_COLLECTION, D_, "href", HREF,
 
88
    TRUE, { NULL }, TRUE },
 
89
 
 
90
  { 0 }
95
91
};
96
92
 
97
 
static void
98
 
push_state(svn_ra_serf__options_context_t *options_ctx, options_state_e state)
99
 
{
100
 
  options_state_list_t *new_state;
101
 
 
102
 
  if (!options_ctx->free_state)
103
 
    {
104
 
      new_state = apr_palloc(options_ctx->pool, sizeof(*options_ctx->state));
105
 
    }
106
 
  else
107
 
    {
108
 
      new_state = options_ctx->free_state;
109
 
      options_ctx->free_state = options_ctx->free_state->prev;
110
 
    }
111
 
  new_state->state = state;
112
 
 
113
 
  /* Add it to the state chain. */
114
 
  new_state->prev = options_ctx->state;
115
 
  options_ctx->state = new_state;
116
 
}
117
 
 
118
 
static void pop_state(svn_ra_serf__options_context_t *options_ctx)
119
 
{
120
 
  options_state_list_t *free_state;
121
 
  free_state = options_ctx->state;
122
 
  /* advance the current state */
123
 
  options_ctx->state = options_ctx->state->prev;
124
 
  free_state->prev = options_ctx->free_state;
125
 
  options_ctx->free_state = free_state;
126
 
}
127
 
 
128
 
static svn_error_t *
129
 
start_options(svn_ra_serf__xml_parser_t *parser,
130
 
              void *userData,
131
 
              svn_ra_serf__dav_props_t name,
132
 
              const char **attrs)
133
 
{
134
 
  svn_ra_serf__options_context_t *options_ctx = userData;
135
 
 
136
 
  if (!options_ctx->state && strcmp(name.name, "options-response") == 0)
137
 
    {
138
 
      push_state(options_ctx, OPTIONS);
139
 
    }
140
 
  else if (!options_ctx->state)
141
 
    {
142
 
      /* Nothing to do. */
143
 
      return SVN_NO_ERROR;
144
 
    }
145
 
  else if (options_ctx->state->state == OPTIONS &&
146
 
           strcmp(name.name, "activity-collection-set") == 0)
147
 
    {
148
 
      push_state(options_ctx, ACTIVITY_COLLECTION);
149
 
    }
150
 
  else if (options_ctx->state->state == ACTIVITY_COLLECTION &&
151
 
           strcmp(name.name, "href") == 0)
152
 
    {
153
 
      options_ctx->collect_cdata = TRUE;
154
 
      push_state(options_ctx, HREF);
155
 
    }
156
 
 
157
 
  return SVN_NO_ERROR;
158
 
}
159
 
 
160
 
static svn_error_t *
161
 
end_options(svn_ra_serf__xml_parser_t *parser,
162
 
            void *userData,
163
 
            svn_ra_serf__dav_props_t name)
164
 
{
165
 
  svn_ra_serf__options_context_t *options_ctx = userData;
166
 
  options_state_list_t *cur_state;
167
 
 
168
 
  if (!options_ctx->state)
169
 
    {
170
 
      return SVN_NO_ERROR;
171
 
    }
172
 
 
173
 
  cur_state = options_ctx->state;
174
 
 
175
 
  if (cur_state->state == OPTIONS &&
176
 
      strcmp(name.name, "options-response") == 0)
177
 
    {
178
 
      pop_state(options_ctx);
179
 
    }
180
 
  else if (cur_state->state == ACTIVITY_COLLECTION &&
181
 
           strcmp(name.name, "activity-collection-set") == 0)
182
 
    {
183
 
      pop_state(options_ctx);
184
 
    }
185
 
  else if (cur_state->state == HREF &&
186
 
           strcmp(name.name, "href") == 0)
187
 
    {
188
 
      options_ctx->collect_cdata = FALSE;
189
 
      options_ctx->activity_collection =
190
 
        svn_urlpath__canonicalize(options_ctx->attr_val, options_ctx->pool);
191
 
      pop_state(options_ctx);
192
 
    }
193
 
 
194
 
  return SVN_NO_ERROR;
195
 
}
196
 
 
197
 
static svn_error_t *
198
 
cdata_options(svn_ra_serf__xml_parser_t *parser,
199
 
              void *userData,
200
 
              const char *data,
201
 
              apr_size_t len)
202
 
{
203
 
  svn_ra_serf__options_context_t *ctx = userData;
204
 
  if (ctx->collect_cdata)
205
 
    {
206
 
      svn_ra_serf__expand_string(&ctx->attr_val, &ctx->attr_val_len,
207
 
                                 data, len, ctx->pool);
208
 
    }
209
 
 
210
 
  return SVN_NO_ERROR;
211
 
}
 
93
 
 
94
/* Conforms to svn_ra_serf__xml_closed_t  */
 
95
static svn_error_t *
 
96
options_closed(svn_ra_serf__xml_estate_t *xes,
 
97
               void *baton,
 
98
               int leaving_state,
 
99
               const svn_string_t *cdata,
 
100
               apr_hash_t *attrs,
 
101
               apr_pool_t *scratch_pool)
 
102
{
 
103
  options_context_t *opt_ctx = baton;
 
104
 
 
105
  SVN_ERR_ASSERT(leaving_state == HREF);
 
106
  SVN_ERR_ASSERT(cdata != NULL);
 
107
 
 
108
  opt_ctx->activity_collection = svn_urlpath__canonicalize(cdata->data,
 
109
                                                           opt_ctx->pool);
 
110
 
 
111
  return SVN_NO_ERROR;
 
112
}
 
113
 
212
114
 
213
115
static svn_error_t *
214
116
create_options_body(serf_bucket_t **body_bkt,
229
131
  return SVN_NO_ERROR;
230
132
}
231
133
 
232
 
svn_boolean_t*
233
 
svn_ra_serf__get_options_done_ptr(svn_ra_serf__options_context_t *ctx)
234
 
{
235
 
  return &ctx->done;
236
 
}
237
 
 
238
 
const char *
239
 
svn_ra_serf__options_get_activity_collection(svn_ra_serf__options_context_t *ctx)
240
 
{
241
 
  return ctx->activity_collection;
242
 
}
243
 
 
244
 
svn_revnum_t
245
 
svn_ra_serf__options_get_youngest_rev(svn_ra_serf__options_context_t *ctx)
246
 
{
247
 
  return ctx->youngest_rev;
248
 
}
249
 
 
250
 
/* Context for both options_response_handler() and capabilities callback. */
251
 
struct options_response_ctx_t {
252
 
  /* Baton for __handle_xml_parser() */
253
 
  svn_ra_serf__xml_parser_t *parser_ctx;
254
 
 
255
 
  /* Session into which we'll store server capabilities */
256
 
  svn_ra_serf__session_t *session;
257
 
 
258
 
  /* For temporary work only. */
259
 
  apr_pool_t *pool;
260
 
};
261
 
 
262
134
 
263
135
/* We use these static pointers so we can employ pointer comparison
264
136
 * of our capabilities hash members instead of strcmp()ing all over
265
137
 * the place.
266
138
 */
267
139
/* Both server and repository support the capability. */
268
 
static const char *capability_yes = "yes";
 
140
static const char *const capability_yes = "yes";
269
141
/* Either server or repository does not support the capability. */
270
 
static const char *capability_no = "no";
 
142
static const char *const capability_no = "no";
271
143
/* Server supports the capability, but don't yet know if repository does. */
272
 
static const char *capability_server_yes = "server-yes";
 
144
static const char *const capability_server_yes = "server-yes";
273
145
 
274
146
 
275
147
/* This implements serf_bucket_headers_do_callback_fn_t.
279
151
                                       const char *key,
280
152
                                       const char *val)
281
153
{
282
 
  struct options_response_ctx_t *orc = baton;
 
154
  options_context_t *opt_ctx = baton;
 
155
  svn_ra_serf__session_t *session = opt_ctx->session;
283
156
 
284
157
  if (svn_cstring_casecmp(key, "dav") == 0)
285
158
    {
287
160
           DAV: version-control,checkout,working-resource
288
161
           DAV: merge,baseline,activity,version-controlled-collection
289
162
           DAV: http://subversion.tigris.org/xmlns/dav/svn/depth */
290
 
      apr_array_header_t *vals = svn_cstring_split(val, ",", TRUE, orc->pool);
 
163
      apr_array_header_t *vals = svn_cstring_split(val, ",", TRUE,
 
164
                                                   opt_ctx->pool);
291
165
 
292
166
      /* Right now we only have a few capabilities to detect, so just
293
167
         seek for them directly.  This could be written slightly more
296
170
 
297
171
      if (svn_cstring_match_list(SVN_DAV_NS_DAV_SVN_DEPTH, vals))
298
172
        {
299
 
          apr_hash_set(orc->session->capabilities, SVN_RA_CAPABILITY_DEPTH,
300
 
                       APR_HASH_KEY_STRING, capability_yes);
 
173
          svn_hash_sets(session->capabilities,
 
174
                        SVN_RA_CAPABILITY_DEPTH, capability_yes);
301
175
        }
302
176
      if (svn_cstring_match_list(SVN_DAV_NS_DAV_SVN_MERGEINFO, vals))
303
177
        {
304
178
          /* The server doesn't know what repository we're referring
305
179
             to, so it can't just say capability_yes. */
306
 
          apr_hash_set(orc->session->capabilities, SVN_RA_CAPABILITY_MERGEINFO,
307
 
                       APR_HASH_KEY_STRING, capability_server_yes);
 
180
          if (!svn_hash_gets(session->capabilities,
 
181
                             SVN_RA_CAPABILITY_MERGEINFO))
 
182
            {
 
183
              svn_hash_sets(session->capabilities, SVN_RA_CAPABILITY_MERGEINFO,
 
184
                            capability_server_yes);
 
185
            }
308
186
        }
309
187
      if (svn_cstring_match_list(SVN_DAV_NS_DAV_SVN_LOG_REVPROPS, vals))
310
188
        {
311
 
          apr_hash_set(orc->session->capabilities,
312
 
                       SVN_RA_CAPABILITY_LOG_REVPROPS,
313
 
                       APR_HASH_KEY_STRING, capability_yes);
 
189
          svn_hash_sets(session->capabilities,
 
190
                        SVN_RA_CAPABILITY_LOG_REVPROPS, capability_yes);
314
191
        }
315
192
      if (svn_cstring_match_list(SVN_DAV_NS_DAV_SVN_ATOMIC_REVPROPS, vals))
316
193
        {
317
 
          apr_hash_set(orc->session->capabilities,
318
 
                       SVN_RA_CAPABILITY_ATOMIC_REVPROPS,
319
 
                       APR_HASH_KEY_STRING, capability_yes);
 
194
          svn_hash_sets(session->capabilities,
 
195
                        SVN_RA_CAPABILITY_ATOMIC_REVPROPS, capability_yes);
320
196
        }
321
197
      if (svn_cstring_match_list(SVN_DAV_NS_DAV_SVN_PARTIAL_REPLAY, vals))
322
198
        {
323
 
          apr_hash_set(orc->session->capabilities,
324
 
                       SVN_RA_CAPABILITY_PARTIAL_REPLAY,
325
 
                       APR_HASH_KEY_STRING, capability_yes);
 
199
          svn_hash_sets(session->capabilities,
 
200
                        SVN_RA_CAPABILITY_PARTIAL_REPLAY, capability_yes);
 
201
        }
 
202
      if (svn_cstring_match_list(SVN_DAV_NS_DAV_SVN_INHERITED_PROPS, vals))
 
203
        {
 
204
          svn_hash_sets(session->capabilities,
 
205
                        SVN_RA_CAPABILITY_INHERITED_PROPS, capability_yes);
 
206
        }
 
207
      if (svn_cstring_match_list(SVN_DAV_NS_DAV_SVN_REVERSE_FILE_REVS,
 
208
                                 vals))
 
209
        {
 
210
          svn_hash_sets(session->capabilities,
 
211
                        SVN_RA_CAPABILITY_GET_FILE_REVS_REVERSE,
 
212
                        capability_yes);
 
213
        }
 
214
      if (svn_cstring_match_list(SVN_DAV_NS_DAV_SVN_EPHEMERAL_TXNPROPS, vals))
 
215
        {
 
216
          svn_hash_sets(session->capabilities,
 
217
                        SVN_RA_CAPABILITY_EPHEMERAL_TXNPROPS, capability_yes);
 
218
        }
 
219
      if (svn_cstring_match_list(SVN_DAV_NS_DAV_SVN_INLINE_PROPS, vals))
 
220
        {
 
221
          session->supports_inline_props = TRUE;
 
222
        }
 
223
      if (svn_cstring_match_list(SVN_DAV_NS_DAV_SVN_REPLAY_REV_RESOURCE, vals))
 
224
        {
 
225
          session->supports_rev_rsrc_replay = TRUE;
326
226
        }
327
227
    }
328
228
 
329
229
  /* SVN-specific headers -- if present, server supports HTTP protocol v2 */
330
230
  else if (strncmp(key, "SVN", 3) == 0)
331
231
    {
 
232
      /* If we've not yet seen any information about supported POST
 
233
         requests, we'll initialize the list/hash with "create-txn"
 
234
         (which we know is supported by virtue of the server speaking
 
235
         HTTPv2 at all. */
 
236
      if (! session->supported_posts)
 
237
        {
 
238
          session->supported_posts = apr_hash_make(session->pool);
 
239
          apr_hash_set(session->supported_posts, "create-txn", 10, (void *)1);
 
240
        }
 
241
 
332
242
      if (svn_cstring_casecmp(key, SVN_DAV_ROOT_URI_HEADER) == 0)
333
243
        {
334
 
          orc->session->repos_root = orc->session->session_url;
335
 
          orc->session->repos_root.path =
336
 
            (char *)svn_fspath__canonicalize(val, orc->session->pool);
337
 
          orc->session->repos_root_str =
 
244
          session->repos_root = session->session_url;
 
245
          session->repos_root.path =
 
246
            (char *)svn_fspath__canonicalize(val, session->pool);
 
247
          session->repos_root_str =
338
248
            svn_urlpath__canonicalize(
339
 
                apr_uri_unparse(orc->session->pool,
340
 
                                &orc->session->repos_root,
341
 
                                0),
342
 
                orc->session->pool);
 
249
                apr_uri_unparse(session->pool, &session->repos_root, 0),
 
250
                session->pool);
343
251
        }
344
252
      else if (svn_cstring_casecmp(key, SVN_DAV_ME_RESOURCE_HEADER) == 0)
345
253
        {
348
256
 
349
257
          if (!(ignore_v2_env_var
350
258
                && apr_strnatcasecmp(ignore_v2_env_var, "yes") == 0))
351
 
            orc->session->me_resource = apr_pstrdup(orc->session->pool, val);
 
259
            session->me_resource = apr_pstrdup(session->pool, val);
352
260
#else
353
 
          orc->session->me_resource = apr_pstrdup(orc->session->pool, val);
 
261
          session->me_resource = apr_pstrdup(session->pool, val);
354
262
#endif
355
263
        }
356
264
      else if (svn_cstring_casecmp(key, SVN_DAV_REV_STUB_HEADER) == 0)
357
265
        {
358
 
          orc->session->rev_stub = apr_pstrdup(orc->session->pool, val);
 
266
          session->rev_stub = apr_pstrdup(session->pool, val);
359
267
        }
360
268
      else if (svn_cstring_casecmp(key, SVN_DAV_REV_ROOT_STUB_HEADER) == 0)
361
269
        {
362
 
          orc->session->rev_root_stub = apr_pstrdup(orc->session->pool, val);
 
270
          session->rev_root_stub = apr_pstrdup(session->pool, val);
363
271
        }
364
272
      else if (svn_cstring_casecmp(key, SVN_DAV_TXN_STUB_HEADER) == 0)
365
273
        {
366
 
          orc->session->txn_stub = apr_pstrdup(orc->session->pool, val);
 
274
          session->txn_stub = apr_pstrdup(session->pool, val);
367
275
        }
368
276
      else if (svn_cstring_casecmp(key, SVN_DAV_TXN_ROOT_STUB_HEADER) == 0)
369
277
        {
370
 
          orc->session->txn_root_stub = apr_pstrdup(orc->session->pool, val);
 
278
          session->txn_root_stub = apr_pstrdup(session->pool, val);
371
279
        }
372
280
      else if (svn_cstring_casecmp(key, SVN_DAV_VTXN_STUB_HEADER) == 0)
373
281
        {
374
 
          orc->session->vtxn_stub = apr_pstrdup(orc->session->pool, val);
 
282
          session->vtxn_stub = apr_pstrdup(session->pool, val);
375
283
        }
376
284
      else if (svn_cstring_casecmp(key, SVN_DAV_VTXN_ROOT_STUB_HEADER) == 0)
377
285
        {
378
 
          orc->session->vtxn_root_stub = apr_pstrdup(orc->session->pool, val);
 
286
          session->vtxn_root_stub = apr_pstrdup(session->pool, val);
379
287
        }
380
288
      else if (svn_cstring_casecmp(key, SVN_DAV_REPOS_UUID_HEADER) == 0)
381
289
        {
382
 
          orc->session->uuid = apr_pstrdup(orc->session->pool, val);
 
290
          session->uuid = apr_pstrdup(session->pool, val);
383
291
        }
384
292
      else if (svn_cstring_casecmp(key, SVN_DAV_YOUNGEST_REV_HEADER) == 0)
385
293
        {
386
 
          struct svn_ra_serf__options_context_t *user_data =
387
 
            orc->parser_ctx->user_data;
388
 
          user_data->youngest_rev = SVN_STR_TO_REV(val);
 
294
          opt_ctx->youngest_rev = SVN_STR_TO_REV(val);
 
295
        }
 
296
      else if (svn_cstring_casecmp(key, SVN_DAV_ALLOW_BULK_UPDATES) == 0)
 
297
        {
 
298
          session->server_allows_bulk = apr_pstrdup(session->pool, val);
 
299
        }
 
300
      else if (svn_cstring_casecmp(key, SVN_DAV_SUPPORTED_POSTS_HEADER) == 0)
 
301
        {
 
302
          /* May contain multiple values, separated by commas. */
 
303
          int i;
 
304
          apr_array_header_t *vals = svn_cstring_split(val, ",", TRUE,
 
305
                                                       opt_ctx->pool);
 
306
 
 
307
          for (i = 0; i < vals->nelts; i++)
 
308
            {
 
309
              const char *post_val = APR_ARRAY_IDX(vals, i, const char *);
 
310
 
 
311
              svn_hash_sets(session->supported_posts, post_val, (void *)1);
 
312
            }
 
313
        }
 
314
      else if (svn_cstring_casecmp(key, SVN_DAV_REPOSITORY_MERGEINFO) == 0)
 
315
        {
 
316
          if (svn_cstring_casecmp(val, "yes") == 0)
 
317
            {
 
318
              svn_hash_sets(session->capabilities, SVN_RA_CAPABILITY_MERGEINFO,
 
319
                            capability_yes);
 
320
            }
 
321
          else if (svn_cstring_casecmp(val, "no") == 0)
 
322
            {
 
323
              svn_hash_sets(session->capabilities, SVN_RA_CAPABILITY_MERGEINFO,
 
324
                            capability_no);
 
325
            }
389
326
        }
390
327
    }
391
328
 
394
331
 
395
332
 
396
333
/* A custom serf_response_handler_t which is mostly a wrapper around
397
 
   svn_ra_serf__handle_xml_parser -- it just notices OPTIONS response
 
334
   the expat-based response handler -- it just notices OPTIONS response
398
335
   headers first, before handing off to the xml parser.
399
336
   Implements svn_ra_serf__response_handler_t */
400
337
static svn_error_t *
403
340
                         void *baton,
404
341
                         apr_pool_t *pool)
405
342
{
406
 
  struct options_response_ctx_t *orc = baton;
407
 
  serf_bucket_t *hdrs = serf_bucket_response_get_headers(response);
408
 
 
409
 
  /* Start out assuming all capabilities are unsupported. */
410
 
  apr_hash_set(orc->session->capabilities, SVN_RA_CAPABILITY_PARTIAL_REPLAY,
411
 
               APR_HASH_KEY_STRING, capability_no);
412
 
  apr_hash_set(orc->session->capabilities, SVN_RA_CAPABILITY_DEPTH,
413
 
               APR_HASH_KEY_STRING, capability_no);
414
 
  apr_hash_set(orc->session->capabilities, SVN_RA_CAPABILITY_MERGEINFO,
415
 
               APR_HASH_KEY_STRING, capability_no);
416
 
  apr_hash_set(orc->session->capabilities, SVN_RA_CAPABILITY_LOG_REVPROPS,
417
 
               APR_HASH_KEY_STRING, capability_no);
418
 
  apr_hash_set(orc->session->capabilities, SVN_RA_CAPABILITY_ATOMIC_REVPROPS,
419
 
               APR_HASH_KEY_STRING, capability_no);
420
 
 
421
 
  /* Then see which ones we can discover. */
422
 
  serf_bucket_headers_do(hdrs, capabilities_headers_iterator_callback, orc);
423
 
 
424
 
  /* Execute the 'real' response handler to XML-parse the repsonse body. */
425
 
  return svn_ra_serf__handle_xml_parser(request, response,
426
 
                                        orc->parser_ctx, pool);
 
343
  options_context_t *opt_ctx = baton;
 
344
 
 
345
  if (!opt_ctx->headers_processed)
 
346
    {
 
347
      svn_ra_serf__session_t *session = opt_ctx->session;
 
348
      serf_bucket_t *hdrs = serf_bucket_response_get_headers(response);
 
349
 
 
350
      /* Start out assuming all capabilities are unsupported. */
 
351
      svn_hash_sets(session->capabilities, SVN_RA_CAPABILITY_PARTIAL_REPLAY,
 
352
                    capability_no);
 
353
      svn_hash_sets(session->capabilities, SVN_RA_CAPABILITY_DEPTH,
 
354
                    capability_no);
 
355
      svn_hash_sets(session->capabilities, SVN_RA_CAPABILITY_MERGEINFO,
 
356
                    NULL);
 
357
      svn_hash_sets(session->capabilities, SVN_RA_CAPABILITY_LOG_REVPROPS,
 
358
                    capability_no);
 
359
      svn_hash_sets(session->capabilities, SVN_RA_CAPABILITY_ATOMIC_REVPROPS,
 
360
                    capability_no);
 
361
      svn_hash_sets(session->capabilities, SVN_RA_CAPABILITY_INHERITED_PROPS,
 
362
                    capability_no);
 
363
      svn_hash_sets(session->capabilities, SVN_RA_CAPABILITY_EPHEMERAL_TXNPROPS,
 
364
                    capability_no);
 
365
      svn_hash_sets(session->capabilities, SVN_RA_CAPABILITY_GET_FILE_REVS_REVERSE,
 
366
                    capability_no);
 
367
 
 
368
      /* Then see which ones we can discover. */
 
369
      serf_bucket_headers_do(hdrs, capabilities_headers_iterator_callback,
 
370
                             opt_ctx);
 
371
 
 
372
      /* Assume mergeinfo capability unsupported, if didn't recieve information
 
373
         about server or repository mergeinfo capability. */
 
374
      if (!svn_hash_gets(session->capabilities, SVN_RA_CAPABILITY_MERGEINFO))
 
375
        svn_hash_sets(session->capabilities, SVN_RA_CAPABILITY_MERGEINFO,
 
376
                      capability_no);
 
377
 
 
378
      opt_ctx->headers_processed = TRUE;
 
379
    }
 
380
 
 
381
  /* Execute the 'real' response handler to XML-parse the response body. */
 
382
  return opt_ctx->inner_handler(request, response, opt_ctx->inner_baton, pool);
427
383
}
428
384
 
429
385
 
430
 
svn_error_t *
431
 
svn_ra_serf__create_options_req(svn_ra_serf__options_context_t **opt_ctx,
432
 
                                svn_ra_serf__session_t *session,
433
 
                                svn_ra_serf__connection_t *conn,
434
 
                                const char *path,
435
 
                                apr_pool_t *pool)
 
386
static svn_error_t *
 
387
create_options_req(options_context_t **opt_ctx,
 
388
                   svn_ra_serf__session_t *session,
 
389
                   svn_ra_serf__connection_t *conn,
 
390
                   apr_pool_t *pool)
436
391
{
437
 
  svn_ra_serf__options_context_t *new_ctx;
 
392
  options_context_t *new_ctx;
 
393
  svn_ra_serf__xml_context_t *xmlctx;
438
394
  svn_ra_serf__handler_t *handler;
439
 
  svn_ra_serf__xml_parser_t *parser_ctx;
440
 
  struct options_response_ctx_t *options_response_ctx;
441
395
 
442
396
  new_ctx = apr_pcalloc(pool, sizeof(*new_ctx));
443
 
 
444
397
  new_ctx->pool = pool;
445
 
 
446
 
  new_ctx->path = path;
447
 
  new_ctx->youngest_rev = SVN_INVALID_REVNUM;
448
 
 
449
398
  new_ctx->session = session;
450
399
  new_ctx->conn = conn;
451
400
 
452
 
  handler = apr_pcalloc(pool, sizeof(*handler));
 
401
  new_ctx->youngest_rev = SVN_INVALID_REVNUM;
 
402
 
 
403
  xmlctx = svn_ra_serf__xml_context_create(options_ttable,
 
404
                                           NULL, options_closed, NULL,
 
405
                                           new_ctx,
 
406
                                           pool);
 
407
  handler = svn_ra_serf__create_expat_handler(xmlctx, pool);
453
408
 
454
409
  handler->method = "OPTIONS";
455
 
  handler->path = path;
 
410
  handler->path = session->session_url.path;
456
411
  handler->body_delegate = create_options_body;
457
412
  handler->body_type = "text/xml";
458
413
  handler->conn = conn;
459
414
  handler->session = session;
460
415
 
461
 
  parser_ctx = apr_pcalloc(pool, sizeof(*parser_ctx));
462
 
 
463
 
  parser_ctx->pool = pool;
464
 
  parser_ctx->user_data = new_ctx;
465
 
  parser_ctx->start = start_options;
466
 
  parser_ctx->end = end_options;
467
 
  parser_ctx->cdata = cdata_options;
468
 
  parser_ctx->done = &new_ctx->done;
469
 
  parser_ctx->status_code = &new_ctx->status_code;
470
 
 
471
 
  options_response_ctx = apr_pcalloc(pool, sizeof(*options_response_ctx));
472
 
  options_response_ctx->parser_ctx = parser_ctx;
473
 
  options_response_ctx->session = session;
474
 
  options_response_ctx->pool = pool;
475
 
 
 
416
  new_ctx->handler = handler;
 
417
 
 
418
  new_ctx->inner_handler = handler->response_handler;
 
419
  new_ctx->inner_baton = handler->response_baton;
476
420
  handler->response_handler = options_response_handler;
477
 
  handler->response_baton = options_response_ctx;
478
 
 
479
 
  svn_ra_serf__request_create(handler);
480
 
 
481
 
  new_ctx->parser_ctx = parser_ctx;
 
421
  handler->response_baton = new_ctx;
482
422
 
483
423
  *opt_ctx = new_ctx;
484
424
 
486
426
}
487
427
 
488
428
 
 
429
svn_error_t *
 
430
svn_ra_serf__v2_get_youngest_revnum(svn_revnum_t *youngest,
 
431
                                    svn_ra_serf__connection_t *conn,
 
432
                                    apr_pool_t *scratch_pool)
 
433
{
 
434
  svn_ra_serf__session_t *session = conn->session;
 
435
  options_context_t *opt_ctx;
 
436
 
 
437
  SVN_ERR_ASSERT(SVN_RA_SERF__HAVE_HTTPV2_SUPPORT(session));
 
438
 
 
439
  SVN_ERR(create_options_req(&opt_ctx, session, conn, scratch_pool));
 
440
  SVN_ERR(svn_ra_serf__context_run_one(opt_ctx->handler, scratch_pool));
 
441
  SVN_ERR(svn_ra_serf__error_on_status(opt_ctx->handler->sline,
 
442
                                       opt_ctx->handler->path,
 
443
                                       opt_ctx->handler->location));
 
444
 
 
445
  *youngest = opt_ctx->youngest_rev;
 
446
  SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(*youngest));
 
447
 
 
448
  return SVN_NO_ERROR;
 
449
}
 
450
 
 
451
 
 
452
svn_error_t *
 
453
svn_ra_serf__v1_get_activity_collection(const char **activity_url,
 
454
                                        svn_ra_serf__connection_t *conn,
 
455
                                        apr_pool_t *result_pool,
 
456
                                        apr_pool_t *scratch_pool)
 
457
{
 
458
  svn_ra_serf__session_t *session = conn->session;
 
459
  options_context_t *opt_ctx;
 
460
 
 
461
  SVN_ERR_ASSERT(!SVN_RA_SERF__HAVE_HTTPV2_SUPPORT(session));
 
462
 
 
463
  SVN_ERR(create_options_req(&opt_ctx, session, conn, scratch_pool));
 
464
  SVN_ERR(svn_ra_serf__context_run_one(opt_ctx->handler, scratch_pool));
 
465
 
 
466
  SVN_ERR(svn_ra_serf__error_on_status(opt_ctx->handler->sline,
 
467
                                       opt_ctx->handler->path,
 
468
                                       opt_ctx->handler->location));
 
469
 
 
470
  *activity_url = apr_pstrdup(result_pool, opt_ctx->activity_collection);
 
471
 
 
472
  return SVN_NO_ERROR;
 
473
 
 
474
}
 
475
 
 
476
 
489
477
 
490
478
/** Capabilities exchange. */
491
479
 
494
482
                                   const char **corrected_url,
495
483
                                   apr_pool_t *pool)
496
484
{
497
 
  svn_ra_serf__options_context_t *opt_ctx;
 
485
  options_context_t *opt_ctx;
498
486
  svn_error_t *err;
499
487
 
500
488
  /* This routine automatically fills in serf_sess->capabilities */
501
 
  SVN_ERR(svn_ra_serf__create_options_req(&opt_ctx, serf_sess,
502
 
                                          serf_sess->conns[0],
503
 
                                          serf_sess->session_url.path, pool));
 
489
  SVN_ERR(create_options_req(&opt_ctx, serf_sess, serf_sess->conns[0], pool));
504
490
 
505
 
  err = svn_ra_serf__context_run_wait(
506
 
            svn_ra_serf__get_options_done_ptr(opt_ctx), serf_sess, pool);
 
491
  err = svn_ra_serf__context_run_one(opt_ctx->handler, pool);
507
492
 
508
493
  /* If our caller cares about server redirections, and our response
509
494
     carries such a thing, report as much.  We'll disregard ERR --
510
495
     it's most likely just a complaint about the response body not
511
496
     successfully parsing as XML or somesuch. */
512
 
  if (corrected_url && (opt_ctx->status_code == 301))
 
497
  if (corrected_url && (opt_ctx->handler->sline.code == 301))
513
498
    {
514
499
      svn_error_clear(err);
515
 
      *corrected_url = opt_ctx->parser_ctx->location;
 
500
      *corrected_url = opt_ctx->handler->location;
516
501
      return SVN_NO_ERROR;
517
502
    }
518
503
 
519
504
  SVN_ERR(svn_error_compose_create(
520
 
              svn_ra_serf__error_on_status(opt_ctx->status_code,
 
505
              svn_ra_serf__error_on_status(opt_ctx->handler->sline,
521
506
                                           serf_sess->session_url.path,
522
 
                                           opt_ctx->parser_ctx->location),
 
507
                                           opt_ctx->handler->location),
523
508
              err));
524
509
 
525
510
  /* Opportunistically cache any reported activity URL.  (We don't
535
520
}
536
521
 
537
522
 
 
523
static svn_error_t *
 
524
create_simple_options_body(serf_bucket_t **body_bkt,
 
525
                           void *baton,
 
526
                           serf_bucket_alloc_t *alloc,
 
527
                           apr_pool_t *pool)
 
528
{
 
529
  serf_bucket_t *body;
 
530
  serf_bucket_t *s;
 
531
 
 
532
  body = serf_bucket_aggregate_create(alloc);
 
533
  svn_ra_serf__add_xml_header_buckets(body, alloc);
 
534
 
 
535
  s = SERF_BUCKET_SIMPLE_STRING("<D:options xmlns:D=\"DAV:\" />", alloc);
 
536
  serf_bucket_aggregate_append(body, s);
 
537
 
 
538
  *body_bkt = body;
 
539
  return SVN_NO_ERROR;
 
540
}
 
541
 
 
542
 
 
543
svn_error_t *
 
544
svn_ra_serf__probe_proxy(svn_ra_serf__session_t *serf_sess,
 
545
                         apr_pool_t *scratch_pool)
 
546
{
 
547
  svn_ra_serf__handler_t *handler;
 
548
 
 
549
  handler = apr_pcalloc(scratch_pool, sizeof(*handler));
 
550
  handler->handler_pool = scratch_pool;
 
551
  handler->method = "OPTIONS";
 
552
  handler->path = serf_sess->session_url.path;
 
553
  handler->conn = serf_sess->conns[0];
 
554
  handler->session = serf_sess;
 
555
 
 
556
  /* We don't care about the response body, so discard it.  */
 
557
  handler->response_handler = svn_ra_serf__handle_discard_body;
 
558
 
 
559
  /* We need a simple body, in order to send it in chunked format.  */
 
560
  handler->body_delegate = create_simple_options_body;
 
561
 
 
562
  /* No special headers.  */
 
563
 
 
564
  SVN_ERR(svn_ra_serf__context_run_one(handler, scratch_pool));
 
565
  /* Some versions of nginx in reverse proxy mode will return 411. They want
 
566
     a Content-Length header, rather than chunked requests. We can keep other
 
567
     HTTP/1.1 features, but will disable the chunking.  */
 
568
  if (handler->sline.code == 411)
 
569
    {
 
570
      serf_sess->using_chunked_requests = FALSE;
 
571
 
 
572
      return SVN_NO_ERROR;
 
573
    }
 
574
  SVN_ERR(svn_ra_serf__error_on_status(handler->sline,
 
575
                                       handler->path,
 
576
                                       handler->location));
 
577
 
 
578
  return SVN_NO_ERROR;
 
579
}
 
580
 
 
581
 
538
582
svn_error_t *
539
583
svn_ra_serf__has_capability(svn_ra_session_t *ra_session,
540
584
                            svn_boolean_t *has,
551
595
      return SVN_NO_ERROR;
552
596
    }
553
597
 
554
 
  cap_result = apr_hash_get(serf_sess->capabilities,
555
 
                            capability,
556
 
                            APR_HASH_KEY_STRING);
 
598
  cap_result = svn_hash_gets(serf_sess->capabilities, capability);
557
599
 
558
600
  /* If any capability is unknown, they're all unknown, so ask. */
559
601
  if (cap_result == NULL)
560
602
    SVN_ERR(svn_ra_serf__exchange_capabilities(serf_sess, NULL, pool));
561
603
 
562
604
  /* Try again, now that we've fetched the capabilities. */
563
 
  cap_result = apr_hash_get(serf_sess->capabilities,
564
 
                            capability, APR_HASH_KEY_STRING);
 
605
  cap_result = svn_hash_gets(serf_sess->capabilities, capability);
565
606
 
566
 
  /* Some capabilities depend on the repository as well as the server.
567
 
     NOTE: svn_ra_neon__has_capability() has a very similar code block.  If
568
 
     you change something here, check there as well. */
 
607
  /* Some capabilities depend on the repository as well as the server. */
569
608
  if (cap_result == capability_server_yes)
570
609
    {
571
610
      if (strcmp(capability, SVN_RA_CAPABILITY_MERGEINFO) == 0)
609
648
          else
610
649
            cap_result = capability_yes;
611
650
 
612
 
            apr_hash_set(serf_sess->capabilities,
613
 
                         SVN_RA_CAPABILITY_MERGEINFO, APR_HASH_KEY_STRING,
614
 
                         cap_result);
 
651
          svn_hash_sets(serf_sess->capabilities,
 
652
                        SVN_RA_CAPABILITY_MERGEINFO,  cap_result);
615
653
        }
616
654
      else
617
655
        {