log.c revision 266731
138494Sobrien/* 2174294Sobrien * log.c : entry point for log RA functions for ra_serf 338494Sobrien * 438494Sobrien * ==================================================================== 538494Sobrien * Licensed to the Apache Software Foundation (ASF) under one 638494Sobrien * or more contributor license agreements. See the NOTICE file 738494Sobrien * distributed with this work for additional information 838494Sobrien * regarding copyright ownership. The ASF licenses this file 938494Sobrien * to you under the Apache License, Version 2.0 (the 1038494Sobrien * "License"); you may not use this file except in compliance 1138494Sobrien * with the License. You may obtain a copy of the License at 1238494Sobrien * 1338494Sobrien * http://www.apache.org/licenses/LICENSE-2.0 1438494Sobrien * 1538494Sobrien * Unless required by applicable law or agreed to in writing, 1638494Sobrien * software distributed under the License is distributed on an 1738494Sobrien * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 1838494Sobrien * KIND, either express or implied. See the License for the 1938494Sobrien * specific language governing permissions and limitations 2042629Sobrien * under the License. 2138494Sobrien * ==================================================================== 2238494Sobrien */ 2338494Sobrien 2438494Sobrien 2538494Sobrien 2638494Sobrien#include <apr_uri.h> 2738494Sobrien#include <serf.h> 2838494Sobrien 2938494Sobrien#include "svn_hash.h" 3038494Sobrien#include "svn_pools.h" 3138494Sobrien#include "svn_ra.h" 3238494Sobrien#include "svn_dav.h" 3338494Sobrien#include "svn_base64.h" 3438494Sobrien#include "svn_xml.h" 3538494Sobrien#include "svn_config.h" 3638494Sobrien#include "svn_path.h" 3738494Sobrien#include "svn_props.h" 3838494Sobrien 3938494Sobrien#include "private/svn_dav_protocol.h" 40174294Sobrien#include "private/svn_string_private.h" 4138494Sobrien#include "private/svn_subr_private.h" 4238494Sobrien#include "svn_private_config.h" 4338494Sobrien 4438494Sobrien#include "ra_serf.h" 4538494Sobrien#include "../libsvn_ra/ra_loader.h" 4638494Sobrien 4738494Sobrien 4838494Sobrien/* 4938494Sobrien * This enum represents the current state of our XML parsing for a REPORT. 5038494Sobrien */ 5138494Sobrienenum { 5238494Sobrien INITIAL = 0, 5338494Sobrien REPORT, 5438494Sobrien ITEM, 5538494Sobrien VERSION, 5638494Sobrien CREATOR, 5738494Sobrien DATE, 5838494Sobrien COMMENT, 5938494Sobrien REVPROP, 6038494Sobrien HAS_CHILDREN, 6138494Sobrien ADDED_PATH, 6238494Sobrien REPLACED_PATH, 6338494Sobrien DELETED_PATH, 6438494Sobrien MODIFIED_PATH, 6538494Sobrien SUBTRACTIVE_MERGE 6638494Sobrien}; 6738494Sobrien 6838494Sobrientypedef struct log_context_t { 6938494Sobrien apr_pool_t *pool; 7038494Sobrien 7138494Sobrien /* parameters set by our caller */ 7238494Sobrien const apr_array_header_t *paths; 7338494Sobrien svn_revnum_t start; 7438494Sobrien svn_revnum_t end; 7538494Sobrien int limit; 7638494Sobrien svn_boolean_t changed_paths; 7738494Sobrien svn_boolean_t strict_node_history; 78174294Sobrien svn_boolean_t include_merged_revisions; 7938494Sobrien const apr_array_header_t *revprops; 80174294Sobrien int nest_level; /* used to track mergeinfo nesting levels */ 8138494Sobrien int count; /* only incremented when nest_level == 0 */ 8238494Sobrien 8338494Sobrien /* Collect information for storage into a log entry. Most of the entry 84174294Sobrien members are collected by individual states. revprops and paths are 8538494Sobrien N datapoints per entry. */ 8638494Sobrien apr_hash_t *collect_revprops; 87174294Sobrien apr_hash_t *collect_paths; 88174294Sobrien 89174294Sobrien /* log receiver function and baton */ 9052894Sobrien svn_log_entry_receiver_t receiver; 9138494Sobrien void *receiver_baton; 9238494Sobrien 9338494Sobrien /* pre-1.5 compatibility */ 9438494Sobrien svn_boolean_t want_author; 9538494Sobrien svn_boolean_t want_date; 9638494Sobrien svn_boolean_t want_message; 9738494Sobrien} log_context_t; 98174294Sobrien 9938494Sobrien#define D_ "DAV:" 100174294Sobrien#define S_ SVN_XML_NAMESPACE 10138494Sobrienstatic const svn_ra_serf__xml_transition_t log_ttable[] = { 10238494Sobrien { INITIAL, S_, "log-report", REPORT, 103174294Sobrien FALSE, { NULL }, FALSE }, 10438494Sobrien 105174294Sobrien /* Note that we have an opener here. We need to construct a new LOG_ENTRY 10638494Sobrien to record multiple paths. */ 10738494Sobrien { REPORT, S_, "log-item", ITEM, 10838494Sobrien FALSE, { NULL }, TRUE }, 10938494Sobrien 110174294Sobrien { ITEM, D_, SVN_DAV__VERSION_NAME, VERSION, 111174294Sobrien TRUE, { NULL }, TRUE }, 112131702Smbr 11382794Sobrien { ITEM, D_, "creator-displayname", CREATOR, 11438494Sobrien TRUE, { "?encoding", NULL }, TRUE }, 115174294Sobrien 116174294Sobrien { ITEM, S_, "date", DATE, 117174294Sobrien TRUE, { "?encoding", NULL }, TRUE }, 11838494Sobrien 119174294Sobrien { ITEM, D_, "comment", COMMENT, 120174294Sobrien TRUE, { "?encoding", NULL }, TRUE }, 121174294Sobrien 12282794Sobrien { ITEM, S_, "revprop", REVPROP, 12338494Sobrien TRUE, { "name", "?encoding", NULL }, TRUE }, 12438494Sobrien 125174294Sobrien { ITEM, S_, "has-children", HAS_CHILDREN, 12638494Sobrien FALSE, { NULL }, TRUE }, 12738494Sobrien 12838494Sobrien { ITEM, S_, "subtractive-merge", SUBTRACTIVE_MERGE, 12938494Sobrien FALSE, { NULL }, TRUE }, 13038494Sobrien 13138494Sobrien { ITEM, S_, "added-path", ADDED_PATH, 13238494Sobrien TRUE, { "?node-kind", "?text-mods", "?prop-mods", 13382794Sobrien "?copyfrom-path", "?copyfrom-rev", NULL }, TRUE }, 13438494Sobrien 135174294Sobrien { ITEM, S_, "replaced-path", REPLACED_PATH, 13638494Sobrien TRUE, { "?node-kind", "?text-mods", "?prop-mods", 137174294Sobrien "?copyfrom-path", "?copyfrom-rev", NULL }, TRUE }, 13852894Sobrien 13938494Sobrien { ITEM, S_, "deleted-path", DELETED_PATH, 140174294Sobrien TRUE, { "?node-kind", "?text-mods", "?prop-mods", NULL }, TRUE }, 14138494Sobrien 14238494Sobrien { ITEM, S_, "modified-path", MODIFIED_PATH, 14338494Sobrien TRUE, { "?node-kind", "?text-mods", "?prop-mods", NULL }, TRUE }, 144174294Sobrien 14538494Sobrien { 0 } 14638494Sobrien}; 14738494Sobrien 14838494Sobrien 14938494Sobrien/* Store CDATA into REVPROPS, associated with PROPNAME. If ENCODING is not 150174294Sobrien NULL, then it must base "base64" and CDATA will be decoded first. 15138494Sobrien 15238494Sobrien NOTE: PROPNAME must live longer than REVPROPS. */ 15338494Sobrienstatic svn_error_t * 15438494Sobriencollect_revprop(apr_hash_t *revprops, 15538494Sobrien const char *propname, 156174294Sobrien const svn_string_t *cdata, 157174294Sobrien const char *encoding) 15838494Sobrien{ 15938494Sobrien apr_pool_t *result_pool = apr_hash_pool_get(revprops); 160174294Sobrien const svn_string_t *decoded; 16138494Sobrien 162174294Sobrien if (encoding) 16338494Sobrien { 16438494Sobrien /* Check for a known encoding type. This is easy -- there's 16538494Sobrien only one. */ 166174294Sobrien if (strcmp(encoding, "base64") != 0) 16738494Sobrien { 16838494Sobrien return svn_error_createf(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL, 169174294Sobrien _("Unsupported encoding '%s'"), 170174294Sobrien encoding); 171174294Sobrien } 17238494Sobrien 17352894Sobrien decoded = svn_base64_decode_string(cdata, result_pool); 17438494Sobrien } 17538494Sobrien else 17638494Sobrien { 17738494Sobrien decoded = svn_string_dup(cdata, result_pool); 17838494Sobrien } 17938494Sobrien 180174294Sobrien /* Caller has ensured PROPNAME has sufficient lifetime. */ 18138494Sobrien svn_hash_sets(revprops, propname, decoded); 182174294Sobrien 18338494Sobrien return SVN_NO_ERROR; 18438494Sobrien} 185174294Sobrien 18638494Sobrien 187174294Sobrien/* Record ACTION on the path in CDATA into PATHS. Other properties about 18838494Sobrien the action are pulled from ATTRS. */ 18938494Sobrienstatic svn_error_t * 19038494Sobriencollect_path(apr_hash_t *paths, 19138494Sobrien char action, 192174294Sobrien const svn_string_t *cdata, 193174294Sobrien apr_hash_t *attrs) 194131702Smbr{ 19582794Sobrien apr_pool_t *result_pool = apr_hash_pool_get(paths); 19638494Sobrien svn_log_changed_path2_t *lcp; 197174294Sobrien const char *copyfrom_path; 198174294Sobrien const char *copyfrom_rev; 199174294Sobrien const char *path; 20038494Sobrien 201174294Sobrien lcp = svn_log_changed_path2_create(result_pool); 202174294Sobrien lcp->action = action; 203174294Sobrien lcp->copyfrom_rev = SVN_INVALID_REVNUM; 20482794Sobrien 20538494Sobrien /* COPYFROM_* are only recorded for ADDED_PATH and REPLACED_PATH. */ 20638494Sobrien copyfrom_path = svn_hash_gets(attrs, "copyfrom-path"); 207174294Sobrien copyfrom_rev = svn_hash_gets(attrs, "copyfrom-rev"); 20838494Sobrien if (copyfrom_path && copyfrom_rev) 20938494Sobrien { 21038494Sobrien svn_revnum_t rev = SVN_STR_TO_REV(copyfrom_rev); 21138494Sobrien 21238494Sobrien if (SVN_IS_VALID_REVNUM(rev)) 21338494Sobrien { 21438494Sobrien lcp->copyfrom_path = apr_pstrdup(result_pool, copyfrom_path); 21582794Sobrien lcp->copyfrom_rev = rev; 21682794Sobrien } 21738494Sobrien } 218174294Sobrien 21938494Sobrien lcp->node_kind = svn_node_kind_from_word(svn_hash_gets(attrs, "node-kind")); 220174294Sobrien lcp->text_modified = svn_tristate__from_word(svn_hash_gets(attrs, 22152894Sobrien "text-mods")); 22238494Sobrien lcp->props_modified = svn_tristate__from_word(svn_hash_gets(attrs, 22338494Sobrien "prop-mods")); 22438494Sobrien 22538494Sobrien path = apr_pstrmemdup(result_pool, cdata->data, cdata->len); 22638494Sobrien svn_hash_sets(paths, path, lcp); 227174294Sobrien 22838494Sobrien return SVN_NO_ERROR; 22938494Sobrien} 230174294Sobrien 23138494Sobrien 23238494Sobrien/* Conforms to svn_ra_serf__xml_opened_t */ 23338494Sobrienstatic svn_error_t * 23438494Sobrienlog_opened(svn_ra_serf__xml_estate_t *xes, 23538494Sobrien void *baton, 236174294Sobrien int entered_state, 23738494Sobrien const svn_ra_serf__dav_props_t *tag, 23838494Sobrien apr_pool_t *scratch_pool) 23938494Sobrien{ 24038494Sobrien log_context_t *log_ctx = baton; 24138494Sobrien 242174294Sobrien if (entered_state == ITEM) 24338494Sobrien { 24438494Sobrien apr_pool_t *state_pool = svn_ra_serf__xml_state_pool(xes); 24538494Sobrien 24638494Sobrien log_ctx->collect_revprops = apr_hash_make(state_pool); 24738494Sobrien log_ctx->collect_paths = apr_hash_make(state_pool); 248174294Sobrien } 249174294Sobrien 250174294Sobrien return SVN_NO_ERROR; 25138494Sobrien} 25238494Sobrien 25338494Sobrien 25438494Sobrien/* Conforms to svn_ra_serf__xml_closed_t */ 25538494Sobrienstatic svn_error_t * 25638494Sobrienlog_closed(svn_ra_serf__xml_estate_t *xes, 25738494Sobrien void *baton, 25838494Sobrien int leaving_state, 25938494Sobrien const svn_string_t *cdata, 26038494Sobrien apr_hash_t *attrs, 26138494Sobrien apr_pool_t *scratch_pool) 26238494Sobrien{ 26382794Sobrien log_context_t *log_ctx = baton; 26438494Sobrien 26538494Sobrien if (leaving_state == ITEM) 26638494Sobrien { 26738494Sobrien svn_log_entry_t *log_entry; 268174294Sobrien const char *rev_str; 26938494Sobrien 27038494Sobrien if (log_ctx->limit && (log_ctx->nest_level == 0) 27138494Sobrien && (++log_ctx->count > log_ctx->limit)) 27238494Sobrien { 27338494Sobrien return SVN_NO_ERROR; 27438494Sobrien } 27538494Sobrien 27638494Sobrien log_entry = svn_log_entry_create(scratch_pool); 277174294Sobrien 27838494Sobrien /* Pick up the paths from the context. These have the same lifetime 27938494Sobrien as this state. That is long enough for us to pass the paths to 28038494Sobrien the receiver callback. */ 28138494Sobrien if (apr_hash_count(log_ctx->collect_paths) > 0) 282174294Sobrien { 28338494Sobrien log_entry->changed_paths = log_ctx->collect_paths; 28438494Sobrien log_entry->changed_paths2 = log_ctx->collect_paths; 28538494Sobrien } 28638494Sobrien 287174294Sobrien /* ... and same story for the collected revprops. */ 28838494Sobrien log_entry->revprops = log_ctx->collect_revprops; 289174294Sobrien 290174294Sobrien log_entry->has_children = svn_hash__get_bool(attrs, 291174294Sobrien "has-children", 292174294Sobrien FALSE); 293174294Sobrien log_entry->subtractive_merge = svn_hash__get_bool(attrs, 294174294Sobrien "subtractive-merge", 295174294Sobrien FALSE); 29638494Sobrien 29738494Sobrien rev_str = svn_hash_gets(attrs, "revision"); 29838494Sobrien if (rev_str) 29938494Sobrien log_entry->revision = SVN_STR_TO_REV(rev_str); 30038494Sobrien else 30138494Sobrien log_entry->revision = SVN_INVALID_REVNUM; 30238494Sobrien 30338494Sobrien /* Give the info to the reporter */ 30438494Sobrien SVN_ERR(log_ctx->receiver(log_ctx->receiver_baton, 30538494Sobrien log_entry, 306174294Sobrien scratch_pool)); 30738494Sobrien 30838494Sobrien if (log_entry->has_children) 309174294Sobrien { 310174294Sobrien log_ctx->nest_level++; 311174294Sobrien } 312174294Sobrien if (! SVN_IS_VALID_REVNUM(log_entry->revision)) 313174294Sobrien { 314174294Sobrien SVN_ERR_ASSERT(log_ctx->nest_level); 315174294Sobrien log_ctx->nest_level--; 316174294Sobrien } 317174294Sobrien 318174294Sobrien /* These hash tables are going to be unusable once this state's 31938494Sobrien pool is destroyed. But let's not leave stale pointers in 32038494Sobrien structures that have a longer life. */ 321174294Sobrien log_ctx->collect_revprops = NULL; 322174294Sobrien log_ctx->collect_paths = NULL; 323174294Sobrien } 324174294Sobrien else if (leaving_state == VERSION) 325174294Sobrien { 326174294Sobrien svn_ra_serf__xml_note(xes, ITEM, "revision", cdata->data); 327174294Sobrien } 328174294Sobrien else if (leaving_state == CREATOR) 329174294Sobrien { 330174294Sobrien if (log_ctx->want_author) 331174294Sobrien { 332174294Sobrien SVN_ERR(collect_revprop(log_ctx->collect_revprops, 333174294Sobrien SVN_PROP_REVISION_AUTHOR, 334174294Sobrien cdata, 335174294Sobrien svn_hash_gets(attrs, "encoding"))); 33638494Sobrien } 337174294Sobrien } 33838494Sobrien else if (leaving_state == DATE) 33938494Sobrien { 34038494Sobrien if (log_ctx->want_date) 34138494Sobrien { 34238494Sobrien SVN_ERR(collect_revprop(log_ctx->collect_revprops, 34338494Sobrien SVN_PROP_REVISION_DATE, 34438494Sobrien cdata, 34538494Sobrien svn_hash_gets(attrs, "encoding"))); 34638494Sobrien } 34738494Sobrien } 34838494Sobrien else if (leaving_state == COMMENT) 34938494Sobrien { 35038494Sobrien if (log_ctx->want_message) 35138494Sobrien { 35238494Sobrien SVN_ERR(collect_revprop(log_ctx->collect_revprops, 35338494Sobrien SVN_PROP_REVISION_LOG, 35438494Sobrien cdata, 35538494Sobrien svn_hash_gets(attrs, "encoding"))); 35638494Sobrien } 35738494Sobrien } 35838494Sobrien else if (leaving_state == REVPROP) 35938494Sobrien { 36038494Sobrien apr_pool_t *result_pool = apr_hash_pool_get(log_ctx->collect_revprops); 36138494Sobrien 36238494Sobrien SVN_ERR(collect_revprop( 36338494Sobrien log_ctx->collect_revprops, 36438494Sobrien apr_pstrdup(result_pool, 36538494Sobrien svn_hash_gets(attrs, "name")), 36638494Sobrien cdata, 36738494Sobrien svn_hash_gets(attrs, "encoding") 36838494Sobrien )); 36938494Sobrien } 37038494Sobrien else if (leaving_state == HAS_CHILDREN) 37138494Sobrien { 37238494Sobrien svn_ra_serf__xml_note(xes, ITEM, "has-children", "yes"); 37338494Sobrien } 37438494Sobrien else if (leaving_state == SUBTRACTIVE_MERGE) 375174294Sobrien { 376174294Sobrien svn_ra_serf__xml_note(xes, ITEM, "subtractive-merge", "yes"); 377174294Sobrien } 378174294Sobrien else 379174294Sobrien { 380174294Sobrien char action; 381174294Sobrien 382174294Sobrien if (leaving_state == ADDED_PATH) 383174294Sobrien action = 'A'; 384174294Sobrien else if (leaving_state == REPLACED_PATH) 385174294Sobrien action = 'R'; 386174294Sobrien else if (leaving_state == DELETED_PATH) 38738494Sobrien action = 'D'; 38838494Sobrien else 38938494Sobrien { 39038494Sobrien SVN_ERR_ASSERT(leaving_state == MODIFIED_PATH); 39138494Sobrien action = 'M'; 39238494Sobrien } 39338494Sobrien 39438494Sobrien SVN_ERR(collect_path(log_ctx->collect_paths, action, cdata, attrs)); 395174294Sobrien } 396174294Sobrien 397174294Sobrien return SVN_NO_ERROR; 398174294Sobrien} 399174294Sobrien 400174294Sobrien 401174294Sobrienstatic svn_error_t * 402174294Sobriencreate_log_body(serf_bucket_t **body_bkt, 403174294Sobrien void *baton, 404174294Sobrien serf_bucket_alloc_t *alloc, 405174294Sobrien apr_pool_t *pool) 406174294Sobrien{ 407174294Sobrien serf_bucket_t *buckets; 408174294Sobrien log_context_t *log_ctx = baton; 409174294Sobrien 410174294Sobrien buckets = serf_bucket_aggregate_create(alloc); 41138494Sobrien 41238494Sobrien svn_ra_serf__add_open_tag_buckets(buckets, alloc, 41338494Sobrien "S:log-report", 41438494Sobrien "xmlns:S", SVN_XML_NAMESPACE, 41538494Sobrien NULL); 41638494Sobrien 41738494Sobrien svn_ra_serf__add_tag_buckets(buckets, 41838494Sobrien "S:start-revision", 41938494Sobrien apr_ltoa(pool, log_ctx->start), 42038494Sobrien alloc); 42138494Sobrien svn_ra_serf__add_tag_buckets(buckets, 42238494Sobrien "S:end-revision", 42338494Sobrien apr_ltoa(pool, log_ctx->end), 42438494Sobrien alloc); 42538494Sobrien 42638494Sobrien if (log_ctx->limit) 42738494Sobrien { 42838494Sobrien svn_ra_serf__add_tag_buckets(buckets, 42938494Sobrien "S:limit", apr_ltoa(pool, log_ctx->limit), 43038494Sobrien alloc); 43138494Sobrien } 43238494Sobrien 43338494Sobrien if (log_ctx->changed_paths) 43438494Sobrien { 43538494Sobrien svn_ra_serf__add_tag_buckets(buckets, 43638494Sobrien "S:discover-changed-paths", NULL, 43738494Sobrien alloc); 43838494Sobrien } 43938494Sobrien 44038494Sobrien if (log_ctx->strict_node_history) 44138494Sobrien { 44238494Sobrien svn_ra_serf__add_tag_buckets(buckets, 44338494Sobrien "S:strict-node-history", NULL, 44438494Sobrien alloc); 44538494Sobrien } 44638494Sobrien 44738494Sobrien if (log_ctx->include_merged_revisions) 448174294Sobrien { 449174294Sobrien svn_ra_serf__add_tag_buckets(buckets, 450174294Sobrien "S:include-merged-revisions", NULL, 451174294Sobrien alloc); 452174294Sobrien } 453174294Sobrien 454174294Sobrien if (log_ctx->revprops) 455174294Sobrien { 45638494Sobrien int i; 45738494Sobrien for (i = 0; i < log_ctx->revprops->nelts; i++) 45838494Sobrien { 459174294Sobrien char *name = APR_ARRAY_IDX(log_ctx->revprops, i, char *); 46038494Sobrien svn_ra_serf__add_tag_buckets(buckets, 46138494Sobrien "S:revprop", name, 46238494Sobrien alloc); 46342629Sobrien } 46438494Sobrien if (log_ctx->revprops->nelts == 0) 46538494Sobrien { 46638494Sobrien svn_ra_serf__add_tag_buckets(buckets, 46738494Sobrien "S:no-revprops", NULL, 46838494Sobrien alloc); 46938494Sobrien } 47038494Sobrien } 47138494Sobrien else 47238494Sobrien { 47338494Sobrien svn_ra_serf__add_tag_buckets(buckets, 47438494Sobrien "S:all-revprops", NULL, 47538494Sobrien alloc); 47638494Sobrien } 47738494Sobrien 47838494Sobrien if (log_ctx->paths) 47938494Sobrien { 480174294Sobrien int i; 481174294Sobrien for (i = 0; i < log_ctx->paths->nelts; i++) 482174294Sobrien { 483174294Sobrien svn_ra_serf__add_tag_buckets(buckets, 484174294Sobrien "S:path", APR_ARRAY_IDX(log_ctx->paths, i, 485174294Sobrien const char*), 486174294Sobrien alloc); 487174294Sobrien } 488174294Sobrien } 489174294Sobrien 490174294Sobrien svn_ra_serf__add_tag_buckets(buckets, 491174294Sobrien "S:encode-binary-props", NULL, 492174294Sobrien alloc); 493174294Sobrien 494174294Sobrien svn_ra_serf__add_close_tag_buckets(buckets, alloc, 495174294Sobrien "S:log-report"); 496174294Sobrien 497174294Sobrien *body_bkt = buckets; 498174294Sobrien return SVN_NO_ERROR; 499174294Sobrien} 500174294Sobrien 501174294Sobriensvn_error_t * 502174294Sobriensvn_ra_serf__get_log(svn_ra_session_t *ra_session, 503174294Sobrien const apr_array_header_t *paths, 504174294Sobrien svn_revnum_t start, 505174294Sobrien svn_revnum_t end, 506174294Sobrien int limit, 507174294Sobrien svn_boolean_t discover_changed_paths, 508174294Sobrien svn_boolean_t strict_node_history, 509174294Sobrien svn_boolean_t include_merged_revisions, 510174294Sobrien const apr_array_header_t *revprops, 511174294Sobrien svn_log_entry_receiver_t receiver, 512174294Sobrien void *receiver_baton, 513174294Sobrien apr_pool_t *pool) 514174294Sobrien{ 515174294Sobrien log_context_t *log_ctx; 516174294Sobrien svn_ra_serf__session_t *session = ra_session->priv; 517174294Sobrien svn_ra_serf__handler_t *handler; 518174294Sobrien svn_ra_serf__xml_context_t *xmlctx; 519174294Sobrien svn_boolean_t want_custom_revprops; 520174294Sobrien svn_revnum_t peg_rev; 521174294Sobrien svn_error_t *err; 522174294Sobrien const char *req_url; 523174294Sobrien 524174294Sobrien log_ctx = apr_pcalloc(pool, sizeof(*log_ctx)); 525174294Sobrien log_ctx->pool = pool; 526174294Sobrien log_ctx->receiver = receiver; 527174294Sobrien log_ctx->receiver_baton = receiver_baton; 528174294Sobrien log_ctx->paths = paths; 529174294Sobrien log_ctx->start = start; 530174294Sobrien log_ctx->end = end; 531174294Sobrien log_ctx->limit = limit; 532174294Sobrien log_ctx->changed_paths = discover_changed_paths; 533174294Sobrien log_ctx->strict_node_history = strict_node_history; 534174294Sobrien log_ctx->include_merged_revisions = include_merged_revisions; 535174294Sobrien log_ctx->revprops = revprops; 536174294Sobrien log_ctx->nest_level = 0; 537174294Sobrien 538174294Sobrien want_custom_revprops = FALSE; 539174294Sobrien if (revprops) 540174294Sobrien { 541174294Sobrien int i; 542174294Sobrien for (i = 0; i < revprops->nelts; i++) 543174294Sobrien { 544174294Sobrien char *name = APR_ARRAY_IDX(revprops, i, char *); 545174294Sobrien if (strcmp(name, SVN_PROP_REVISION_AUTHOR) == 0) 546174294Sobrien log_ctx->want_author = TRUE; 547174294Sobrien else if (strcmp(name, SVN_PROP_REVISION_DATE) == 0) 54852894Sobrien log_ctx->want_date = TRUE; 54952894Sobrien else if (strcmp(name, SVN_PROP_REVISION_LOG) == 0) 55052894Sobrien log_ctx->want_message = TRUE; 55152894Sobrien else 55252894Sobrien want_custom_revprops = TRUE; 55352894Sobrien } 55452894Sobrien } 55552894Sobrien else 55638494Sobrien { 55738494Sobrien log_ctx->want_author = log_ctx->want_date = log_ctx->want_message = TRUE; 55838494Sobrien want_custom_revprops = TRUE; 55938494Sobrien } 56038494Sobrien 56138494Sobrien if (want_custom_revprops) 56238494Sobrien { 56338494Sobrien svn_boolean_t has_log_revprops; 56438494Sobrien SVN_ERR(svn_ra_serf__has_capability(ra_session, &has_log_revprops, 56538494Sobrien SVN_RA_CAPABILITY_LOG_REVPROPS, pool)); 56638494Sobrien if (!has_log_revprops) 56738494Sobrien return svn_error_create(SVN_ERR_RA_NOT_IMPLEMENTED, NULL, 56838494Sobrien _("Server does not support custom revprops" 56938494Sobrien " via log")); 57038494Sobrien } 57138494Sobrien /* At this point, we may have a deleted file. So, we'll match ra_neon's 57238494Sobrien * behavior and use the larger of start or end as our 'peg' rev. 57338494Sobrien */ 57438494Sobrien peg_rev = (start == SVN_INVALID_REVNUM || start > end) ? start : end; 57538494Sobrien 57638494Sobrien SVN_ERR(svn_ra_serf__get_stable_url(&req_url, NULL /* latest_revnum */, 57738494Sobrien session, NULL /* conn */, 57838494Sobrien NULL /* url */, peg_rev, 57938494Sobrien pool, pool)); 58038494Sobrien 58138494Sobrien xmlctx = svn_ra_serf__xml_context_create(log_ttable, 58238494Sobrien log_opened, log_closed, NULL, 58338494Sobrien log_ctx, 58438494Sobrien pool); 58538494Sobrien handler = svn_ra_serf__create_expat_handler(xmlctx, pool); 58638494Sobrien 58738494Sobrien handler->method = "REPORT"; 58838494Sobrien handler->path = req_url; 58938494Sobrien handler->body_delegate = create_log_body; 59038494Sobrien handler->body_delegate_baton = log_ctx; 59138494Sobrien handler->body_type = "text/xml"; 59238494Sobrien handler->conn = session->conns[0]; 59338494Sobrien handler->session = session; 59438494Sobrien 59538494Sobrien err = svn_ra_serf__context_run_one(handler, pool); 59638494Sobrien 59738494Sobrien SVN_ERR(svn_error_compose_create( 59838494Sobrien svn_ra_serf__error_on_status(handler->sline, 59938494Sobrien req_url, 60038494Sobrien handler->location), 60138494Sobrien err)); 60238494Sobrien 60338494Sobrien return SVN_NO_ERROR; 60438494Sobrien} 60538494Sobrien