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

« back to all changes in this revision

Viewing changes to subversion/libsvn_ra_serf/property.c

  • Committer: Package Import Robot
  • Author(s): James McCoy
  • Date: 2015-08-07 21:32:47 UTC
  • mfrom: (0.2.15) (4.1.7 experimental)
  • Revision ID: package-import@ubuntu.com-20150807213247-ozyewtmgsr6tkewl
Tags: 1.9.0-1
* Upload to unstable
* New upstream release.
  + Security fixes
    - CVE-2015-3184: Mixed anonymous/authenticated path-based authz with
      httpd 2.4
    - CVE-2015-3187: svn_repos_trace_node_locations() reveals paths hidden
      by authz
* Add >= 2.7 requirement for python-all-dev Build-Depends, needed to run
  tests.
* Remove Build-Conflicts against ruby-test-unit.  (Closes: #791844)
* Remove patches/apache_module_dependency in favor of expressing the
  dependencies in authz_svn.load/dav_svn.load.
* Build-Depend on apache2-dev (>= 2.4.16) to ensure ap_some_authn_required()
  is available when building mod_authz_svn and Depend on apache2-bin (>=
  2.4.16) for runtime support.

Show diffs side-by-side

added added

removed removed

Lines of Context:
42
42
 
43
43
/* Our current parsing state we're in for the PROPFIND response. */
44
44
typedef enum prop_state_e {
45
 
  INITIAL = 0,
 
45
  INITIAL = XML_STATE_INITIAL,
46
46
  MULTISTATUS,
47
47
  RESPONSE,
48
48
  HREF,
59
59
 * This structure represents a pending PROPFIND response.
60
60
 */
61
61
typedef struct propfind_context_t {
62
 
  /* pool to issue allocations from */
63
 
  apr_pool_t *pool;
64
 
 
65
62
  svn_ra_serf__handler_t *handler;
66
63
 
67
 
  /* associated serf session */
68
 
  svn_ra_serf__session_t *sess;
69
 
  svn_ra_serf__connection_t *conn;
70
 
 
71
64
  /* the requested path */
72
65
  const char *path;
73
66
 
74
 
  /* the requested version (number and string form) */
75
 
  svn_revnum_t rev;
 
67
  /* the requested version (in string form) */
76
68
  const char *label;
77
69
 
78
70
  /* the request depth */
81
73
  /* the list of requested properties */
82
74
  const svn_ra_serf__dav_props_t *find_props;
83
75
 
84
 
  /* hash table that will be updated with the properties
85
 
   *
86
 
   * This can be shared between multiple propfind_context_t
87
 
   * structures
88
 
   */
89
 
  apr_hash_t *ret_props;
 
76
  svn_ra_serf__prop_func_t prop_func;
 
77
  void *prop_func_baton;
90
78
 
91
79
  /* hash table containing all the properties associated with the
92
80
   * "current" <propstat> tag.  These will get copied into RET_PROPS
94
82
   * "good"; otherwise, they'll get discarded.
95
83
   */
96
84
  apr_hash_t *ps_props;
97
 
 
98
 
  /* If not-NULL, add us to this list when we're done. */
99
 
  svn_ra_serf__list_t **done_list;
100
 
 
101
 
  svn_ra_serf__list_t done_item;
102
 
 
103
85
} propfind_context_t;
104
86
 
105
87
 
136
118
  { 0 }
137
119
};
138
120
 
 
121
static const int propfind_expected_status[] = {
 
122
  207,
 
123
  0
 
124
};
139
125
 
140
126
/* Return the HTTP status code contained in STATUS_LINE, or 0 if
141
127
   there's a problem parsing it. */
142
 
static int parse_status_code(const char *status_line)
 
128
static apr_int64_t parse_status_code(const char *status_line)
143
129
{
144
130
  /* STATUS_LINE should be of form: "HTTP/1.1 200 OK" */
145
131
  if (status_line[0] == 'H' &&
159
145
  return 0;
160
146
}
161
147
 
162
 
 
163
 
/* Conforms to svn_ra_serf__path_rev_walker_t  */
164
 
static svn_error_t *
165
 
copy_into_ret_props(void *baton,
166
 
                    const char *path, apr_ssize_t path_len,
167
 
                    const char *ns, apr_ssize_t ns_len,
168
 
                    const char *name, apr_ssize_t name_len,
169
 
                    const svn_string_t *val,
170
 
                    apr_pool_t *pool)
171
 
{
172
 
  propfind_context_t *ctx = baton;
173
 
 
174
 
  svn_ra_serf__set_ver_prop(ctx->ret_props, path, ctx->rev, ns, name,
175
 
                            val, ctx->pool);
176
 
  return SVN_NO_ERROR;
177
 
}
178
 
 
179
 
 
180
148
/* Conforms to svn_ra_serf__xml_opened_t  */
181
149
static svn_error_t *
182
150
propfind_opened(svn_ra_serf__xml_estate_t *xes,
189
157
 
190
158
  if (entered_state == PROPVAL)
191
159
    {
192
 
      svn_ra_serf__xml_note(xes, PROPVAL, "ns", tag->namespace);
 
160
        svn_ra_serf__xml_note(xes, PROPVAL, "ns", tag->xmlns);
193
161
      svn_ra_serf__xml_note(xes, PROPVAL, "name", tag->name);
194
162
    }
195
163
  else if (entered_state == PROPSTAT)
196
164
    {
197
 
      ctx->ps_props = apr_hash_make(ctx->pool);
 
165
      ctx->ps_props = apr_hash_make(svn_ra_serf__xml_state_pool(xes));
198
166
    }
199
167
 
200
168
  return SVN_NO_ERROR;
201
169
}
202
170
 
 
171
/* Set PROPS for NS:NAME VAL. Helper for propfind_closed */
 
172
static void
 
173
set_ns_prop(apr_hash_t *ns_props,
 
174
            const char *ns, const char *name,
 
175
            const svn_string_t *val, apr_pool_t *result_pool)
 
176
{
 
177
  apr_hash_t *props = svn_hash_gets(ns_props, ns);
 
178
 
 
179
  if (!props)
 
180
    {
 
181
      props = apr_hash_make(result_pool);
 
182
      ns = apr_pstrdup(result_pool, ns);
 
183
      svn_hash_sets(ns_props, ns, props);
 
184
    }
 
185
 
 
186
  if (val)
 
187
    {
 
188
      name = apr_pstrdup(result_pool, name);
 
189
      val = svn_string_dup(val, result_pool);
 
190
    }
 
191
 
 
192
  svn_hash_sets(props, name, val);
 
193
}
203
194
 
204
195
/* Conforms to svn_ra_serf__xml_closed_t  */
205
196
static svn_error_t *
218
209
         onto the "done list". External callers will then know this
219
210
         request has been completed (tho stray response bytes may still
220
211
         arrive).  */
221
 
      if (ctx->done_list)
222
 
        {
223
 
          ctx->done_item.data = ctx->handler;
224
 
          ctx->done_item.next = *ctx->done_list;
225
 
          *ctx->done_list = &ctx->done_item;
226
 
        }
227
212
    }
228
213
  else if (leaving_state == HREF)
229
214
    {
230
215
      const char *path;
231
 
      const svn_string_t *val_str;
232
216
 
233
217
      if (strcmp(ctx->depth, "1") == 0)
234
218
        path = svn_urlpath__canonicalize(cdata->data, scratch_pool);
237
221
 
238
222
      svn_ra_serf__xml_note(xes, RESPONSE, "path", path);
239
223
 
240
 
      /* Copy the value into the right pool, then save the HREF.  */
241
 
      val_str = svn_string_dup(cdata, ctx->pool);
242
 
      svn_ra_serf__set_ver_prop(ctx->ret_props,
243
 
                                path, ctx->rev, D_, "href", val_str,
244
 
                                ctx->pool);
 
224
      SVN_ERR(ctx->prop_func(ctx->prop_func_baton,
 
225
                             path,
 
226
                             D_, "href",
 
227
                             cdata, scratch_pool));
245
228
    }
246
229
  else if (leaving_state == COLLECTION)
247
230
    {
257
240
         that we wish to ignore.  (Typically, if it's not a 200, the
258
241
         status will be 404 to indicate that a property we
259
242
         specifically requested from the server doesn't exist.)  */
260
 
      int status = parse_status_code(cdata->data);
 
243
      apr_int64_t status = parse_status_code(cdata->data);
261
244
      if (status != 200)
262
245
        svn_ra_serf__xml_note(xes, PROPSTAT, "ignore-prop", "*");
263
246
    }
264
247
  else if (leaving_state == PROPVAL)
265
248
    {
266
 
      const char *encoding = svn_hash_gets(attrs, "V:encoding");
 
249
      const char *encoding;
267
250
      const svn_string_t *val_str;
268
 
      apr_hash_t *gathered;
269
 
      const char *path;
270
251
      const char *ns;
271
252
      const char *name;
272
253
      const char *altvalue;
273
254
 
274
 
      if (encoding)
 
255
      if ((altvalue = svn_hash_gets(attrs, "altvalue")) != NULL)
 
256
        {
 
257
          val_str = svn_string_create(altvalue, scratch_pool);
 
258
        }
 
259
      else if ((encoding = svn_hash_gets(attrs, "V:encoding")) != NULL)
275
260
        {
276
261
          if (strcmp(encoding, "base64") != 0)
277
262
            return svn_error_createf(SVN_ERR_RA_DAV_MALFORMED_DATA,
280
265
                                     encoding);
281
266
 
282
267
          /* Decode into the right pool.  */
283
 
          val_str = svn_base64_decode_string(cdata, ctx->pool);
 
268
          val_str = svn_base64_decode_string(cdata, scratch_pool);
284
269
        }
285
270
      else
286
271
        {
287
272
          /* Copy into the right pool.  */
288
 
          val_str = svn_string_dup(cdata, ctx->pool);
 
273
          val_str = cdata;
289
274
        }
290
275
 
291
 
      /* The current path sits on the RESPONSE state. Gather up all the
292
 
         state from this PROPVAL to the (grandparent) RESPONSE state,
293
 
         and grab the path from there.
 
276
      /* The current path sits on the RESPONSE state.
294
277
 
295
278
         Now, it would be nice if we could, at this point, know that
296
279
         the status code for this property indicated a problem -- then
300
283
         here, setting the property and value as expected.  Once we
301
284
         know for sure the status code associate with the property,
302
285
         we'll decide its fate.  */
303
 
      gathered = svn_ra_serf__xml_gather_since(xes, RESPONSE);
304
 
 
305
 
      /* These will be dup'd into CTX->POOL, as necessary.  */
306
 
      path = svn_hash_gets(gathered, "path");
307
 
      if (path == NULL)
308
 
        path = ctx->path;
309
286
 
310
287
      ns = svn_hash_gets(attrs, "ns");
311
 
      name = apr_pstrdup(ctx->pool,
312
 
                         svn_hash_gets(attrs, "name"));
313
 
 
314
 
      altvalue = svn_hash_gets(attrs, "altvalue");
315
 
      if (altvalue != NULL)
316
 
        val_str = svn_string_create(altvalue, ctx->pool);
317
 
 
318
 
      svn_ra_serf__set_ver_prop(ctx->ps_props,
319
 
                                path, ctx->rev, ns, name, val_str,
320
 
                                ctx->pool);
 
288
      name = svn_hash_gets(attrs, "name");
 
289
 
 
290
      set_ns_prop(ctx->ps_props, ns, name, val_str,
 
291
                  apr_hash_pool_get(ctx->ps_props));
321
292
    }
322
293
  else
323
294
    {
325
296
 
326
297
      SVN_ERR_ASSERT(leaving_state == PROPSTAT);
327
298
 
328
 
      gathered = svn_ra_serf__xml_gather_since(xes, PROPSTAT);
 
299
      gathered = svn_ra_serf__xml_gather_since(xes, RESPONSE);
329
300
 
330
301
      /* If we've squirreled away a note that says we want to ignore
331
302
         these properties, we'll do so.  Otherwise, we need to copy
332
303
         them from the temporary hash into the ctx->ret_props hash. */
333
304
      if (! svn_hash_gets(gathered, "ignore-prop"))
334
305
        {
335
 
          SVN_ERR(svn_ra_serf__walk_all_paths(ctx->ps_props, ctx->rev,
336
 
                                              copy_into_ret_props, ctx,
337
 
                                              scratch_pool));
338
 
        }
339
 
 
340
 
      ctx->ps_props = NULL;
341
 
    }
342
 
 
343
 
  return SVN_NO_ERROR;
344
 
}
345
 
 
346
 
 
347
 
const svn_string_t *
348
 
svn_ra_serf__get_ver_prop_string(apr_hash_t *props,
349
 
                                 const char *path,
350
 
                                 svn_revnum_t rev,
351
 
                                 const char *ns,
352
 
                                 const char *name)
353
 
{
354
 
  apr_hash_t *ver_props, *path_props, *ns_props;
355
 
  void *val = NULL;
356
 
 
357
 
  ver_props = apr_hash_get(props, &rev, sizeof(rev));
358
 
  if (ver_props)
359
 
    {
360
 
      path_props = svn_hash_gets(ver_props, path);
361
 
 
362
 
      if (path_props)
363
 
        {
364
 
          ns_props = svn_hash_gets(path_props, ns);
365
 
          if (ns_props)
 
306
          apr_hash_index_t *hi_ns;
 
307
          const char *path;
 
308
          apr_pool_t *iterpool = svn_pool_create(scratch_pool);
 
309
 
 
310
 
 
311
          path = svn_hash_gets(gathered, "path");
 
312
          if (!path)
 
313
            path = ctx->path;
 
314
 
 
315
          for (hi_ns = apr_hash_first(scratch_pool, ctx->ps_props);
 
316
               hi_ns;
 
317
               hi_ns = apr_hash_next(hi_ns))
366
318
            {
367
 
              val = svn_hash_gets(ns_props, name);
 
319
              const char *ns = apr_hash_this_key(hi_ns);
 
320
              apr_hash_t *props = apr_hash_this_val(hi_ns);
 
321
              apr_hash_index_t *hi_prop;
 
322
 
 
323
              svn_pool_clear(iterpool);
 
324
 
 
325
              for (hi_prop = apr_hash_first(iterpool, props);
 
326
                   hi_prop;
 
327
                   hi_prop = apr_hash_next(hi_prop))
 
328
                {
 
329
                  const char *name = apr_hash_this_key(hi_prop);
 
330
                  const svn_string_t *value = apr_hash_this_val(hi_prop);
 
331
 
 
332
                  SVN_ERR(ctx->prop_func(ctx->prop_func_baton, path,
 
333
                                         ns, name, value, iterpool));
 
334
                }
368
335
            }
 
336
 
 
337
          svn_pool_destroy(iterpool);
369
338
        }
370
 
    }
371
 
 
372
 
  return val;
373
 
}
374
 
 
375
 
const char *
376
 
svn_ra_serf__get_ver_prop(apr_hash_t *props,
377
 
                          const char *path,
378
 
                          svn_revnum_t rev,
379
 
                          const char *ns,
380
 
                          const char *name)
381
 
{
382
 
  const svn_string_t *val;
383
 
 
384
 
  val = svn_ra_serf__get_ver_prop_string(props, path, rev, ns, name);
385
 
 
386
 
  if (val)
387
 
    {
388
 
      return val->data;
389
 
    }
390
 
 
391
 
  return NULL;
392
 
}
393
 
 
394
 
const svn_string_t *
395
 
svn_ra_serf__get_prop_string(apr_hash_t *props,
396
 
                             const char *path,
397
 
                             const char *ns,
398
 
                             const char *name)
399
 
{
400
 
  return svn_ra_serf__get_ver_prop_string(props, path, SVN_INVALID_REVNUM,
401
 
                                          ns, name);
402
 
}
403
 
 
404
 
const char *
405
 
svn_ra_serf__get_prop(apr_hash_t *props,
406
 
                      const char *path,
407
 
                      const char *ns,
408
 
                      const char *name)
409
 
{
410
 
  return svn_ra_serf__get_ver_prop(props, path, SVN_INVALID_REVNUM, ns, name);
411
 
}
412
 
 
413
 
void
414
 
svn_ra_serf__set_ver_prop(apr_hash_t *props,
415
 
                          const char *path, svn_revnum_t rev,
416
 
                          const char *ns, const char *name,
417
 
                          const svn_string_t *val, apr_pool_t *pool)
418
 
{
419
 
  apr_hash_t *ver_props, *path_props, *ns_props;
420
 
 
421
 
  ver_props = apr_hash_get(props, &rev, sizeof(rev));
422
 
  if (!ver_props)
423
 
    {
424
 
      ver_props = apr_hash_make(pool);
425
 
      apr_hash_set(props, apr_pmemdup(pool, &rev, sizeof(rev)), sizeof(rev),
426
 
                   ver_props);
427
 
    }
428
 
 
429
 
  path_props = svn_hash_gets(ver_props, path);
430
 
 
431
 
  if (!path_props)
432
 
    {
433
 
      path_props = apr_hash_make(pool);
434
 
      path = apr_pstrdup(pool, path);
435
 
      svn_hash_sets(ver_props, path, path_props);
436
 
 
437
 
      /* todo: we know that we'll fail the next check, but fall through
438
 
       * for now for simplicity's sake.
439
 
       */
440
 
    }
441
 
 
442
 
  ns_props = svn_hash_gets(path_props, ns);
443
 
  if (!ns_props)
444
 
    {
445
 
      ns_props = apr_hash_make(pool);
446
 
      ns = apr_pstrdup(pool, ns);
447
 
      svn_hash_sets(path_props, ns, ns_props);
448
 
    }
449
 
 
450
 
  svn_hash_sets(ns_props, name, val);
451
 
}
452
 
 
453
 
void
454
 
svn_ra_serf__set_prop(apr_hash_t *props,
455
 
                      const char *path,
456
 
                      const char *ns, const char *name,
457
 
                      const svn_string_t *val, apr_pool_t *pool)
458
 
{
459
 
  svn_ra_serf__set_ver_prop(props, path, SVN_INVALID_REVNUM, ns, name,
460
 
                            val, pool);
461
 
}
 
339
 
 
340
      ctx->ps_props = NULL; /* Allocated in PROPSTAT state pool */
 
341
    }
 
