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