271
262
return SVN_NO_ERROR;
274
/* Implements svn_ra_serf__response_handler_t */
276
handle_checkout(serf_request_t *request,
277
serf_bucket_t *response,
281
checkout_context_t *ctx = handler_baton;
283
svn_error_t *err = svn_ra_serf__handle_status_only(request, response,
284
&ctx->progress, pool);
286
/* These handler functions are supposed to return an APR_EOF status
287
wrapped in a svn_error_t to indicate to serf that the response was
288
completely read. While we have to return this status code to our
289
caller, we should treat it as the normal case for now. */
290
if (err && ! APR_STATUS_IS_EOF(err->apr_err))
293
/* Get the resulting location. */
294
if (ctx->progress.done && ctx->progress.status == 201)
266
/* Using the HTTPv1 protocol, perform a CHECKOUT of NODE_URL within the
267
given COMMIT_CTX. The resulting working resource will be returned in
268
*WORKING_URL, allocated from RESULT_POOL. All temporary allocations
269
are performed in SCRATCH_POOL.
271
### are these URLs actually repos relpath values? or fspath? or maybe
272
### the abspath portion of the full URL.
274
This function operates synchronously.
276
Strictly speaking, we could perform "all" of the CHECKOUT requests
277
when the commit starts, and only block when we need a specific
278
answer. Or, at a minimum, send off these individual requests async
279
and block when we need the answer (eg PUT or PROPPATCH).
281
However: the investment to speed this up is not worthwhile, given
282
that CHECKOUT (and the related round trip) is completely obviated
286
checkout_node(const char **working_url,
287
const commit_context_t *commit_ctx,
288
const char *node_url,
289
apr_pool_t *result_pool,
290
apr_pool_t *scratch_pool)
292
svn_ra_serf__handler_t handler = { 0 };
296
/* HANDLER_POOL is the scratch pool since we don't need to remember
297
anything from the handler. We just want the working resource. */
298
handler.handler_pool = scratch_pool;
299
handler.session = commit_ctx->session;
300
handler.conn = commit_ctx->conn;
302
handler.body_delegate = create_checkout_body;
303
handler.body_delegate_baton = (/* const */ void *)commit_ctx->activity_url;
304
handler.body_type = "text/xml";
306
handler.response_handler = svn_ra_serf__expect_empty_body;
307
handler.response_baton = &handler;
309
handler.method = "CHECKOUT";
310
handler.path = node_url;
312
SVN_ERR(svn_ra_serf__context_run_one(&handler, scratch_pool));
314
if (handler.sline.code != 201)
315
return svn_error_trace(return_response_err(&handler));
317
if (handler.location == NULL)
318
return svn_error_create(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL,
319
_("No Location header received"));
321
/* We only want the path portion of the Location header.
322
(code.google.com sometimes returns an 'http:' scheme for an
323
'https:' transaction ... we'll work around that by stripping the
324
scheme, host, and port here and re-adding the correct ones
326
status = apr_uri_parse(scratch_pool, handler.location, &uri);
328
return svn_error_create(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL,
329
_("Error parsing Location header value"));
331
*working_url = svn_urlpath__canonicalize(uri.path, result_pool);
337
/* This is a wrapper around checkout_node() (which see for
338
documentation) which simply retries the CHECKOUT request when it
339
fails due to an SVN_ERR_APMOD_BAD_BASELINE error return from the
342
See http://subversion.tigris.org/issues/show_bug.cgi?id=4127 for
346
retry_checkout_node(const char **working_url,
347
const commit_context_t *commit_ctx,
348
const char *node_url,
349
apr_pool_t *result_pool,
350
apr_pool_t *scratch_pool)
352
svn_error_t *err = SVN_NO_ERROR;
353
int retry_count = 5; /* Magic, arbitrary number. */
298
const char *location;
301
hdrs = serf_bucket_response_get_headers(response);
302
location = serf_bucket_headers_get(hdrs, "Location");
304
return svn_error_create(SVN_ERR_RA_DAV_MALFORMED_DATA, err,
305
_("No Location header received"));
307
status = apr_uri_parse(pool, location, &uri);
310
err = svn_error_compose_create(svn_error_wrap_apr(status, NULL), err);
312
ctx->resource_url = svn_urlpath__canonicalize(uri.path, ctx->pool);
357
svn_error_clear(err);
359
err = checkout_node(working_url, commit_ctx, node_url,
360
result_pool, scratch_pool);
362
/* There's a small chance of a race condition here if Apache is
363
experiencing heavy commit concurrency or if the network has
364
long latency. It's possible that the value of HEAD changed
365
between the time we fetched the latest baseline and the time
366
we try to CHECKOUT that baseline. If that happens, Apache
367
will throw us a BAD_BASELINE error (deltaV says you can only
368
checkout the latest baseline). We just ignore that specific
369
error and retry a few times, asking for the latest baseline
371
if (err && (err->apr_err != SVN_ERR_APMOD_BAD_BASELINE))
374
while (err && retry_count--);
318
380
static svn_error_t *
319
checkout_dir(dir_context_t *dir)
381
checkout_dir(dir_context_t *dir,
382
apr_pool_t *scratch_pool)
321
checkout_context_t *checkout_ctx;
322
svn_ra_serf__handler_t *handler;
323
384
svn_error_t *err;
324
385
dir_context_t *p_dir = dir;
386
const char *checkout_url;
387
const char **working;
389
if (dir->working_url)
328
391
return SVN_NO_ERROR;
331
/* Is this directory or one of our parent dirs newly added?
394
/* Is this directory or one of our parent dirs newly added?
332
395
* If so, we're already implicitly checked out. */
335
398
if (p_dir->added)
400
/* Calculate the working_url by skipping the shared ancestor bewteen
401
* the parent->relpath and dir->relpath. This is safe since an
402
* add is guaranteed to have a parent that is checked out. */
403
dir_context_t *parent = p_dir->parent_dir;
404
const char *relpath = svn_relpath_skip_ancestor(parent->relpath,
337
407
/* Implicitly checkout this dir now. */
338
dir->checkout = apr_pcalloc(dir->pool, sizeof(*dir->checkout));
339
dir->checkout->pool = dir->pool;
340
dir->checkout->progress.pool = dir->pool;
341
dir->checkout->activity_url = dir->commit->activity_url;
342
dir->checkout->resource_url =
343
svn_path_url_add_component2(dir->parent_dir->checkout->resource_url,
344
dir->name, dir->pool);
408
SVN_ERR_ASSERT(parent->working_url);
409
dir->working_url = svn_path_url_add_component2(
346
412
return SVN_NO_ERROR;
348
414
p_dir = p_dir->parent_dir;
351
/* Checkout our directory into the activity URL now. */
352
handler = apr_pcalloc(dir->pool, sizeof(*handler));
353
handler->session = dir->commit->session;
354
handler->conn = dir->commit->conn;
356
checkout_ctx = apr_pcalloc(dir->pool, sizeof(*checkout_ctx));
357
checkout_ctx->pool = dir->pool;
358
checkout_ctx->progress.pool = dir->pool;
360
checkout_ctx->activity_url = dir->commit->activity_url;
362
417
/* We could be called twice for the root: once to checkout the baseline;
363
418
* once to checkout the directory itself if we need to do so.
419
* Note: CHECKOUT_URL should live longer than HANDLER.
365
if (!dir->parent_dir && !dir->commit->baseline)
421
if (!dir->parent_dir && !dir->commit->baseline_url)
367
checkout_ctx->checkout_url = dir->commit->vcc_url;
368
dir->commit->baseline = checkout_ctx;
423
checkout_url = dir->commit->vcc_url;
424
working = &dir->commit->baseline_url;
372
checkout_ctx->checkout_url = dir->url;
373
dir->checkout = checkout_ctx;
428
checkout_url = dir->url;
429
working = &dir->working_url;
376
handler->body_delegate = create_checkout_body;
377
handler->body_delegate_baton = checkout_ctx;
378
handler->body_type = "text/xml";
380
handler->response_handler = handle_checkout;
381
handler->response_baton = checkout_ctx;
383
handler->method = "CHECKOUT";
384
handler->path = checkout_ctx->checkout_url;
386
svn_ra_serf__request_create(handler);
388
err = svn_ra_serf__context_run_wait(&checkout_ctx->progress.done,
389
dir->commit->session,
432
/* Checkout our directory into the activity URL now. */
433
err = retry_checkout_node(working, dir->commit, checkout_url,
434
dir->pool, scratch_pool);
393
437
if (err->apr_err == SVN_ERR_FS_CONFLICT)
394
SVN_ERR_W(err, apr_psprintf(dir->pool,
438
SVN_ERR_W(err, apr_psprintf(scratch_pool,
395
439
_("Directory '%s' is out of date; try updating"),
396
svn_dirent_local_style(dir->relpath, dir->pool)));
440
svn_dirent_local_style(dir->relpath, scratch_pool)));
400
if (checkout_ctx->progress.status != 201)
402
return return_response_err(handler, &checkout_ctx->progress);
405
444
return SVN_NO_ERROR;
458
svn_ra_serf__propfind_context_t *propfind_ctx;
460
499
const char *propfind_url;
462
props = apr_hash_make(pool);
500
svn_ra_serf__connection_t *conn = session->conns[0];
464
502
if (SVN_IS_VALID_REVNUM(base_revision))
466
const char *bc_url, *bc_relpath;
468
504
/* mod_dav_svn can't handle the "Label:" header that
469
505
svn_ra_serf__deliver_props() is going to try to use for
470
506
this lookup, so we'll do things the hard(er) way, by
471
507
looking up the version URL from a resource in the
472
508
baseline collection. */
473
SVN_ERR(svn_ra_serf__get_baseline_info(&bc_url, &bc_relpath,
475
session->session_url.path,
476
base_revision, NULL, pool));
477
propfind_url = svn_path_url_add_component2(bc_url, bc_relpath, pool);
509
/* ### conn==NULL for session->conns[0]. same as CONN. */
510
SVN_ERR(svn_ra_serf__get_stable_url(&propfind_url,
511
NULL /* latest_revnum */,
512
session, NULL /* conn */,
513
NULL /* url */, base_revision,
514
scratch_pool, scratch_pool));
481
518
propfind_url = session->session_url.path;
484
/* ### switch to svn_ra_serf__retrieve_props */
485
SVN_ERR(svn_ra_serf__deliver_props(&propfind_ctx, props, session, conn,
486
propfind_url, base_revision, "0",
487
checked_in_props, NULL, pool));
488
SVN_ERR(svn_ra_serf__wait_for_props(propfind_ctx, session, pool));
490
/* We wouldn't get here if the url wasn't found (404), so the checked-in
491
property should have been set. */
493
svn_ra_serf__get_ver_prop(props, propfind_url,
494
base_revision, "DAV:", "checked-in");
521
SVN_ERR(svn_ra_serf__fetch_dav_prop(&root_checkout,
522
conn, propfind_url, base_revision,
524
scratch_pool, scratch_pool));
496
525
if (!root_checkout)
497
526
return svn_error_createf(SVN_ERR_RA_DAV_REQUEST_FAILED, NULL,
498
527
_("Path '%s' not present"),
499
528
session->session_url.path);
501
root_checkout = svn_urlpath__canonicalize(root_checkout, pool);
530
root_checkout = svn_urlpath__canonicalize(root_checkout, scratch_pool);
504
*checked_in_url = svn_path_url_add_component2(root_checkout, relpath, pool);
533
*checked_in_url = svn_path_url_add_component2(root_checkout, relpath,
506
536
return SVN_NO_ERROR;
509
539
static svn_error_t *
510
checkout_file(file_context_t *file)
540
checkout_file(file_context_t *file,
541
apr_pool_t *scratch_pool)
512
svn_ra_serf__handler_t *handler;
513
543
svn_error_t *err;
514
544
dir_context_t *parent_dir = file->parent_dir;
545
const char *checkout_url;
516
547
/* Is one of our parent dirs newly added? If so, we're already
517
548
* implicitly checked out.
521
552
if (parent_dir->added)
523
554
/* Implicitly checkout this file now. */
524
file->checkout = apr_pcalloc(file->pool, sizeof(*file->checkout));
525
file->checkout->pool = file->pool;
526
file->checkout->progress.pool = file->pool;
527
file->checkout->activity_url = file->commit->activity_url;
528
file->checkout->resource_url =
529
svn_path_url_add_component2(parent_dir->checkout->resource_url,
530
svn_relpath__is_child(parent_dir->relpath,
555
file->working_url = svn_path_url_add_component2(
556
parent_dir->working_url,
557
svn_relpath_skip_ancestor(
558
parent_dir->relpath, file->relpath),
534
560
return SVN_NO_ERROR;
536
562
parent_dir = parent_dir->parent_dir;
565
SVN_ERR(get_version_url(&checkout_url,
566
file->commit->session,
567
file->relpath, file->base_revision,
568
NULL, scratch_pool, scratch_pool));
539
570
/* Checkout our file into the activity URL now. */
540
handler = apr_pcalloc(file->pool, sizeof(*handler));
541
handler->session = file->commit->session;
542
handler->conn = file->commit->conn;
544
file->checkout = apr_pcalloc(file->pool, sizeof(*file->checkout));
545
file->checkout->pool = file->pool;
546
file->checkout->progress.pool = file->pool;
548
file->checkout->activity_url = file->commit->activity_url;
550
SVN_ERR(get_version_url(&(file->checkout->checkout_url),
551
file->commit->session, file->commit->conn,
552
file->relpath, file->base_revision,
555
handler->body_delegate = create_checkout_body;
556
handler->body_delegate_baton = file->checkout;
557
handler->body_type = "text/xml";
559
handler->response_handler = handle_checkout;
560
handler->response_baton = file->checkout;
562
handler->method = "CHECKOUT";
563
handler->path = file->checkout->checkout_url;
565
svn_ra_serf__request_create(handler);
567
/* There's no need to wait here as we only need this when we start the
568
* PROPPATCH or PUT of the file.
570
err = svn_ra_serf__context_run_wait(&file->checkout->progress.done,
571
file->commit->session,
571
err = retry_checkout_node(&file->working_url, file->commit, checkout_url,
572
file->pool, scratch_pool);
575
575
if (err->apr_err == SVN_ERR_FS_CONFLICT)
576
SVN_ERR_W(err, apr_psprintf(file->pool,
576
SVN_ERR_W(err, apr_psprintf(scratch_pool,
577
577
_("File '%s' is out of date; try updating"),
578
svn_dirent_local_style(file->relpath, file->pool)));
578
svn_dirent_local_style(file->relpath, scratch_pool)));
582
if (file->checkout->progress.status != 201)
584
return return_response_err(handler, &file->checkout->progress);
587
582
return SVN_NO_ERROR;
788
783
return SVN_NO_ERROR;
786
/* Possible add the lock-token "If:" precondition header to HEADERS if
787
an examination of COMMIT_CTX and RELPATH indicates that this is the
790
Generally speaking, if the client provided a lock token for
791
RELPATH, it's the right thing to do. There is a notable instance
792
where this is not the case, however. If the file at RELPATH was
793
explicitly deleted in this commit already, then mod_dav removed its
794
lock token when it fielded the DELETE request, so we don't want to
795
set the lock precondition again. (See
796
http://subversion.tigris.org/issues/show_bug.cgi?id=3674 for details.)
799
maybe_set_lock_token_header(serf_bucket_t *headers,
800
commit_context_t *commit_ctx,
806
if (! (relpath && commit_ctx->lock_tokens))
809
if (! svn_hash_gets(commit_ctx->deleted_entries, relpath))
811
token = svn_hash_gets(commit_ctx->lock_tokens, relpath);
814
const char *token_header;
815
const char *token_uri;
816
apr_uri_t uri = commit_ctx->session->session_url;
818
/* Supplying the optional URI affects apache response when
819
the lock is broken, see issue 4369. When present any URI
820
must be absolute (RFC 2518 9.4). */
821
uri.path = (char *)svn_path_url_add_component2(uri.path, relpath,
823
token_uri = apr_uri_unparse(pool, &uri, 0);
825
token_header = apr_pstrcat(pool, "<", token_uri, "> (<", token, ">)",
827
serf_bucket_headers_set(headers, "If", token_header);
791
834
static svn_error_t *
792
835
setup_proppatch_headers(serf_bucket_t *headers,
1286
1316
proppatch_context_t *proppatch_ctx;
1287
1317
dir_context_t *dir;
1288
1318
apr_hash_index_t *hi;
1289
const char *proppatch_target;
1319
const char *proppatch_target = NULL;
1291
1321
if (SVN_RA_SERF__HAVE_HTTPV2_SUPPORT(ctx->session))
1293
svn_ra_serf__simple_request_context_t *post_ctx;
1294
1323
post_response_ctx_t *prc;
1295
1324
const char *rel_path;
1325
svn_boolean_t post_with_revprops
1326
= (NULL != svn_hash_gets(ctx->session->supported_posts,
1327
"create-txn-with-props"));
1297
1329
/* Create our activity URL now on the server. */
1298
1330
handler = apr_pcalloc(ctx->pool, sizeof(*handler));
1331
handler->handler_pool = ctx->pool;
1299
1332
handler->method = "POST";
1300
1333
handler->body_type = SVN_SKEL_MIME_TYPE;
1301
1334
handler->body_delegate = create_txn_post_body;
1302
handler->body_delegate_baton = NULL;
1335
handler->body_delegate_baton =
1336
post_with_revprops ? ctx->revprop_table : NULL;
1303
1337
handler->header_delegate = setup_post_headers;
1304
1338
handler->header_delegate_baton = NULL;
1305
1339
handler->path = ctx->session->me_resource;
1306
1340
handler->conn = ctx->session->conns[0];
1307
1341
handler->session = ctx->session;
1309
post_ctx = apr_pcalloc(ctx->pool, sizeof(*post_ctx));
1310
post_ctx->pool = ctx->pool;
1312
1343
prc = apr_pcalloc(ctx->pool, sizeof(*prc));
1313
prc->request_ctx = post_ctx;
1344
prc->handler = handler;
1314
1345
prc->commit_ctx = ctx;
1316
1347
handler->response_handler = post_response_handler;
1317
1348
handler->response_baton = prc;
1319
svn_ra_serf__request_create(handler);
1321
SVN_ERR(svn_ra_serf__context_run_wait(&post_ctx->done, ctx->session,
1324
if (post_ctx->status != 201)
1350
SVN_ERR(svn_ra_serf__context_run_one(handler, ctx->pool));
1352
if (handler->sline.code != 201)
1326
1354
apr_status_t status = SVN_ERR_RA_DAV_REQUEST_FAILED;
1327
switch(post_ctx->status)
1356
switch (handler->sline.code)
1330
1359
status = SVN_ERR_RA_DAV_FORBIDDEN;
1461
1477
dir->removed_props = apr_hash_make(dir->pool);
1463
1479
SVN_ERR(get_version_url(&dir->url, dir->commit->session,
1464
dir->commit->conn, dir->relpath,
1465
1481
dir->base_revision, ctx->checked_in_url,
1482
dir->pool, dir->pool /* scratch_pool */));
1467
1483
ctx->checked_in_url = dir->url;
1469
1485
/* Checkout our root dir */
1470
SVN_ERR(checkout_dir(dir));
1486
SVN_ERR(checkout_dir(dir, dir->pool /* scratch_pool */));
1472
proppatch_target = ctx->baseline->resource_url;
1488
proppatch_target = ctx->baseline_url;
1476
/* PROPPATCH our revprops and pass them along. */
1477
proppatch_ctx = apr_pcalloc(ctx->pool, sizeof(*proppatch_ctx));
1478
proppatch_ctx->pool = dir_pool;
1479
proppatch_ctx->progress.pool = dir_pool;
1480
proppatch_ctx->commit = ctx;
1481
proppatch_ctx->path = proppatch_target;
1482
proppatch_ctx->changed_props = apr_hash_make(proppatch_ctx->pool);
1483
proppatch_ctx->removed_props = apr_hash_make(proppatch_ctx->pool);
1484
proppatch_ctx->base_revision = SVN_INVALID_REVNUM;
1486
for (hi = apr_hash_first(ctx->pool, ctx->revprop_table); hi;
1487
hi = apr_hash_next(hi))
1491
/* Unless this is NULL -- which means we don't need to PROPPATCH the
1492
transaction with our revprops -- then, you know, PROPPATCH the
1493
transaction with our revprops. */
1494
if (proppatch_target)
1492
svn_string_t *value;
1495
apr_hash_this(hi, &key, NULL, &val);
1499
if (strncmp(name, SVN_PROP_PREFIX, sizeof(SVN_PROP_PREFIX) - 1) == 0)
1501
ns = SVN_DAV_PROP_NS_SVN;
1502
name += sizeof(SVN_PROP_PREFIX) - 1;
1506
ns = SVN_DAV_PROP_NS_CUSTOM;
1509
svn_ra_serf__set_prop(proppatch_ctx->changed_props, proppatch_ctx->path,
1510
ns, name, value, proppatch_ctx->pool);
1496
proppatch_ctx = apr_pcalloc(ctx->pool, sizeof(*proppatch_ctx));
1497
proppatch_ctx->pool = dir_pool;
1498
proppatch_ctx->commit = ctx;
1499
proppatch_ctx->path = proppatch_target;
1500
proppatch_ctx->changed_props = apr_hash_make(proppatch_ctx->pool);
1501
proppatch_ctx->removed_props = apr_hash_make(proppatch_ctx->pool);
1502
proppatch_ctx->base_revision = SVN_INVALID_REVNUM;
1504
for (hi = apr_hash_first(ctx->pool, ctx->revprop_table); hi;
1505
hi = apr_hash_next(hi))
1507
const char *name = svn__apr_hash_index_key(hi);
1508
svn_string_t *value = svn__apr_hash_index_val(hi);
1511
if (strncmp(name, SVN_PROP_PREFIX, sizeof(SVN_PROP_PREFIX) - 1) == 0)
1513
ns = SVN_DAV_PROP_NS_SVN;
1514
name += sizeof(SVN_PROP_PREFIX) - 1;
1518
ns = SVN_DAV_PROP_NS_CUSTOM;
1521
svn_ra_serf__set_prop(proppatch_ctx->changed_props,
1522
proppatch_ctx->path,
1523
ns, name, value, proppatch_ctx->pool);
1526
SVN_ERR(proppatch_resource(proppatch_ctx, dir->commit, ctx->pool));
1513
SVN_ERR(proppatch_resource(proppatch_ctx, dir->commit, ctx->pool));
1515
1529
*root_baton = dir;
1517
1531
return SVN_NO_ERROR;
1920
1915
if (! ((dir->added && !dir->copy_path) ||
1921
1916
(deleted_parent && deleted_parent[0] != '\0')))
1923
svn_ra_serf__simple_request_context_t *head_ctx;
1924
1918
svn_ra_serf__handler_t *handler;
1926
head_ctx = apr_pcalloc(new_file->pool, sizeof(*head_ctx));
1927
head_ctx->pool = new_file->pool;
1929
1920
handler = apr_pcalloc(new_file->pool, sizeof(*handler));
1921
handler->handler_pool = new_file->pool;
1930
1922
handler->session = new_file->commit->session;
1931
1923
handler->conn = new_file->commit->conn;
1932
1924
handler->method = "HEAD";
1933
1925
handler->path = svn_path_url_add_component2(
1934
1926
dir->commit->session->session_url.path,
1935
1927
path, new_file->pool);
1936
handler->response_handler = svn_ra_serf__handle_status_only;
1937
handler->response_baton = head_ctx;
1938
svn_ra_serf__request_create(handler);
1940
SVN_ERR(svn_ra_serf__context_run_wait(&head_ctx->done,
1941
new_file->commit->session,
1944
if (head_ctx->status != 404)
1928
handler->response_handler = svn_ra_serf__expect_empty_body;
1929
handler->response_baton = handler;
1931
SVN_ERR(svn_ra_serf__context_run_one(handler, new_file->pool));
1933
if (handler->sline.code != 404)
1946
return svn_error_createf(SVN_ERR_RA_DAV_ALREADY_EXISTS, NULL,
1935
if (handler->sline.code != 200)
1939
err = svn_ra_serf__error_on_status(handler->sline,
1946
return svn_error_createf(SVN_ERR_FS_ALREADY_EXISTS, NULL,
1947
1947
_("File '%s' already exists"), path);
2096
2096
ctx->copy_path);
2099
SVN_ERR(svn_ra_serf__get_baseline_info(&basecoll_url, &rel_copy_path,
2100
ctx->commit->session,
2102
uri.path, ctx->copy_revision,
2104
req_url = svn_path_url_add_component2(basecoll_url, rel_copy_path, pool);
2099
/* ### conn==NULL for session->conns[0]. same as commit->conn. */
2100
SVN_ERR(svn_ra_serf__get_stable_url(&req_url, NULL /* latest_revnum */,
2101
ctx->commit->session,
2103
uri.path, ctx->copy_revision,
2104
scratch_pool, scratch_pool));
2106
handler = apr_pcalloc(pool, sizeof(*handler));
2106
handler = apr_pcalloc(scratch_pool, sizeof(*handler));
2107
handler->handler_pool = scratch_pool;
2107
2108
handler->method = "COPY";
2108
2109
handler->path = req_url;
2109
2110
handler->conn = ctx->commit->conn;
2110
2111
handler->session = ctx->commit->session;
2112
copy_ctx = apr_pcalloc(pool, sizeof(*copy_ctx));
2113
copy_ctx->pool = pool;
2115
handler->response_handler = svn_ra_serf__handle_status_only;
2116
handler->response_baton = copy_ctx;
2113
handler->response_handler = svn_ra_serf__expect_empty_body;
2114
handler->response_baton = handler;
2118
2116
handler->header_delegate = setup_copy_file_headers;
2119
2117
handler->header_delegate_baton = ctx;
2121
svn_ra_serf__request_create(handler);
2123
SVN_ERR(svn_ra_serf__context_run_wait(©_ctx->done,
2124
ctx->commit->session, pool));
2126
if (copy_ctx->status != 201 && copy_ctx->status != 204)
2119
SVN_ERR(svn_ra_serf__context_run_one(handler, scratch_pool));
2121
if (handler->sline.code != 201 && handler->sline.code != 204)
2128
return return_response_err(handler, copy_ctx);
2123
return svn_error_trace(return_response_err(handler));
2210
2198
apr_pool_t *pool)
2212
2200
commit_context_t *ctx = edit_baton;
2213
svn_ra_serf__merge_context_t *merge_ctx;
2214
svn_ra_serf__simple_request_context_t *delete_ctx;
2215
svn_ra_serf__handler_t *handler;
2216
svn_boolean_t *merge_done;
2217
2201
const char *merge_target =
2218
2202
ctx->activity_url ? ctx->activity_url : ctx->txn_url;
2203
const svn_commit_info_t *commit_info;
2220
2206
/* MERGE our activity */
2221
SVN_ERR(svn_ra_serf__merge_create_req(&merge_ctx, ctx->session,
2222
ctx->session->conns[0],
2228
merge_done = svn_ra_serf__merge_get_done_ptr(merge_ctx);
2230
SVN_ERR(svn_ra_serf__context_run_wait(merge_done, ctx->session, pool));
2232
if (svn_ra_serf__merge_get_status(merge_ctx) != 200)
2207
SVN_ERR(svn_ra_serf__run_merge(&commit_info, &response_code,
2209
ctx->session->conns[0],
2215
if (response_code != 200)
2234
2217
return svn_error_createf(SVN_ERR_RA_DAV_REQUEST_FAILED, NULL,
2235
2218
_("MERGE request failed: returned %d "
2236
2219
"(during commit)"),
2237
svn_ra_serf__merge_get_status(merge_ctx));
2240
2223
/* Inform the WC that we did a commit. */
2241
2224
if (ctx->callback)
2242
SVN_ERR(ctx->callback(svn_ra_serf__merge_get_commit_info(merge_ctx),
2243
ctx->callback_baton, pool));
2225
SVN_ERR(ctx->callback(commit_info, ctx->callback_baton, pool));
2245
2227
/* If we're using activities, DELETE our completed activity. */
2246
2228
if (ctx->activity_url)
2230
svn_ra_serf__handler_t *handler;
2248
2232
handler = apr_pcalloc(pool, sizeof(*handler));
2233
handler->handler_pool = pool;
2249
2234
handler->method = "DELETE";
2250
2235
handler->path = ctx->activity_url;
2251
2236
handler->conn = ctx->conn;
2252
2237
handler->session = ctx->session;
2254
delete_ctx = apr_pcalloc(pool, sizeof(*delete_ctx));
2255
delete_ctx->pool = pool;
2257
handler->response_handler = svn_ra_serf__handle_status_only;
2258
handler->response_baton = delete_ctx;
2260
svn_ra_serf__request_create(handler);
2262
SVN_ERR(svn_ra_serf__context_run_wait(&delete_ctx->done, ctx->session,
2265
SVN_ERR_ASSERT(delete_ctx->status == 204);
2239
handler->response_handler = svn_ra_serf__expect_empty_body;
2240
handler->response_baton = handler;
2242
SVN_ERR(svn_ra_serf__context_run_one(handler, pool));
2244
SVN_ERR_ASSERT(handler->sline.code == 204);
2268
2247
return SVN_NO_ERROR;