342
 
 
343
  return SVN_NO_ERROR;
 
344
}
 
345
 
462
346
 
463
347
 
464
348
static svn_error_t *
465
349
setup_propfind_headers(serf_bucket_t *headers,
466
 
                        void *setup_baton,
467
 
                        apr_pool_t *pool)
 
350
                       void *setup_baton,
 
351
                       apr_pool_t *pool /* request pool */,
 
352
                       apr_pool_t *scratch_pool)
468
353
{
469
354
  propfind_context_t *ctx = setup_baton;
470
355
 
480
365
#define PROPFIND_HEADER "<?xml version=\"1.0\" encoding=\"utf-8\"?><propfind xmlns=\"DAV:\">"
481
366
#define PROPFIND_TRAILER "</propfind>"
482
367
 
 
368
/* Implements svn_ra_serf__request_body_delegate_t */
483
369
static svn_error_t *
484
370
create_propfind_body(serf_bucket_t **bkt,
485
371
                     void *setup_baton,
486
372
                     serf_bucket_alloc_t *alloc,
487
 
                     apr_pool_t *pool)
 
373
                     apr_pool_t *pool /* request pool */,
 
374
                     apr_pool_t *scratch_pool)
488
375
{
489
376
  propfind_context_t *ctx = setup_baton;
490
377
 
495
382
  body_bkt = serf_bucket_aggregate_create(alloc);
496
383
 
497
384
  prop = ctx->find_props;
498
 
  while (prop && prop->namespace)
 
385
  while (prop && prop->xmlns)
499
386
    {
500
387
      /* special case the allprop case. */
501
388
      if (strcmp(prop->name, "allprop") == 0)
515
402
                                          alloc);
516
403
      serf_bucket_aggregate_append(body_bkt, tmp);
517
404
 
518
 
      tmp = SERF_BUCKET_SIMPLE_STRING(prop->namespace, alloc);
 
405
      tmp = SERF_BUCKET_SIMPLE_STRING(prop->xmlns, alloc);
519
406
      serf_bucket_aggregate_append(body_bkt, tmp);
520
407
 
521
408
      tmp = SERF_BUCKET_SIMPLE_STRING_LEN("\"/>", sizeof("\"/>")-1,
559
446
 
560
447
 
561
448
svn_error_t *
562
 
svn_ra_serf__deliver_props(svn_ra_serf__handler_t **propfind_handler,
563
 
                           apr_hash_t *ret_props,
564
 
                           svn_ra_serf__session_t *sess,
565
 
                           svn_ra_serf__connection_t *conn,
566
 
                           const char *path,
567
 
                           svn_revnum_t rev,
568
 
                           const char *depth,
569
 
                           const svn_ra_serf__dav_props_t *find_props,
570
 
                           svn_ra_serf__list_t **done_list,
571
 
                           apr_pool_t *pool)
 
449
svn_ra_serf__create_propfind_handler(svn_ra_serf__handler_t **propfind_handler,
 
450
                                     svn_ra_serf__session_t *sess,
 
451
                                     const char *path,
 
452
                                     svn_revnum_t rev,
 
453
                                     const char *depth,
 
454
                                     const svn_ra_serf__dav_props_t *find_props,
 
455
                                     svn_ra_serf__prop_func_t prop_func,
 
456
                                     void *prop_func_baton,
 
457
                                     apr_pool_t *pool)
572
458
{
573
459
  propfind_context_t *new_prop_ctx;
574
460
  svn_ra_serf__handler_t *handler;
576
462
 
577
463
  new_prop_ctx = apr_pcalloc(pool, sizeof(*new_prop_ctx));
578
464
 
579
 
  new_prop_ctx->pool = apr_hash_pool_get(ret_props);
580
465
  new_prop_ctx->path = path;
581
466
  new_prop_ctx->find_props = find_props;
582
 
  new_prop_ctx->ret_props = ret_props;
 
467
  new_prop_ctx->prop_func = prop_func;
 
468
  new_prop_ctx->prop_func_baton = prop_func_baton;
583
469
  new_prop_ctx->depth = depth;
584
 
  new_prop_ctx->sess = sess;
585
 
  new_prop_ctx->conn = conn;
586
 
  new_prop_ctx->rev = rev;
587
 
  new_prop_ctx->done_list = done_list;
588
470
 
589
471
  if (SVN_IS_VALID_REVNUM(rev))
590
472
    {
601
483
                                           NULL,
602
484
                                           new_prop_ctx,
603
485
                                           pool);
604
 
  handler = svn_ra_serf__create_expat_handler(xmlctx, pool);
 
486
  handler = svn_ra_serf__create_expat_handler(sess, xmlctx,
 
487
                                              propfind_expected_status,
 
488
                                              pool);
605
489
 
606
490
  handler->method = "PROPFIND";
607
491
  handler->path = path;
611
495
  handler->header_delegate = setup_propfind_headers;
612
496
  handler->header_delegate_baton = new_prop_ctx;
613
497
 
614
 
  handler->session = new_prop_ctx->sess;
615
 
  handler->conn = new_prop_ctx->conn;
 
498
  handler->no_dav_headers = TRUE;
616
499
 
617
500
  new_prop_ctx->handler = handler;
618
501
 
621
504
  return SVN_NO_ERROR;
622
505
}
623
506
 
624
 
 
625
 
/*
626
 
 * This helper function will block until the PROP_CTX indicates that is done
627
 
 * or another error is returned.
628
 
 */
629
 
svn_error_t *
630
 
svn_ra_serf__wait_for_props(svn_ra_serf__handler_t *handler,
631
 
                            apr_pool_t *scratch_pool)
632
 
{
633
 
  svn_error_t *err;
634
 
  svn_error_t *err2;
635
 
 
636
 
  err = svn_ra_serf__context_run_one(handler, scratch_pool);
637
 
 
638
 
  err2 = svn_ra_serf__error_on_status(handler->sline,
639
 
                                      handler->path,
640
 
                                      handler->location);
641
 
 
642
 
  return svn_error_compose_create(err2, err);
643
 
}
644
 
 
645
 
/*
646
 
 * This is a blocking version of deliver_props.
647
 
 */
648
 
svn_error_t *
649
 
svn_ra_serf__retrieve_props(apr_hash_t **results,
650
 
                            svn_ra_serf__session_t *sess,
651
 
                            svn_ra_serf__connection_t *conn,
652
 
                            const char *url,
653
 
                            svn_revnum_t rev,
654
 
                            const char *depth,
655
 
                            const svn_ra_serf__dav_props_t *props,
656
 
                            apr_pool_t *result_pool,
657
 
                            apr_pool_t *scratch_pool)
658
 
{
659
 
  svn_ra_serf__handler_t *handler;
660
 
 
661
 
  *results = apr_hash_make(result_pool);
662
 
 
663
 
  SVN_ERR(svn_ra_serf__deliver_props(&handler, *results, sess, conn, url,
664
 
                                     rev, depth, props, NULL, result_pool));
665
 
  SVN_ERR(svn_ra_serf__wait_for_props(handler, scratch_pool));
666
 
 
667
 
  return SVN_NO_ERROR;
668
 
}
669
 
 
 
507
svn_error_t *
 
508
svn_ra_serf__deliver_svn_props(void *baton,
 
509
                               const char *path,
 
510
                               const char *ns,
 
511
                               const char *name,
 
512
                               const svn_string_t *value,
 
513
                               apr_pool_t *scratch_pool)
 
514
{
 
515
  apr_hash_t *props = baton;
 
516
  apr_pool_t *result_pool = apr_hash_pool_get(props);
 
517
  const char *prop_name;
 
518
 
 
519
  prop_name = svn_ra_serf__svnname_from_wirename(ns, name, result_pool);
 
520
  if (prop_name == NULL)
 
521
    return SVN_NO_ERROR;
 
522
 
 
523
  svn_hash_sets(props, prop_name, svn_string_dup(value, result_pool));
 
524
 
 
525
  return SVN_NO_ERROR;
 
526
}
 
527
 
 
528
/*
 
529
 * Implementation of svn_ra_serf__prop_func_t that delivers all DAV properties
 
530
 * in (const char * -> apr_hash_t *) on Namespace pointing to a second hash
 
531
 *    (const char * -> svn_string_t *) to the values.
 
532
 */
 
533
static svn_error_t *
 
534
deliver_node_props(void *baton,
 
535
                  const char *path,
 
536
                  const char *ns,
 
537
                  const char *name,
 
538
                  const svn_string_t *value,
 
539
                  apr_pool_t *scratch_pool)
 
540
{
 
541
  apr_hash_t *nss = baton;
 
542
  apr_hash_t *props;
 
543
  apr_pool_t *result_pool = apr_hash_pool_get(nss);
 
544
 
 
545
  props = svn_hash_gets(nss, ns);
 
546
 
 
547
  if (!props)
 
548
    {
 
549
      props = apr_hash_make(result_pool);
 
550
 
 
551
      ns = apr_pstrdup(result_pool, ns);
 
552
      svn_hash_sets(nss, ns, props);
 
553
    }
 
554
 
 
555
  name = apr_pstrdup(result_pool, name);
 
556
  svn_hash_sets(props, name, svn_string_dup(value, result_pool));
 
557
 
 
558
  return SVN_NO_ERROR;
 
559
}
670
560
 
671
561
svn_error_t *
672
562
svn_ra_serf__fetch_node_props(apr_hash_t **results,
673
 
                              svn_ra_serf__connection_t *conn,
 
563
                              svn_ra_serf__session_t *session,
674
564
                              const char *url,
675
565
                              svn_revnum_t revision,
676
566
                              const svn_ra_serf__dav_props_t *which_props,
677
567
                              apr_pool_t *result_pool,
678
568
                              apr_pool_t *scratch_pool)
679
569
{
680
 
  apr_hash_t *multiprops;
681
 
  apr_hash_t *ver_props;
682
 
 
683
 
  /* Note: a couple extra hash tables and whatnot get into RESULT_POOL.
684
 
     Not a big deal at this point. Theoretically, we could fetch all
685
 
     props into SCRATCH_POOL, then copy just the REVISION/URL props
686
 
     into RESULT_POOL. Too much work for too little gain...  */
687
 
  SVN_ERR(svn_ra_serf__retrieve_props(&multiprops, conn->session, conn,
688
 
                                      url, revision, "0", which_props,
689
 
                                      result_pool, scratch_pool));
690
 
 
691
 
  ver_props = apr_hash_get(multiprops, &revision, sizeof(revision));
692
 
  if (ver_props != NULL)
693
 
    {
694
 
      *results = svn_hash_gets(ver_props, url);
695
 
      if (*results != NULL)
696
 
        return SVN_NO_ERROR;
697
 
    }
698
 
 
699
 
  return svn_error_create(SVN_ERR_RA_DAV_PROPS_NOT_FOUND, NULL,
700
 
                          _("The PROPFIND response did not include "
701
 
                            "the requested properties"));
702
 
}
703
 
 
704
 
 
705
 
svn_error_t *
706
 
svn_ra_serf__walk_node_props(apr_hash_t *props,
707
 
                             svn_ra_serf__walker_visitor_t walker,
708
 
                             void *baton,
709
 
                             apr_pool_t *scratch_pool)
710
 
{
711
 
  apr_pool_t *iterpool;
712
 
  apr_hash_index_t *ns_hi;
713
 
 
714
 
  iterpool = svn_pool_create(scratch_pool);
715
 
  for (ns_hi = apr_hash_first(scratch_pool, props); ns_hi;
716
 
       ns_hi = apr_hash_next(ns_hi))
717
 
    {
718
 
      void *ns_val;
719
 
      const void *ns_name;
720
 
      apr_hash_index_t *name_hi;
721
 
 
722
 
      /* NOTE: We do not clear ITERPOOL in this loop. Generally, there are
723
 
           very few namespaces, so this loop will not have many iterations.
724
 
           Instead, ITERPOOL is used for the inner loop.  */
725
 
 
726
 
      apr_hash_this(ns_hi, &ns_name, NULL, &ns_val);
727
 
 
728
 
      for (name_hi = apr_hash_first(scratch_pool, ns_val); name_hi;
729
 
           name_hi = apr_hash_next(name_hi))
730
 
        {
731
 
          void *prop_val;
732
 
          const void *prop_name;
733
 
 
734
 
          /* See note above, regarding clearing of this pool.  */
735
 
          svn_pool_clear(iterpool);
736
 
 
737
 
          apr_hash_this(name_hi, &prop_name, NULL, &prop_val);
738
 
 
739
 
          SVN_ERR(walker(baton, ns_name, prop_name, prop_val, iterpool));
740
 
        }
741
 
    }
742
 
  svn_pool_destroy(iterpool);
743
 
 
744
 
  return SVN_NO_ERROR;
745
 
}
746
 
 
747
 
 
748
 
svn_error_t *
749
 
svn_ra_serf__walk_all_props(apr_hash_t *props,
750
 
                            const char *name,
751
 
                            svn_revnum_t rev,
752
 
                            svn_ra_serf__walker_visitor_t walker,
753
 
                            void *baton,
754
 
                            apr_pool_t *scratch_pool)
755
 
{
756
 
  apr_hash_t *ver_props;
757
 
  apr_hash_t *path_props;
758
 
 
759
 
  ver_props = apr_hash_get(props, &rev, sizeof(rev));
760
 
  if (!ver_props)
761
 
    return SVN_NO_ERROR;
762
 
 
763
 
  path_props = svn_hash_gets(ver_props, name);
764
 
  if (!path_props)
765
 
    return SVN_NO_ERROR;
766
 
 
767
 
  return svn_error_trace(svn_ra_serf__walk_node_props(path_props,
768
 
                                                      walker, baton,
769
 
                                                      scratch_pool));
770
 
}
771
 
 
772
 
 
773
 
svn_error_t *
774
 
svn_ra_serf__walk_all_paths(apr_hash_t *props,
775
 
                            svn_revnum_t rev,
776
 
                            svn_ra_serf__path_rev_walker_t walker,
777
 
                            void *baton,
778
 
                            apr_pool_t *pool)
779
 
{
780
 
  apr_hash_index_t *path_hi;
781
 
  apr_hash_t *ver_props;
782
 
 
783
 
  ver_props = apr_hash_get(props, &rev, sizeof(rev));
784
 
 
785
 
  if (!ver_props)
786
 
    {
787
 
      return SVN_NO_ERROR;
788
 
    }
789
 
 
790
 
  for (path_hi = apr_hash_first(pool, ver_props); path_hi;
791
 
       path_hi = apr_hash_next(path_hi))
792
 
    {
793
 
      void *path_props;
794
 
      const void *path_name;
795
 
      apr_ssize_t path_len;
796
 
      apr_hash_index_t *ns_hi;
797
 
 
798
 
      apr_hash_this(path_hi, &path_name, &path_len, &path_props);
799
 
      for (ns_hi = apr_hash_first(pool, path_props); ns_hi;
800
 
           ns_hi = apr_hash_next(ns_hi))
801
 
        {
802
 
          void *ns_val;
803
 
          const void *ns_name;
804
 
          apr_ssize_t ns_len;
805
 
          apr_hash_index_t *name_hi;
806
 
          apr_hash_this(ns_hi, &ns_name, &ns_len, &ns_val);
807
 
          for (name_hi = apr_hash_first(pool, ns_val); name_hi;
808
 
               name_hi = apr_hash_next(name_hi))
809
 
            {
810
 
              void *prop_val;
811
 
              const void *prop_name;
812
 
              apr_ssize_t prop_len;
813
 
 
814
 
              apr_hash_this(name_hi, &prop_name, &prop_len, &prop_val);
815
 
              /* use a subpool? */
816
 
              SVN_ERR(walker(baton, path_name, path_len, ns_name, ns_len,
817
 
                             prop_name, prop_len, prop_val, pool));
818
 
            }
819
 
        }
820
 
    }
821
 
 
822
 
  return SVN_NO_ERROR;
823
 
}
824
 
 
 
570
  apr_hash_t *props;
 
571
  svn_ra_serf__handler_t *handler;
 
572
 
 
573
  props = apr_hash_make(result_pool);
 
574
 
 
575
  SVN_ERR(svn_ra_serf__create_propfind_handler(&handler, session,
 
576
                                               url, revision, "0", which_props,
 
577
                                               deliver_node_props,
 
578
                                               props, scratch_pool));
 
579
 
 
580
  SVN_ERR(svn_ra_serf__context_run_one(handler, scratch_pool));
 
581
 
 
582
  *results = props;
 
583
  return SVN_NO_ERROR;
 
584
}
825
585
 
826
586
const char *
827
587
svn_ra_serf__svnname_from_wirename(const char *ns,
832
592
    return apr_pstrdup(result_pool, name);
833
593
 
834
594
  if (strcmp(ns, SVN_DAV_PROP_NS_SVN) == 0)
835
 
    return apr_pstrcat(result_pool, SVN_PROP_PREFIX, name, (char *)NULL);
 
595
    return apr_pstrcat(result_pool, SVN_PROP_PREFIX, name, SVN_VA_NULL);
836
596
 
837
597
  if (strcmp(ns, SVN_PROP_PREFIX) == 0)
838
 
    return apr_pstrcat(result_pool, SVN_PROP_PREFIX, name, (char *)NULL);
 
598
    return apr_pstrcat(result_pool, SVN_PROP_PREFIX, name, SVN_VA_NULL);
839
599
 
840
600
  if (strcmp(name, SVN_DAV__VERSION_NAME) == 0)
841
601
    return SVN_PROP_ENTRY_COMMITTED_REV;
863
623
    }
864
624
 
865
625
  /* An unknown namespace, must be a custom property. */
866
 
  return apr_pstrcat(result_pool, ns, name, (char *)NULL);
867
 
}
868
 
 
869
 
 
870
 
