1251881Speter/* 2251881Speter * log.c : entry point for log RA functions for ra_serf 3251881Speter * 4251881Speter * ==================================================================== 5251881Speter * Licensed to the Apache Software Foundation (ASF) under one 6251881Speter * or more contributor license agreements. See the NOTICE file 7251881Speter * distributed with this work for additional information 8251881Speter * regarding copyright ownership. The ASF licenses this file 9251881Speter * to you under the Apache License, Version 2.0 (the 10251881Speter * "License"); you may not use this file except in compliance 11251881Speter * with the License. You may obtain a copy of the License at 12251881Speter * 13251881Speter * http://www.apache.org/licenses/LICENSE-2.0 14251881Speter * 15251881Speter * Unless required by applicable law or agreed to in writing, 16251881Speter * software distributed under the License is distributed on an 17251881Speter * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 18251881Speter * KIND, either express or implied. See the License for the 19251881Speter * specific language governing permissions and limitations 20251881Speter * under the License. 21251881Speter * ==================================================================== 22251881Speter */ 23251881Speter 24251881Speter 25251881Speter 26251881Speter#include <apr_uri.h> 27251881Speter#include <serf.h> 28251881Speter 29251881Speter#include "svn_hash.h" 30251881Speter#include "svn_pools.h" 31251881Speter#include "svn_ra.h" 32251881Speter#include "svn_dav.h" 33251881Speter#include "svn_base64.h" 34251881Speter#include "svn_xml.h" 35251881Speter#include "svn_config.h" 36251881Speter#include "svn_path.h" 37251881Speter#include "svn_props.h" 38251881Speter 39251881Speter#include "private/svn_dav_protocol.h" 40251881Speter#include "private/svn_string_private.h" 41251881Speter#include "private/svn_subr_private.h" 42251881Speter#include "svn_private_config.h" 43251881Speter 44251881Speter#include "ra_serf.h" 45251881Speter#include "../libsvn_ra/ra_loader.h" 46251881Speter 47251881Speter 48251881Speter/* 49251881Speter * This enum represents the current state of our XML parsing for a REPORT. 50251881Speter */ 51251881Speterenum { 52251881Speter INITIAL = 0, 53251881Speter REPORT, 54251881Speter ITEM, 55251881Speter VERSION, 56251881Speter CREATOR, 57251881Speter DATE, 58251881Speter COMMENT, 59251881Speter REVPROP, 60251881Speter HAS_CHILDREN, 61251881Speter ADDED_PATH, 62251881Speter REPLACED_PATH, 63251881Speter DELETED_PATH, 64251881Speter MODIFIED_PATH, 65251881Speter SUBTRACTIVE_MERGE 66251881Speter}; 67251881Speter 68251881Spetertypedef struct log_context_t { 69251881Speter apr_pool_t *pool; 70251881Speter 71251881Speter /* parameters set by our caller */ 72251881Speter const apr_array_header_t *paths; 73251881Speter svn_revnum_t start; 74251881Speter svn_revnum_t end; 75251881Speter int limit; 76251881Speter svn_boolean_t changed_paths; 77251881Speter svn_boolean_t strict_node_history; 78251881Speter svn_boolean_t include_merged_revisions; 79251881Speter const apr_array_header_t *revprops; 80251881Speter int nest_level; /* used to track mergeinfo nesting levels */ 81251881Speter int count; /* only incremented when nest_level == 0 */ 82251881Speter 83251881Speter /* Collect information for storage into a log entry. Most of the entry 84251881Speter members are collected by individual states. revprops and paths are 85251881Speter N datapoints per entry. */ 86251881Speter apr_hash_t *collect_revprops; 87251881Speter apr_hash_t *collect_paths; 88251881Speter 89251881Speter /* log receiver function and baton */ 90251881Speter svn_log_entry_receiver_t receiver; 91251881Speter void *receiver_baton; 92251881Speter 93251881Speter /* pre-1.5 compatibility */ 94251881Speter svn_boolean_t want_author; 95251881Speter svn_boolean_t want_date; 96251881Speter svn_boolean_t want_message; 97251881Speter} log_context_t; 98251881Speter 99251881Speter#define D_ "DAV:" 100251881Speter#define S_ SVN_XML_NAMESPACE 101251881Speterstatic const svn_ra_serf__xml_transition_t log_ttable[] = { 102251881Speter { INITIAL, S_, "log-report", REPORT, 103251881Speter FALSE, { NULL }, FALSE }, 104251881Speter 105251881Speter /* Note that we have an opener here. We need to construct a new LOG_ENTRY 106251881Speter to record multiple paths. */ 107251881Speter { REPORT, S_, "log-item", ITEM, 108251881Speter FALSE, { NULL }, TRUE }, 109251881Speter 110251881Speter { ITEM, D_, SVN_DAV__VERSION_NAME, VERSION, 111251881Speter TRUE, { NULL }, TRUE }, 112251881Speter 113251881Speter { ITEM, D_, "creator-displayname", CREATOR, 114251881Speter TRUE, { "?encoding", NULL }, TRUE }, 115251881Speter 116251881Speter { ITEM, S_, "date", DATE, 117251881Speter TRUE, { "?encoding", NULL }, TRUE }, 118251881Speter 119251881Speter { ITEM, D_, "comment", COMMENT, 120251881Speter TRUE, { "?encoding", NULL }, TRUE }, 121251881Speter 122251881Speter { ITEM, S_, "revprop", REVPROP, 123251881Speter TRUE, { "name", "?encoding", NULL }, TRUE }, 124251881Speter 125251881Speter { ITEM, S_, "has-children", HAS_CHILDREN, 126251881Speter FALSE, { NULL }, TRUE }, 127251881Speter 128251881Speter { ITEM, S_, "subtractive-merge", SUBTRACTIVE_MERGE, 129251881Speter FALSE, { NULL }, TRUE }, 130251881Speter 131251881Speter { ITEM, S_, "added-path", ADDED_PATH, 132251881Speter TRUE, { "?node-kind", "?text-mods", "?prop-mods", 133251881Speter "?copyfrom-path", "?copyfrom-rev", NULL }, TRUE }, 134251881Speter 135251881Speter { ITEM, S_, "replaced-path", REPLACED_PATH, 136251881Speter TRUE, { "?node-kind", "?text-mods", "?prop-mods", 137251881Speter "?copyfrom-path", "?copyfrom-rev", NULL }, TRUE }, 138251881Speter 139251881Speter { ITEM, S_, "deleted-path", DELETED_PATH, 140251881Speter TRUE, { "?node-kind", "?text-mods", "?prop-mods", NULL }, TRUE }, 141251881Speter 142251881Speter { ITEM, S_, "modified-path", MODIFIED_PATH, 143251881Speter TRUE, { "?node-kind", "?text-mods", "?prop-mods", NULL }, TRUE }, 144251881Speter 145251881Speter { 0 } 146251881Speter}; 147251881Speter 148251881Speter 149251881Speter/* Store CDATA into REVPROPS, associated with PROPNAME. If ENCODING is not 150251881Speter NULL, then it must base "base64" and CDATA will be decoded first. 151251881Speter 152251881Speter NOTE: PROPNAME must live longer than REVPROPS. */ 153251881Speterstatic svn_error_t * 154251881Spetercollect_revprop(apr_hash_t *revprops, 155251881Speter const char *propname, 156251881Speter const svn_string_t *cdata, 157251881Speter const char *encoding) 158251881Speter{ 159251881Speter apr_pool_t *result_pool = apr_hash_pool_get(revprops); 160251881Speter const svn_string_t *decoded; 161251881Speter 162251881Speter if (encoding) 163251881Speter { 164251881Speter /* Check for a known encoding type. This is easy -- there's 165251881Speter only one. */ 166251881Speter if (strcmp(encoding, "base64") != 0) 167251881Speter { 168251881Speter return svn_error_createf(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL, 169251881Speter _("Unsupported encoding '%s'"), 170251881Speter encoding); 171251881Speter } 172251881Speter 173251881Speter decoded = svn_base64_decode_string(cdata, result_pool); 174251881Speter } 175251881Speter else 176251881Speter { 177251881Speter decoded = svn_string_dup(cdata, result_pool); 178251881Speter } 179251881Speter 180251881Speter /* Caller has ensured PROPNAME has sufficient lifetime. */ 181251881Speter svn_hash_sets(revprops, propname, decoded); 182251881Speter 183251881Speter return SVN_NO_ERROR; 184251881Speter} 185251881Speter 186251881Speter 187251881Speter/* Record ACTION on the path in CDATA into PATHS. Other properties about 188251881Speter the action are pulled from ATTRS. */ 189251881Speterstatic svn_error_t * 190251881Spetercollect_path(apr_hash_t *paths, 191251881Speter char action, 192251881Speter const svn_string_t *cdata, 193251881Speter apr_hash_t *attrs) 194251881Speter{ 195251881Speter apr_pool_t *result_pool = apr_hash_pool_get(paths); 196251881Speter svn_log_changed_path2_t *lcp; 197251881Speter const char *copyfrom_path; 198251881Speter const char *copyfrom_rev; 199251881Speter const char *path; 200251881Speter 201251881Speter lcp = svn_log_changed_path2_create(result_pool); 202251881Speter lcp->action = action; 203251881Speter lcp->copyfrom_rev = SVN_INVALID_REVNUM; 204251881Speter 205251881Speter /* COPYFROM_* are only recorded for ADDED_PATH and REPLACED_PATH. */ 206251881Speter copyfrom_path = svn_hash_gets(attrs, "copyfrom-path"); 207251881Speter copyfrom_rev = svn_hash_gets(attrs, "copyfrom-rev"); 208251881Speter if (copyfrom_path && copyfrom_rev) 209251881Speter { 210251881Speter svn_revnum_t rev = SVN_STR_TO_REV(copyfrom_rev); 211251881Speter 212251881Speter if (SVN_IS_VALID_REVNUM(rev)) 213251881Speter { 214251881Speter lcp->copyfrom_path = apr_pstrdup(result_pool, copyfrom_path); 215251881Speter lcp->copyfrom_rev = rev; 216251881Speter } 217251881Speter } 218251881Speter 219251881Speter lcp->node_kind = svn_node_kind_from_word(svn_hash_gets(attrs, "node-kind")); 220251881Speter lcp->text_modified = svn_tristate__from_word(svn_hash_gets(attrs, 221251881Speter "text-mods")); 222251881Speter lcp->props_modified = svn_tristate__from_word(svn_hash_gets(attrs, 223251881Speter "prop-mods")); 224251881Speter 225251881Speter path = apr_pstrmemdup(result_pool, cdata->data, cdata->len); 226251881Speter svn_hash_sets(paths, path, lcp); 227251881Speter 228251881Speter return SVN_NO_ERROR; 229251881Speter} 230251881Speter 231251881Speter 232251881Speter/* Conforms to svn_ra_serf__xml_opened_t */ 233251881Speterstatic svn_error_t * 234251881Speterlog_opened(svn_ra_serf__xml_estate_t *xes, 235251881Speter void *baton, 236251881Speter int entered_state, 237251881Speter const svn_ra_serf__dav_props_t *tag, 238251881Speter apr_pool_t *scratch_pool) 239251881Speter{ 240251881Speter log_context_t *log_ctx = baton; 241251881Speter 242251881Speter if (entered_state == ITEM) 243251881Speter { 244251881Speter apr_pool_t *state_pool = svn_ra_serf__xml_state_pool(xes); 245251881Speter 246251881Speter log_ctx->collect_revprops = apr_hash_make(state_pool); 247251881Speter log_ctx->collect_paths = apr_hash_make(state_pool); 248251881Speter } 249251881Speter 250251881Speter return SVN_NO_ERROR; 251251881Speter} 252251881Speter 253251881Speter 254251881Speter/* Conforms to svn_ra_serf__xml_closed_t */ 255251881Speterstatic svn_error_t * 256251881Speterlog_closed(svn_ra_serf__xml_estate_t *xes, 257251881Speter void *baton, 258251881Speter int leaving_state, 259251881Speter const svn_string_t *cdata, 260251881Speter apr_hash_t *attrs, 261251881Speter apr_pool_t *scratch_pool) 262251881Speter{ 263251881Speter log_context_t *log_ctx = baton; 264251881Speter 265251881Speter if (leaving_state == ITEM) 266251881Speter { 267251881Speter svn_log_entry_t *log_entry; 268251881Speter const char *rev_str; 269251881Speter 270251881Speter if (log_ctx->limit && (log_ctx->nest_level == 0) 271251881Speter && (++log_ctx->count > log_ctx->limit)) 272251881Speter { 273251881Speter return SVN_NO_ERROR; 274251881Speter } 275251881Speter 276251881Speter log_entry = svn_log_entry_create(scratch_pool); 277251881Speter 278251881Speter /* Pick up the paths from the context. These have the same lifetime 279251881Speter as this state. That is long enough for us to pass the paths to 280251881Speter the receiver callback. */ 281251881Speter if (apr_hash_count(log_ctx->collect_paths) > 0) 282251881Speter { 283251881Speter log_entry->changed_paths = log_ctx->collect_paths; 284251881Speter log_entry->changed_paths2 = log_ctx->collect_paths; 285251881Speter } 286251881Speter 287251881Speter /* ... and same story for the collected revprops. */ 288251881Speter log_entry->revprops = log_ctx->collect_revprops; 289251881Speter 290251881Speter log_entry->has_children = svn_hash__get_bool(attrs, 291251881Speter "has-children", 292251881Speter FALSE); 293251881Speter log_entry->subtractive_merge = svn_hash__get_bool(attrs, 294251881Speter "subtractive-merge", 295251881Speter FALSE); 296251881Speter 297251881Speter rev_str = svn_hash_gets(attrs, "revision"); 298251881Speter if (rev_str) 299251881Speter log_entry->revision = SVN_STR_TO_REV(rev_str); 300251881Speter else 301251881Speter log_entry->revision = SVN_INVALID_REVNUM; 302251881Speter 303251881Speter /* Give the info to the reporter */ 304251881Speter SVN_ERR(log_ctx->receiver(log_ctx->receiver_baton, 305251881Speter log_entry, 306251881Speter scratch_pool)); 307251881Speter 308251881Speter if (log_entry->has_children) 309251881Speter { 310251881Speter log_ctx->nest_level++; 311251881Speter } 312251881Speter if (! SVN_IS_VALID_REVNUM(log_entry->revision)) 313251881Speter { 314251881Speter SVN_ERR_ASSERT(log_ctx->nest_level); 315251881Speter log_ctx->nest_level--; 316251881Speter } 317251881Speter 318251881Speter /* These hash tables are going to be unusable once this state's 319251881Speter pool is destroyed. But let's not leave stale pointers in 320251881Speter structures that have a longer life. */ 321251881Speter log_ctx->collect_revprops = NULL; 322251881Speter log_ctx->collect_paths = NULL; 323251881Speter } 324251881Speter else if (leaving_state == VERSION) 325251881Speter { 326251881Speter svn_ra_serf__xml_note(xes, ITEM, "revision", cdata->data); 327251881Speter } 328251881Speter else if (leaving_state == CREATOR) 329251881Speter { 330251881Speter if (log_ctx->want_author) 331251881Speter { 332251881Speter SVN_ERR(collect_revprop(log_ctx->collect_revprops, 333251881Speter SVN_PROP_REVISION_AUTHOR, 334251881Speter cdata, 335251881Speter svn_hash_gets(attrs, "encoding"))); 336251881Speter } 337251881Speter } 338251881Speter else if (leaving_state == DATE) 339251881Speter { 340251881Speter if (log_ctx->want_date) 341251881Speter { 342251881Speter SVN_ERR(collect_revprop(log_ctx->collect_revprops, 343251881Speter SVN_PROP_REVISION_DATE, 344251881Speter cdata, 345251881Speter svn_hash_gets(attrs, "encoding"))); 346251881Speter } 347251881Speter } 348251881Speter else if (leaving_state == COMMENT) 349251881Speter { 350251881Speter if (log_ctx->want_message) 351251881Speter { 352251881Speter SVN_ERR(collect_revprop(log_ctx->collect_revprops, 353251881Speter SVN_PROP_REVISION_LOG, 354251881Speter cdata, 355251881Speter svn_hash_gets(attrs, "encoding"))); 356251881Speter } 357251881Speter } 358251881Speter else if (leaving_state == REVPROP) 359251881Speter { 360251881Speter apr_pool_t *result_pool = apr_hash_pool_get(log_ctx->collect_revprops); 361251881Speter 362251881Speter SVN_ERR(collect_revprop( 363251881Speter log_ctx->collect_revprops, 364251881Speter apr_pstrdup(result_pool, 365251881Speter svn_hash_gets(attrs, "name")), 366251881Speter cdata, 367251881Speter svn_hash_gets(attrs, "encoding") 368251881Speter )); 369251881Speter } 370251881Speter else if (leaving_state == HAS_CHILDREN) 371251881Speter { 372251881Speter svn_ra_serf__xml_note(xes, ITEM, "has-children", "yes"); 373251881Speter } 374251881Speter else if (leaving_state == SUBTRACTIVE_MERGE) 375251881Speter { 376251881Speter svn_ra_serf__xml_note(xes, ITEM, "subtractive-merge", "yes"); 377251881Speter } 378251881Speter else 379251881Speter { 380251881Speter char action; 381251881Speter 382251881Speter if (leaving_state == ADDED_PATH) 383251881Speter action = 'A'; 384251881Speter else if (leaving_state == REPLACED_PATH) 385251881Speter action = 'R'; 386251881Speter else if (leaving_state == DELETED_PATH) 387251881Speter action = 'D'; 388251881Speter else 389251881Speter { 390251881Speter SVN_ERR_ASSERT(leaving_state == MODIFIED_PATH); 391251881Speter action = 'M'; 392251881Speter } 393251881Speter 394251881Speter SVN_ERR(collect_path(log_ctx->collect_paths, action, cdata, attrs)); 395251881Speter } 396251881Speter 397251881Speter return SVN_NO_ERROR; 398251881Speter} 399251881Speter 400251881Speter 401251881Speterstatic svn_error_t * 402251881Spetercreate_log_body(serf_bucket_t **body_bkt, 403251881Speter void *baton, 404251881Speter serf_bucket_alloc_t *alloc, 405251881Speter apr_pool_t *pool) 406251881Speter{ 407251881Speter serf_bucket_t *buckets; 408251881Speter log_context_t *log_ctx = baton; 409251881Speter 410251881Speter buckets = serf_bucket_aggregate_create(alloc); 411251881Speter 412251881Speter svn_ra_serf__add_open_tag_buckets(buckets, alloc, 413251881Speter "S:log-report", 414251881Speter "xmlns:S", SVN_XML_NAMESPACE, 415251881Speter NULL); 416251881Speter 417251881Speter svn_ra_serf__add_tag_buckets(buckets, 418251881Speter "S:start-revision", 419251881Speter apr_ltoa(pool, log_ctx->start), 420251881Speter alloc); 421251881Speter svn_ra_serf__add_tag_buckets(buckets, 422251881Speter "S:end-revision", 423251881Speter apr_ltoa(pool, log_ctx->end), 424251881Speter alloc); 425251881Speter 426251881Speter if (log_ctx->limit) 427251881Speter { 428251881Speter svn_ra_serf__add_tag_buckets(buckets, 429251881Speter "S:limit", apr_ltoa(pool, log_ctx->limit), 430251881Speter alloc); 431251881Speter } 432251881Speter 433251881Speter if (log_ctx->changed_paths) 434251881Speter { 435251881Speter svn_ra_serf__add_tag_buckets(buckets, 436251881Speter "S:discover-changed-paths", NULL, 437251881Speter alloc); 438251881Speter } 439251881Speter 440251881Speter if (log_ctx->strict_node_history) 441251881Speter { 442251881Speter svn_ra_serf__add_tag_buckets(buckets, 443251881Speter "S:strict-node-history", NULL, 444251881Speter alloc); 445251881Speter } 446251881Speter 447251881Speter if (log_ctx->include_merged_revisions) 448251881Speter { 449251881Speter svn_ra_serf__add_tag_buckets(buckets, 450251881Speter "S:include-merged-revisions", NULL, 451251881Speter alloc); 452251881Speter } 453251881Speter 454251881Speter if (log_ctx->revprops) 455251881Speter { 456251881Speter int i; 457251881Speter for (i = 0; i < log_ctx->revprops->nelts; i++) 458251881Speter { 459251881Speter char *name = APR_ARRAY_IDX(log_ctx->revprops, i, char *); 460251881Speter svn_ra_serf__add_tag_buckets(buckets, 461251881Speter "S:revprop", name, 462251881Speter alloc); 463251881Speter } 464251881Speter if (log_ctx->revprops->nelts == 0) 465251881Speter { 466251881Speter svn_ra_serf__add_tag_buckets(buckets, 467251881Speter "S:no-revprops", NULL, 468251881Speter alloc); 469251881Speter } 470251881Speter } 471251881Speter else 472251881Speter { 473251881Speter svn_ra_serf__add_tag_buckets(buckets, 474251881Speter "S:all-revprops", NULL, 475251881Speter alloc); 476251881Speter } 477251881Speter 478251881Speter if (log_ctx->paths) 479251881Speter { 480251881Speter int i; 481251881Speter for (i = 0; i < log_ctx->paths->nelts; i++) 482251881Speter { 483251881Speter svn_ra_serf__add_tag_buckets(buckets, 484251881Speter "S:path", APR_ARRAY_IDX(log_ctx->paths, i, 485251881Speter const char*), 486251881Speter alloc); 487251881Speter } 488251881Speter } 489251881Speter 490251881Speter svn_ra_serf__add_tag_buckets(buckets, 491251881Speter "S:encode-binary-props", NULL, 492251881Speter alloc); 493251881Speter 494251881Speter svn_ra_serf__add_close_tag_buckets(buckets, alloc, 495251881Speter "S:log-report"); 496251881Speter 497251881Speter *body_bkt = buckets; 498251881Speter return SVN_NO_ERROR; 499251881Speter} 500251881Speter 501251881Spetersvn_error_t * 502251881Spetersvn_ra_serf__get_log(svn_ra_session_t *ra_session, 503251881Speter const apr_array_header_t *paths, 504251881Speter svn_revnum_t start, 505251881Speter svn_revnum_t end, 506251881Speter int limit, 507251881Speter svn_boolean_t discover_changed_paths, 508251881Speter svn_boolean_t strict_node_history, 509251881Speter svn_boolean_t include_merged_revisions, 510251881Speter const apr_array_header_t *revprops, 511251881Speter svn_log_entry_receiver_t receiver, 512251881Speter void *receiver_baton, 513251881Speter apr_pool_t *pool) 514251881Speter{ 515251881Speter log_context_t *log_ctx; 516251881Speter svn_ra_serf__session_t *session = ra_session->priv; 517251881Speter svn_ra_serf__handler_t *handler; 518251881Speter svn_ra_serf__xml_context_t *xmlctx; 519251881Speter svn_boolean_t want_custom_revprops; 520251881Speter svn_revnum_t peg_rev; 521251881Speter svn_error_t *err; 522251881Speter const char *req_url; 523251881Speter 524251881Speter log_ctx = apr_pcalloc(pool, sizeof(*log_ctx)); 525251881Speter log_ctx->pool = pool; 526251881Speter log_ctx->receiver = receiver; 527251881Speter log_ctx->receiver_baton = receiver_baton; 528251881Speter log_ctx->paths = paths; 529251881Speter log_ctx->start = start; 530251881Speter log_ctx->end = end; 531251881Speter log_ctx->limit = limit; 532251881Speter log_ctx->changed_paths = discover_changed_paths; 533251881Speter log_ctx->strict_node_history = strict_node_history; 534251881Speter log_ctx->include_merged_revisions = include_merged_revisions; 535251881Speter log_ctx->revprops = revprops; 536251881Speter log_ctx->nest_level = 0; 537251881Speter 538251881Speter want_custom_revprops = FALSE; 539251881Speter if (revprops) 540251881Speter { 541251881Speter int i; 542251881Speter for (i = 0; i < revprops->nelts; i++) 543251881Speter { 544251881Speter char *name = APR_ARRAY_IDX(revprops, i, char *); 545251881Speter if (strcmp(name, SVN_PROP_REVISION_AUTHOR) == 0) 546251881Speter log_ctx->want_author = TRUE; 547251881Speter else if (strcmp(name, SVN_PROP_REVISION_DATE) == 0) 548251881Speter log_ctx->want_date = TRUE; 549251881Speter else if (strcmp(name, SVN_PROP_REVISION_LOG) == 0) 550251881Speter log_ctx->want_message = TRUE; 551251881Speter else 552251881Speter want_custom_revprops = TRUE; 553251881Speter } 554251881Speter } 555251881Speter else 556251881Speter { 557251881Speter log_ctx->want_author = log_ctx->want_date = log_ctx->want_message = TRUE; 558251881Speter want_custom_revprops = TRUE; 559251881Speter } 560251881Speter 561251881Speter if (want_custom_revprops) 562251881Speter { 563251881Speter svn_boolean_t has_log_revprops; 564251881Speter SVN_ERR(svn_ra_serf__has_capability(ra_session, &has_log_revprops, 565251881Speter SVN_RA_CAPABILITY_LOG_REVPROPS, pool)); 566251881Speter if (!has_log_revprops) 567251881Speter return svn_error_create(SVN_ERR_RA_NOT_IMPLEMENTED, NULL, 568251881Speter _("Server does not support custom revprops" 569251881Speter " via log")); 570251881Speter } 571251881Speter /* At this point, we may have a deleted file. So, we'll match ra_neon's 572251881Speter * behavior and use the larger of start or end as our 'peg' rev. 573251881Speter */ 574251881Speter peg_rev = (start > end) ? start : end; 575251881Speter 576251881Speter SVN_ERR(svn_ra_serf__get_stable_url(&req_url, NULL /* latest_revnum */, 577251881Speter session, NULL /* conn */, 578251881Speter NULL /* url */, peg_rev, 579251881Speter pool, pool)); 580251881Speter 581251881Speter xmlctx = svn_ra_serf__xml_context_create(log_ttable, 582251881Speter log_opened, log_closed, NULL, 583251881Speter log_ctx, 584251881Speter pool); 585251881Speter handler = svn_ra_serf__create_expat_handler(xmlctx, pool); 586251881Speter 587251881Speter handler->method = "REPORT"; 588251881Speter handler->path = req_url; 589251881Speter handler->body_delegate = create_log_body; 590251881Speter handler->body_delegate_baton = log_ctx; 591251881Speter handler->body_type = "text/xml"; 592251881Speter handler->conn = session->conns[0]; 593251881Speter handler->session = session; 594251881Speter 595251881Speter err = svn_ra_serf__context_run_one(handler, pool); 596251881Speter 597251881Speter SVN_ERR(svn_error_compose_create( 598253734Speter svn_ra_serf__error_on_status(handler->sline, 599251881Speter req_url, 600251881Speter handler->location), 601251881Speter err)); 602251881Speter 603251881Speter return SVN_NO_ERROR; 604251881Speter} 605