/* Conforms to svn_ra_serf__walker_visitor_t  */
871
 
static svn_error_t *
872
 
set_flat_props(void *baton,
873
 
               const char *ns,
874
 
               const char *name,
875
 
               const svn_string_t *value,
876
 
               apr_pool_t *pool)
877
 
{
878
 
  apr_hash_t *props = baton;
879
 
  apr_pool_t *result_pool = apr_hash_pool_get(props);
880
 
  const char *prop_name;
881
 
 
882
 
  /* ### is VAL in the proper pool?  */
883
 
 
884
 
  prop_name = svn_ra_serf__svnname_from_wirename(ns, name, result_pool);
885
 
  if (prop_name != NULL)
886
 
    svn_hash_sets(props, prop_name, value);
887
 
 
888
 
  return SVN_NO_ERROR;
889
 
}
890
 
 
891
 
 
892
 
svn_error_t *
893
 
svn_ra_serf__flatten_props(apr_hash_t **flat_props,
894
 
                           apr_hash_t *props,
895
 
                           apr_pool_t *result_pool,
896
 
                           apr_pool_t *scratch_pool)
897
 
{
898
 
  *flat_props = apr_hash_make(result_pool);
899
 
 
900
 
  return svn_error_trace(svn_ra_serf__walk_node_props(
901
 
                            props,
902
 
                            set_flat_props,
903
 
                            *flat_props /* baton */,
904
 
                            scratch_pool));
905
 
}
906
 
 
907
 
 
908
 
static svn_error_t *
909
 
select_revprops(void *baton,
910
 
                const char *ns,
911
 
                const char *name,
912
 
                const svn_string_t *val,
913
 
                apr_pool_t *scratch_pool)
914
 
{
915
 
  apr_hash_t *revprops = baton;
916
 
  apr_pool_t *result_pool = apr_hash_pool_get(revprops);
917
 
  const char *prop_name;
918
 
 
919
 
  /* ### copy NAME into the RESULT_POOL?  */
920
 
  /* ### copy VAL into the RESULT_POOL?  */
921
 
 
922
 
  if (strcmp(ns, SVN_DAV_PROP_NS_CUSTOM) == 0)
923
 
    prop_name = name;
924
 
  else if (strcmp(ns, SVN_DAV_PROP_NS_SVN) == 0)
925
 
    prop_name = apr_pstrcat(result_pool, SVN_PROP_PREFIX, name, (char *)NULL);
926
 
  else if (strcmp(ns, SVN_PROP_PREFIX) == 0)
927
 
    prop_name = apr_pstrcat(result_pool, SVN_PROP_PREFIX, name, (char *)NULL);
928
 
  else if (strcmp(ns, "") == 0)
929
 
    prop_name = name;
930
 
  else
931
 
    {
932
 
      /* do nothing for now? */
933
 
      return SVN_NO_ERROR;
934
 
    }
935
 
 
936
 
  svn_hash_sets(revprops, prop_name, val);
937
 
 
938
 
  return SVN_NO_ERROR;
939
 
}
940
 
 
941
 
 
942
 
svn_error_t *
943
 
svn_ra_serf__select_revprops(apr_hash_t **revprops,
944
 
                             const char *name,
945
 
                             svn_revnum_t rev,
946
 
                             apr_hash_t *all_revprops,
947
 
                             apr_pool_t *result_pool,
948
 
                             apr_pool_t *scratch_pool)
949
 
{
950
 
  *revprops = apr_hash_make(result_pool);
951
 
 
952
 
  return svn_error_trace(svn_ra_serf__walk_all_props(
953
 
                            all_revprops, name, rev,
954
 
                            select_revprops, *revprops,
955
 
                            scratch_pool));
956
 
}
957
 
 
 
626
  return apr_pstrcat(result_pool, ns, name, SVN_VA_NULL);
 
627
}
958
628
 
959
629
/*
960
630
 * Contact the server (using CONN) to calculate baseline
969
639
static svn_error_t *
970
640
retrieve_baseline_info(svn_revnum_t *actual_revision,
971
641
                       const char **basecoll_url_p,
972
 
                       svn_ra_serf__connection_t *conn,
 
642
                       svn_ra_serf__session_t *session,
973
643
                       const char *baseline_url,
974
644
                       svn_revnum_t revision,
975
645
                       apr_pool_t *result_pool,
979
649
  apr_hash_t *dav_props;
980
650
  const char *basecoll_url;
981
651
 
982
 
  SVN_ERR(svn_ra_serf__fetch_node_props(&props, conn,
 
652
  SVN_ERR(svn_ra_serf__fetch_node_props(&props, session,
983
653
                                        baseline_url, revision,
984
654
                                        baseline_props,
985
655
                                        scratch_pool, scratch_pool));
1000
670
      const char *version_name;
1001
671
 
1002
672
      version_name = svn_prop_get_value(dav_props, SVN_DAV__VERSION_NAME);
1003
 
      if (!version_name)
 
673
      if (version_name)
 
674
        {
 
675
          apr_int64_t rev;
 
676
 
 
677
          SVN_ERR(svn_cstring_atoi64(&rev, version_name));
 
678
          *actual_revision = (svn_revnum_t)rev;
 
679
        }
 
680
 
 
681
      if (!version_name || !SVN_IS_VALID_REVNUM(*actual_revision))
1004
682
        return svn_error_create(SVN_ERR_RA_DAV_PROPS_NOT_FOUND, NULL,
1005
683
                                _("The PROPFIND response did not include "
1006
684
                                  "the requested version-name value"));
1007
 
 
1008
 
      *actual_revision = SVN_STR_TO_REV(version_name);
1009
685
    }
1010
686
 
1011
687
  return SVN_NO_ERROR;
1023
699
static svn_error_t *
1024
700
v1_get_youngest_revnum(svn_revnum_t *youngest,
1025
701
                       const char **basecoll_url,
1026
 
                       svn_ra_serf__connection_t *conn,
 
702
                       svn_ra_serf__session_t *session,
1027
703
                       const char *vcc_url,
1028
704
                       apr_pool_t *result_pool,
1029
705
                       apr_pool_t *scratch_pool)
1033
709
 
1034
710
  /* Fetching DAV:checked-in from the VCC (with no Label: to specify a
1035
711
     revision) will return the latest Baseline resource's URL.  */
1036
 
  SVN_ERR(svn_ra_serf__fetch_dav_prop(&baseline_url, conn, vcc_url,
 
712
  SVN_ERR(svn_ra_serf__fetch_dav_prop(&baseline_url, session, vcc_url,
1037
713
                                      SVN_INVALID_REVNUM,
1038
714
                                      "checked-in",
1039
715
                                      scratch_pool, scratch_pool));
1052
728
  /* First check baseline information cache. */
1053
729
  SVN_ERR(svn_ra_serf__blncache_get_baseline_info(&bc_url,
1054
730
                                                  youngest,
1055
 
                                                  conn->session->blncache,
 
731
                                                  session->blncache,
1056
732
                                                  baseline_url,
1057
733
                                                  scratch_pool));
1058
734
  if (!bc_url)
1059
735
    {
1060
 
      SVN_ERR(retrieve_baseline_info(youngest, &bc_url, conn,
 
736
      SVN_ERR(retrieve_baseline_info(youngest, &bc_url, session,
1061
737
                                     baseline_url, SVN_INVALID_REVNUM,
1062
738
                                     scratch_pool, scratch_pool));
1063
 
      SVN_ERR(svn_ra_serf__blncache_set(conn->session->blncache,
 
739
      SVN_ERR(svn_ra_serf__blncache_set(session->blncache,
1064
740
                                        baseline_url, *youngest,
1065
741
                                        bc_url, scratch_pool));
1066
742
    }
1081
757
 
1082
758
  if (SVN_RA_SERF__HAVE_HTTPV2_SUPPORT(session))
1083
759
    return svn_error_trace(svn_ra_serf__v2_get_youngest_revnum(
1084
 
                             youngest, session->conns[0], scratch_pool));
 
760
                             youngest, session, scratch_pool));
1085
761
 
1086
 
  SVN_ERR(svn_ra_serf__discover_vcc(&vcc_url, session, NULL, scratch_pool));
 
762
  SVN_ERR(svn_ra_serf__discover_vcc(&vcc_url, session, scratch_pool));
1087
763
 
1088
764
  return svn_error_trace(v1_get_youngest_revnum(youngest, NULL,
1089
 
                                                session->conns[0], vcc_url,
 
765
                                                session, vcc_url,
1090
766
                                                scratch_pool, scratch_pool));
1091
767
}
1092
768
 
1103
779
get_baseline_info(const char **bc_url,
1104
780
                  svn_revnum_t *revnum_used,
1105
781
                  svn_ra_serf__session_t *session,
1106
 
                  svn_ra_serf__connection_t *conn,
1107
782
                  svn_revnum_t revision,
1108
 
                  apr_pool_t *pool)
 
783
                  apr_pool_t *result_pool,
 
784
                  apr_pool_t *scratch_pool)
1109
785
{
1110
786
  /* If we detected HTTP v2 support on the server, we can construct
1111
787
     the baseline collection URL ourselves, and fetch the latest
1119
795
      else
1120
796
        {
1121
797
          SVN_ERR(svn_ra_serf__v2_get_youngest_revnum(
1122
 
                    revnum_used, conn, pool));
1123
 
          if (! SVN_IS_VALID_REVNUM(*revnum_used))
1124
 
            return svn_error_create(SVN_ERR_RA_DAV_OPTIONS_REQ_FAILED, NULL,
1125
 
                                    _("The OPTIONS response did not include "
1126
 
                                      "the youngest revision"));
 
798
                    revnum_used, session, scratch_pool));
1127
799
        }
1128
800
 
1129
 
      *bc_url = apr_psprintf(pool, "%s/%ld",
 
801
      *bc_url = apr_psprintf(result_pool, "%s/%ld",
1130
802
                             session->rev_root_stub, *revnum_used);
1131
803
    }
1132
804
 
1135
807
    {
1136
808
      const char *vcc_url;
1137
809
 
1138
 
      SVN_ERR(svn_ra_serf__discover_vcc(&vcc_url, session, conn, pool));
 
810
      SVN_ERR(svn_ra_serf__discover_vcc(&vcc_url, session, scratch_pool));
1139
811
 
1140
812
      if (SVN_IS_VALID_REVNUM(revision))
1141
813
        {
1142
814
          /* First check baseline information cache. */
1143
815
          SVN_ERR(svn_ra_serf__blncache_get_bc_url(bc_url,
1144
816
                                                   session->blncache,
1145
 
                                                   revision, pool));
 
817
                                                   revision, result_pool));
1146
818
          if (!*bc_url)
1147
819
            {
1148
 
              SVN_ERR(retrieve_baseline_info(NULL, bc_url, conn,
1149
 
                                             vcc_url, revision, pool, pool));
 
820
              SVN_ERR(retrieve_baseline_info(NULL, bc_url, session,
 
821
                                             vcc_url, revision,
 
822
                                             result_pool, scratch_pool));
1150
823
              SVN_ERR(svn_ra_serf__blncache_set(session->blncache, NULL,
1151
 
                                                revision, *bc_url, pool));
 
824
                                                revision, *bc_url,
 
825
                                                scratch_pool));
1152
826
            }
1153
827
 
1154
828
          *revnum_used = revision;
1156
830
      else
1157
831
        {
1158
832
          SVN_ERR(v1_get_youngest_revnum(revnum_used, bc_url,
1159
 
                                         conn, vcc_url,
1160
 
                                         pool, pool));
 
833
                                         session, vcc_url,
 
834
                                         result_pool, scratch_pool));
1161
835
        }
1162
836
    }
1163
837
 
1169
843
svn_ra_serf__get_stable_url(const char **stable_url,
1170
844
                            svn_revnum_t *latest_revnum,
1171
845
                            svn_ra_serf__session_t *session,
1172
 
                            svn_ra_serf__connection_t *conn,
1173
846
                            const char *url,
1174
847
                            svn_revnum_t revision,
1175
848
                            apr_pool_t *result_pool,
1183
856
  if (! url)
1184
857
    url = session->session_url.path;
1185
858
 
1186
 
  /* If the caller didn't provide a specific connection for us to use,
1187
 
     we'll use the default connection.  */
1188
 
  if (! conn)
1189
 
    conn = session->conns[0];
1190
 
 
1191
859
  SVN_ERR(get_baseline_info(&basecoll_url, &revnum_used,
1192
 
                            session, conn, revision, scratch_pool));
 
860
                            session, revision, scratch_pool, scratch_pool));
1193
861
  SVN_ERR(svn_ra_serf__get_relative_path(&repos_relpath, url,
1194
 
                                         session, conn, scratch_pool));
 
862
                                         session, scratch_pool));
1195
863
 
1196
864
  *stable_url = svn_path_url_add_component2(basecoll_url, repos_relpath,
1197
865
                                            result_pool);
1203
871
 
1204
872
 
1205
873
svn_error_t *
1206
 
svn_ra_serf__get_resource_type(svn_node_kind_t *kind,
1207
 
                               apr_hash_t *props)
1208
 
{
1209
 
  apr_hash_t *dav_props;
1210
 
  const char *res_type;
1211
 
 
1212
 
  dav_props = apr_hash_get(props, "DAV:", 4);
1213
 
  res_type = svn_prop_get_value(dav_props, "resourcetype");
1214
 
  if (!res_type)
1215
 
    {
1216
 
      /* How did this happen? */
1217
 
      return svn_error_create(SVN_ERR_RA_DAV_PROPS_NOT_FOUND, NULL,
1218
 
                              _("The PROPFIND response did not include the "
1219
 
                                "requested resourcetype value"));
1220
 
    }
1221
 
 
1222
 
  if (strcmp(res_type, "collection") == 0)
1223
 
    {
1224
 
      *kind = svn_node_dir;
1225
 
    }
1226
 
  else
1227
 
    {
1228
 
      *kind = svn_node_file;
1229
 
    }
1230
 
 
1231
 
  return SVN_NO_ERROR;
1232
 
}
1233
 
 
1234
 
 
1235
 
svn_error_t *
1236
874
svn_ra_serf__fetch_dav_prop(const char **value,
1237
 
                            svn_ra_serf__connection_t *conn,
 
875
                            svn_ra_serf__session_t *session,
1238
876
                            const char *url,
1239
877
                            svn_revnum_t revision,
1240
878
                            const char *propname,
1244
882
  apr_hash_t *props;
1245
883
  apr_hash_t *dav_props;
1246
884
 
1247
 
  SVN_ERR(svn_ra_serf__fetch_node_props(&props, conn, url, revision,
 
885
  SVN_ERR(svn_ra_serf__fetch_node_props(&props, session, url, revision,
1248
886
                                        checked_in_props,
1249
887
                                        scratch_pool, scratch_pool));
1250
888
  dav_props = apr_hash_get(props, "DAV:", 4);
1261
899
 
1262
900
  return SVN_NO_ERROR;
1263
901
}
 
902
 
 
903
/* Removes all non regular properties from PROPS */
 
904
void
 
905
svn_ra_serf__keep_only_regular_props(apr_hash_t *props,
 
906
                                     apr_pool_t *scratch_pool)
 
907
{
 
908
  apr_hash_index_t *hi;
 
909
 
 
910
  for (hi = apr_hash_first(scratch_pool, props); hi; hi = apr_hash_next(hi))
 
911
    {
 
912
      const char *propname = apr_hash_this_key(hi);
 
913
 
 
914
      if (svn_property_kind2(propname) != svn_prop_regular_kind)
 
915
        svn_hash_sets(props, propname, NULL);
 
916
    }
 
917
}