Return-Path: X-Original-To: apmail-subversion-commits-archive@minotaur.apache.org Delivered-To: apmail-subversion-commits-archive@minotaur.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 8ABF29314 for ; Wed, 16 May 2012 20:34:26 +0000 (UTC) Received: (qmail 27592 invoked by uid 500); 16 May 2012 20:34:26 -0000 Delivered-To: apmail-subversion-commits-archive@subversion.apache.org Received: (qmail 27565 invoked by uid 500); 16 May 2012 20:34:26 -0000 Mailing-List: contact commits-help@subversion.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@subversion.apache.org Delivered-To: mailing list commits@subversion.apache.org Received: (qmail 27556 invoked by uid 99); 16 May 2012 20:34:26 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 16 May 2012 20:34:26 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED,T_FILL_THIS_FORM_SHORT X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 16 May 2012 20:34:20 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id 941802388C73; Wed, 16 May 2012 20:33:14 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1339349 [16/37] - in /subversion/branches/fix-rdump-editor: ./ build/ build/ac-macros/ build/generator/ build/generator/templates/ build/win32/ contrib/client-side/emacs/ contrib/client-side/vim/ contrib/server-side/ notes/ notes/api-errat... Date: Wed, 16 May 2012 20:32:54 -0000 To: commits@subversion.apache.org From: hwright@apache.org X-Mailer: svnmailer-1.0.8-patched Message-Id: <20120516203314.941802388C73@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Modified: subversion/branches/fix-rdump-editor/subversion/libsvn_ra_serf/getlocks.c URL: http://svn.apache.org/viewvc/subversion/branches/fix-rdump-editor/subversion/libsvn_ra_serf/getlocks.c?rev=1339349&r1=1339348&r2=1339349&view=diff ============================================================================== --- subversion/branches/fix-rdump-editor/subversion/libsvn_ra_serf/getlocks.c (original) +++ subversion/branches/fix-rdump-editor/subversion/libsvn_ra_serf/getlocks.c Wed May 16 20:32:43 2012 @@ -46,8 +46,8 @@ /* * This enum represents the current state of our XML parsing for a REPORT. */ -typedef enum lock_state_e { - NONE = 0, +enum { + INITIAL = 0, REPORT, LOCK, PATH, @@ -56,19 +56,7 @@ typedef enum lock_state_e { COMMENT, CREATION_DATE, EXPIRATION_DATE -} lock_state_e; - -typedef struct lock_info_t { - /* Temporary pool */ - apr_pool_t *pool; - - svn_lock_t *lock; - - /* The currently collected value as we build it up */ - const char *tmp; - apr_size_t tmp_len; - -} lock_info_t; +}; typedef struct lock_context_t { apr_pool_t *pool; @@ -80,107 +68,55 @@ typedef struct lock_context_t { /* return hash */ apr_hash_t *hash; - /* are we done? */ - svn_boolean_t done; - } lock_context_t; - -static lock_info_t * -push_state(svn_ra_serf__xml_parser_t *parser, - lock_context_t *lock_ctx, - lock_state_e state) -{ - svn_ra_serf__xml_push_state(parser, state); +#define D_ "DAV:" +#define S_ SVN_XML_NAMESPACE +static const svn_ra_serf__xml_transition_t getlocks_ttable[] = { + { INITIAL, S_, "get-locks-report", REPORT, + FALSE, { NULL }, FALSE, FALSE }, - if (state == LOCK) - { - lock_info_t *info; + { REPORT, S_, "lock", LOCK, + FALSE, { NULL }, FALSE, TRUE }, - info = apr_pcalloc(parser->state->pool, sizeof(*info)); + { LOCK, S_, "path", PATH, + TRUE, { NULL }, FALSE, TRUE }, - info->pool = lock_ctx->pool; - info->lock = svn_lock_create(lock_ctx->pool); - info->lock->path = + { LOCK, S_, "token", TOKEN, + TRUE, { NULL }, FALSE, TRUE }, - parser->state->private = info; - } + { LOCK, S_, "owner", OWNER, + TRUE, { NULL }, FALSE, TRUE }, - return parser->state->private; -} + { LOCK, S_, "comment", COMMENT, + TRUE, { NULL }, FALSE, TRUE }, -static svn_error_t * -start_getlocks(svn_ra_serf__xml_parser_t *parser, - void *userData, - svn_ra_serf__dav_props_t name, - const char **attrs) -{ - lock_context_t *lock_ctx = userData; - lock_state_e state; + { LOCK, S_, SVN_DAV__CREATIONDATE, CREATION_DATE, + TRUE, { NULL }, FALSE, TRUE }, - state = parser->state->current_state; + { LOCK, S_, "expirationdate", EXPIRATION_DATE, + TRUE, { NULL }, FALSE, TRUE }, - if (state == NONE && - strcmp(name.name, "get-locks-report") == 0) - { - push_state(parser, lock_ctx, REPORT); - } - else if (state == REPORT && - strcmp(name.name, "lock") == 0) - { - push_state(parser, lock_ctx, LOCK); - } - else if (state == LOCK) - { - if (strcmp(name.name, "path") == 0) - { - push_state(parser, lock_ctx, PATH); - } - else if (strcmp(name.name, "token") == 0) - { - push_state(parser, lock_ctx, TOKEN); - } - else if (strcmp(name.name, "owner") == 0) - { - push_state(parser, lock_ctx, OWNER); - } - else if (strcmp(name.name, "comment") == 0) - { - push_state(parser, lock_ctx, COMMENT); - } - else if (strcmp(name.name, SVN_DAV__CREATIONDATE) == 0) - { - push_state(parser, lock_ctx, CREATION_DATE); - } - else if (strcmp(name.name, "expirationdate") == 0) - { - push_state(parser, lock_ctx, EXPIRATION_DATE); - } - } - - return SVN_NO_ERROR; -} + { 0 } +}; + +/* Conforms to svn_ra_serf__xml_closed_t */ static svn_error_t * -end_getlocks(svn_ra_serf__xml_parser_t *parser, - void *userData, - svn_ra_serf__dav_props_t name) +getlocks_closed(svn_ra_serf__xml_estate_t *xes, + void *baton, + int leaving_state, + const svn_string_t *cdata, + apr_hash_t *attrs, + apr_pool_t *scratch_pool) { - lock_context_t *lock_ctx = userData; - lock_state_e state; - lock_info_t *info; - - state = parser->state->current_state; - info = parser->state->private; + lock_context_t *lock_ctx = baton; - if (state == REPORT && - strcmp(name.name, "get-locks-report") == 0) - { - svn_ra_serf__xml_pop_state(parser); - } - else if (state == LOCK && - strcmp(name.name, "lock") == 0) + if (leaving_state == LOCK) { + const char *path = apr_hash_get(attrs, "path", APR_HASH_KEY_STRING); + svn_boolean_t save_lock = FALSE; + /* Filter out unwanted paths. Since Subversion only allows locks on files, we can treat depth=immediates the same as depth=files for filtering purposes. Meaning, we'll keep @@ -191,105 +127,81 @@ end_getlocks(svn_ra_serf__xml_parser_t * c) we've asked for depth=files or depth=immediates, and this lock is on an immediate child of our query path. */ - if ((strcmp(lock_ctx->path, info->lock->path) == 0) - || (lock_ctx->requested_depth == svn_depth_infinity)) + if (strcmp(lock_ctx->path, path) == 0 + || lock_ctx->requested_depth == svn_depth_infinity) { - apr_hash_set(lock_ctx->hash, info->lock->path, - APR_HASH_KEY_STRING, info->lock); + save_lock = TRUE; } - else if ((lock_ctx->requested_depth == svn_depth_files) || - (lock_ctx->requested_depth == svn_depth_immediates)) + else if (lock_ctx->requested_depth == svn_depth_files + || lock_ctx->requested_depth == svn_depth_immediates) { - const char *rel_path = svn_fspath__skip_ancestor(lock_ctx->path, - info->lock->path); - if (rel_path && (svn_path_component_count(rel_path) == 1)) - apr_hash_set(lock_ctx->hash, info->lock->path, - APR_HASH_KEY_STRING, info->lock); - } + const char *relpath = svn_fspath__skip_ancestor(lock_ctx->path, + path); + if (relpath && (svn_path_component_count(relpath) == 1)) + save_lock = TRUE; + } + + if (save_lock) + { + /* We get to put the structure on the stack rather than using + svn_lock_create(). Bwahahaha.... */ + svn_lock_t lock = { 0 }; + const char *date; + svn_lock_t *result_lock; + + /* Note: these "attributes" came from child elements. Some of + them may have not been sent, so the value will be NULL. */ + + lock.path = path; + lock.token = apr_hash_get(attrs, "token", APR_HASH_KEY_STRING); + lock.owner = apr_hash_get(attrs, "owner", APR_HASH_KEY_STRING); + lock.comment = apr_hash_get(attrs, "comment", APR_HASH_KEY_STRING); + + date = apr_hash_get(attrs, SVN_DAV__CREATIONDATE, + APR_HASH_KEY_STRING); + if (date) + SVN_ERR(svn_time_from_cstring(&lock.creation_date, date, + scratch_pool)); + + date = apr_hash_get(attrs, "expirationdate", + APR_HASH_KEY_STRING); + if (date) + SVN_ERR(svn_time_from_cstring(&lock.expiration_date, date, + scratch_pool)); + + result_lock = svn_lock_dup(&lock, lock_ctx->pool); + apr_hash_set(lock_ctx->hash, result_lock->path, APR_HASH_KEY_STRING, + result_lock); + } + } + else + { + const char *name; + + SVN_ERR_ASSERT(cdata != NULL); + + if (leaving_state == PATH) + name = "path"; + else if (leaving_state == TOKEN) + name = "token"; + else if (leaving_state == OWNER) + name = "owner"; + else if (leaving_state == COMMENT) + name = "comment"; + else if (leaving_state == CREATION_DATE) + name = SVN_DAV__CREATIONDATE; + else if (leaving_state == EXPIRATION_DATE) + name = "expirationdate"; + else + SVN_ERR_MALFUNCTION(); - svn_ra_serf__xml_pop_state(parser); - } - else if (state == PATH && - strcmp(name.name, "path") == 0) - { - info->lock->path = apr_pstrmemdup(info->pool, info->tmp, info->tmp_len); - info->tmp_len = 0; - svn_ra_serf__xml_pop_state(parser); - } - else if (state == TOKEN && - strcmp(name.name, "token") == 0) - { - info->lock->token = apr_pstrmemdup(info->pool, info->tmp, info->tmp_len); - info->tmp_len = 0; - svn_ra_serf__xml_pop_state(parser); - } - else if (state == OWNER && - strcmp(name.name, "owner") == 0) - { - info->lock->owner = apr_pstrmemdup(info->pool, info->tmp, info->tmp_len); - info->tmp_len = 0; - svn_ra_serf__xml_pop_state(parser); - } - else if (state == COMMENT && - strcmp(name.name, "comment") == 0) - { - info->lock->comment = apr_pstrmemdup(info->pool, - info->tmp, info->tmp_len); - info->tmp_len = 0; - svn_ra_serf__xml_pop_state(parser); - } - else if (state == CREATION_DATE && - strcmp(name.name, SVN_DAV__CREATIONDATE) == 0) - { - SVN_ERR(svn_time_from_cstring(&info->lock->creation_date, - info->tmp, info->pool)); - info->tmp_len = 0; - svn_ra_serf__xml_pop_state(parser); - } - else if (state == EXPIRATION_DATE && - strcmp(name.name, "expirationdate") == 0) - { - SVN_ERR(svn_time_from_cstring(&info->lock->expiration_date, - info->tmp, info->pool)); - info->tmp_len = 0; - svn_ra_serf__xml_pop_state(parser); + /* Store the lock information onto the LOCK elemstate. */ + svn_ra_serf__xml_note(xes, LOCK, name, cdata->data); } return SVN_NO_ERROR; } -static svn_error_t * -cdata_getlocks(svn_ra_serf__xml_parser_t *parser, - void *userData, - const char *data, - apr_size_t len) -{ - lock_context_t *lock_ctx = userData; - lock_state_e state; - lock_info_t *info; - - UNUSED_CTX(lock_ctx); - - state = parser->state->current_state; - info = parser->state->private; - - switch (state) - { - case PATH: - case TOKEN: - case OWNER: - case COMMENT: - case CREATION_DATE: - case EXPIRATION_DATE: - svn_ra_serf__expand_string(&info->tmp, &info->tmp_len, - data, len, parser->state->pool); - break; - default: - break; - } - - return SVN_NO_ERROR; -} /* Implements svn_ra_serf__request_body_delegate_t */ static svn_error_t * @@ -322,9 +234,8 @@ svn_ra_serf__get_locks(svn_ra_session_t lock_context_t *lock_ctx; svn_ra_serf__session_t *session = ra_session->priv; svn_ra_serf__handler_t *handler; - svn_ra_serf__xml_parser_t *parser_ctx; + svn_ra_serf__xml_context_t *xmlctx; const char *req_url, *rel_path; - int status_code; req_url = svn_path_url_add_component2(session->session_url.path, path, pool); SVN_ERR(svn_ra_serf__get_relative_path(&rel_path, req_url, session, @@ -335,9 +246,11 @@ svn_ra_serf__get_locks(svn_ra_session_t lock_ctx->path = apr_pstrcat(pool, "/", rel_path, (char *)NULL); lock_ctx->requested_depth = depth; lock_ctx->hash = apr_hash_make(pool); - lock_ctx->done = FALSE; - handler = apr_pcalloc(pool, sizeof(*handler)); + xmlctx = svn_ra_serf__xml_context_create(getlocks_ttable, + NULL, getlocks_closed, lock_ctx, + pool); + handler = svn_ra_serf__create_expat_handler(xmlctx, pool); handler->method = "REPORT"; handler->path = req_url; @@ -345,25 +258,12 @@ svn_ra_serf__get_locks(svn_ra_session_t handler->conn = session->conns[0]; handler->session = session; - parser_ctx = apr_pcalloc(pool, sizeof(*parser_ctx)); - - parser_ctx->pool = pool; - parser_ctx->user_data = lock_ctx; - parser_ctx->start = start_getlocks; - parser_ctx->end = end_getlocks; - parser_ctx->cdata = cdata_getlocks; - parser_ctx->done = &lock_ctx->done; - parser_ctx->status_code = &status_code; - handler->body_delegate = create_getlocks_body; handler->body_delegate_baton = lock_ctx; - handler->response_handler = svn_ra_serf__handle_xml_parser; - handler->response_baton = parser_ctx; - - svn_ra_serf__request_create(handler); + /* ### use svn_ra_serf__error_on_status() ? */ - SVN_ERR(svn_ra_serf__context_run_wait(&lock_ctx->done, session, pool)); + SVN_ERR(svn_ra_serf__context_run_one(handler, pool)); *locks = lock_ctx->hash; Modified: subversion/branches/fix-rdump-editor/subversion/libsvn_ra_serf/locks.c URL: http://svn.apache.org/viewvc/subversion/branches/fix-rdump-editor/subversion/libsvn_ra_serf/locks.c?rev=1339349&r1=1339348&r2=1339349&view=diff ============================================================================== --- subversion/branches/fix-rdump-editor/subversion/libsvn_ra_serf/locks.c (original) +++ subversion/branches/fix-rdump-editor/subversion/libsvn_ra_serf/locks.c Wed May 16 20:32:43 2012 @@ -24,9 +24,6 @@ #include - -#include - #include #include "svn_dav.h" @@ -45,8 +42,11 @@ /* * This enum represents the current state of our XML parsing for a REPORT. */ -typedef enum lock_state_e { - NONE = 0, +enum { + INITIAL = 0, + MULTISTATUS, + RESPONSE, + PROPSTAT, PROP, LOCK_DISCOVERY, ACTIVE_LOCK, @@ -55,13 +55,9 @@ typedef enum lock_state_e { DEPTH, TIMEOUT, LOCK_TOKEN, - COMMENT -} lock_state_e; - -typedef struct lock_prop_info_t { - const char *data; - apr_size_t len; -} lock_prop_info_t; + OWNER, + HREF +}; typedef struct lock_info_t { apr_pool_t *pool; @@ -75,249 +71,119 @@ typedef struct lock_info_t { svn_boolean_t read_headers; - /* Our HTTP status code and reason. */ - int status_code; - const char *reason; - - /* The currently collected value as we build it up */ - const char *tmp; - apr_size_t tmp_len; + svn_ra_serf__handler_t *handler; + + /* The expat handler. We wrap this to do a bit more work. */ + svn_ra_serf__response_handler_t inner_handler; + void *inner_baton; - /* are we done? */ - svn_boolean_t done; } lock_info_t; - -static lock_prop_info_t* -push_state(svn_ra_serf__xml_parser_t *parser, - lock_info_t *lock_ctx, - lock_state_e state) -{ - svn_ra_serf__xml_push_state(parser, state); - switch (state) - { - case LOCK_TYPE: - case LOCK_SCOPE: - case DEPTH: - case TIMEOUT: - case LOCK_TOKEN: - case COMMENT: - parser->state->private = apr_pcalloc(parser->state->pool, - sizeof(lock_prop_info_t)); - break; - default: - break; - } +#define D_ "DAV:" +#define S_ SVN_XML_NAMESPACE +static const svn_ra_serf__xml_transition_t locks_ttable[] = { + /* The INITIAL state can transition into D:prop (LOCK) or + to D:multistatus (PROPFIND) */ + { INITIAL, D_, "prop", PROP, + FALSE, { NULL }, FALSE, FALSE }, + { INITIAL, D_, "multistatus", MULTISTATUS, + FALSE, { NULL }, FALSE, FALSE }, - return parser->state->private; -} + { MULTISTATUS, D_, "response", RESPONSE, + FALSE, { NULL }, FALSE, FALSE }, -/* - * Expat callback invoked on a start element tag for a PROPFIND response. - */ -static svn_error_t * -start_lock(svn_ra_serf__xml_parser_t *parser, - void *userData, - svn_ra_serf__dav_props_t name, - const char **attrs) -{ - lock_info_t *ctx = userData; - lock_state_e state; + { RESPONSE, D_, "propstat", PROPSTAT, + FALSE, { NULL }, FALSE, FALSE }, - state = parser->state->current_state; + { PROPSTAT, D_, "prop", PROP, + FALSE, { NULL }, FALSE, FALSE }, - if (state == NONE && strcmp(name.name, "prop") == 0) - { - svn_ra_serf__xml_push_state(parser, PROP); - } - else if (state == PROP && - strcmp(name.name, "lockdiscovery") == 0) - { - push_state(parser, ctx, LOCK_DISCOVERY); - } - else if (state == LOCK_DISCOVERY && - strcmp(name.name, "activelock") == 0) - { - push_state(parser, ctx, ACTIVE_LOCK); - } - else if (state == ACTIVE_LOCK) - { - if (strcmp(name.name, "locktype") == 0) - { - push_state(parser, ctx, LOCK_TYPE); - } - else if (strcmp(name.name, "lockscope") == 0) - { - push_state(parser, ctx, LOCK_SCOPE); - } - else if (strcmp(name.name, "depth") == 0) - { - push_state(parser, ctx, DEPTH); - } - else if (strcmp(name.name, "timeout") == 0) - { - push_state(parser, ctx, TIMEOUT); - } - else if (strcmp(name.name, "locktoken") == 0) - { - push_state(parser, ctx, LOCK_TOKEN); - } - else if (strcmp(name.name, "owner") == 0) - { - push_state(parser, ctx, COMMENT); - } - } - else if (state == LOCK_TYPE) - { - if (strcmp(name.name, "write") == 0) - { - /* Do nothing. */ - } - else - { - SVN_ERR_MALFUNCTION(); - } - } - else if (state == LOCK_SCOPE) - { - if (strcmp(name.name, "exclusive") == 0) - { - /* Do nothing. */ - } - else - { - SVN_ERR_MALFUNCTION(); - } - } + { PROP, D_, "lockdiscovery", LOCK_DISCOVERY, + FALSE, { NULL }, FALSE, FALSE }, - return SVN_NO_ERROR; -} + { LOCK_DISCOVERY, D_, "activelock", ACTIVE_LOCK, + FALSE, { NULL }, FALSE, FALSE }, -/* - * Expat callback invoked on an end element tag for a PROPFIND response. - */ +#if 0 + /* ### we don't really need to parse locktype/lockscope. we know what + ### the values are going to be. we *could* validate that the only + ### possible children are D:write and D:exclusive. we'd need to + ### modify the state transition to tell us about all children + ### (ie. maybe support "*" for the name) and then validate. but it + ### just isn't important to validate, so disable this for now... */ + + { ACTIVE_LOCK, D_, "locktype", LOCK_TYPE, + FALSE, { NULL }, FALSE, FALSE }, + + { LOCK_TYPE, D_, "write", WRITE, + FALSE, { NULL }, FALSE, TRUE }, + + { ACTIVE_LOCK, D_, "lockscope", LOCK_SCOPE, + FALSE, { NULL }, FALSE, FALSE }, + + { LOCK_SCOPE, D_, "exclusive", EXCLUSIVE, + FALSE, { NULL }, FALSE, TRUE }, +#endif /* 0 */ + + { ACTIVE_LOCK, D_, "timeout", TIMEOUT, + TRUE, { NULL }, FALSE, TRUE }, + + { ACTIVE_LOCK, D_, "locktoken", LOCK_TOKEN, + FALSE, { NULL }, FALSE, FALSE }, + + { LOCK_TOKEN, D_, "href", HREF, + TRUE, { NULL }, FALSE, TRUE }, + + { ACTIVE_LOCK, D_, "owner", OWNER, + TRUE, { NULL }, FALSE, TRUE }, + + /* ACTIVE_LOCK has a D:depth child, but we can ignore that. */ + + { 0 } +}; + + +/* Conforms to svn_ra_serf__xml_closed_t */ static svn_error_t * -end_lock(svn_ra_serf__xml_parser_t *parser, - void *userData, - svn_ra_serf__dav_props_t name) +locks_closed(svn_ra_serf__xml_estate_t *xes, + void *baton, + int leaving_state, + const svn_string_t *cdata, + apr_hash_t *attrs, + apr_pool_t *scratch_pool) { - lock_info_t *ctx = userData; - lock_state_e state; - - state = parser->state->current_state; + lock_info_t *lock_ctx = baton; - if (state == PROP && - strcmp(name.name, "prop") == 0) - { - svn_ra_serf__xml_pop_state(parser); - } - else if (state == LOCK_DISCOVERY && - strcmp(name.name, "lockdiscovery") == 0) + if (leaving_state == TIMEOUT) { - svn_ra_serf__xml_pop_state(parser); - } - else if (state == ACTIVE_LOCK && - strcmp(name.name, "activelock") == 0) - { - svn_ra_serf__xml_pop_state(parser); - } - else if (state == LOCK_TYPE && - strcmp(name.name, "locktype") == 0) - { - svn_ra_serf__xml_pop_state(parser); - } - else if (state == LOCK_SCOPE && - strcmp(name.name, "lockscope") == 0) - { - svn_ra_serf__xml_pop_state(parser); - } - else if (state == DEPTH && - strcmp(name.name, "depth") == 0) - { - svn_ra_serf__xml_pop_state(parser); - } - else if (state == TIMEOUT && - strcmp(name.name, "timeout") == 0) - { - lock_prop_info_t *info = parser->state->private; - - if (strcmp(info->data, "Infinite") == 0) - { - ctx->lock->expiration_date = 0; - } + if (strcmp(cdata->data, "Infinite") == 0) + lock_ctx->lock->expiration_date = 0; else - { - SVN_ERR(svn_time_from_cstring(&ctx->lock->creation_date, - info->data, ctx->pool)); - } - svn_ra_serf__xml_pop_state(parser); + SVN_ERR(svn_time_from_cstring(&lock_ctx->lock->creation_date, + cdata->data, lock_ctx->pool)); } - else if (state == LOCK_TOKEN && - strcmp(name.name, "locktoken") == 0) + else if (leaving_state == HREF) { - lock_prop_info_t *info = parser->state->private; - - if (!ctx->lock->token && info->len) + if (cdata->len) { - apr_collapse_spaces((char*)info->data, info->data); - ctx->lock->token = apr_pstrndup(ctx->pool, info->data, info->len); + char *buf = apr_pstrmemdup(lock_ctx->pool, cdata->data, cdata->len); + + apr_collapse_spaces(buf, buf); + lock_ctx->lock->token = buf; } - /* We don't actually need the lock token. */ - svn_ra_serf__xml_pop_state(parser); } - else if (state == COMMENT && - strcmp(name.name, "owner") == 0) + else if (leaving_state == OWNER) { - lock_prop_info_t *info = parser->state->private; - - if (info->len) + if (cdata->len) { - ctx->lock->comment = apr_pstrndup(ctx->pool, info->data, info->len); + lock_ctx->lock->comment = apr_pstrmemdup(lock_ctx->pool, + cdata->data, cdata->len); } - svn_ra_serf__xml_pop_state(parser); } return SVN_NO_ERROR; } -static svn_error_t * -cdata_lock(svn_ra_serf__xml_parser_t *parser, - void *userData, - const char *data, - apr_size_t len) -{ - lock_info_t *lock_ctx = userData; - lock_state_e state; - lock_prop_info_t *info; - - UNUSED_CTX(lock_ctx); - - state = parser->state->current_state; - info = parser->state->private; - - switch (state) - { - case LOCK_TYPE: - case LOCK_SCOPE: - case DEPTH: - case TIMEOUT: - case LOCK_TOKEN: - case COMMENT: - svn_ra_serf__expand_string(&info->data, &info->len, - data, len, parser->state->pool); - break; - default: - break; - } - - return SVN_NO_ERROR; -} - -static const svn_ra_serf__dav_props_t lock_props[] = -{ - { "DAV:", "lockdiscovery" }, - { NULL } -}; static svn_error_t * set_lock_headers(serf_bucket_t *headers, @@ -341,6 +207,39 @@ set_lock_headers(serf_bucket_t *headers, return APR_SUCCESS; } + +/* Register an error within the session. If something is already there, + then it will take precedence. */ +static svn_error_t * +determine_error(svn_ra_serf__handler_t *handler, + svn_error_t *err) +{ + { + apr_status_t errcode; + + if (handler->sline.code == 423) + errcode = SVN_ERR_FS_PATH_ALREADY_LOCKED; + else if (handler->sline.code == 403) + errcode = SVN_ERR_RA_DAV_FORBIDDEN; + else + return err; + + /* Client-side or server-side error already. Return it. */ + if (err != NULL) + return err; + + /* The server did not send us a detailed human-readable error. + Provide a generic error. */ + err = svn_error_createf(errcode, NULL, + _("Lock request failed: %d %s"), + handler->sline.code, + handler->sline.reason); + } + + return err; +} + + /* Implements svn_ra_serf__response_handler_t */ static svn_error_t * handle_lock(serf_request_t *request, @@ -348,43 +247,25 @@ handle_lock(serf_request_t *request, void *handler_baton, apr_pool_t *pool) { - svn_ra_serf__xml_parser_t *xml_ctx = handler_baton; - lock_info_t *ctx = xml_ctx->user_data; - svn_error_t *err; + lock_info_t *ctx = handler_baton; + + /* 403 (Forbidden) when a lock doesn't exist. + 423 (Locked) when a lock already exists. */ + if (ctx->handler->sline.code == 403 + || ctx->handler->sline.code == 423) + { + /* Go look in the body for a server-provided error. This will + reset flags for the core handler to Do The Right Thing. We + won't be back to this handler again. */ + return svn_error_trace(svn_ra_serf__expect_empty_body( + request, response, ctx->handler, pool)); + } if (ctx->read_headers == FALSE) { serf_bucket_t *headers; const char *val; - serf_status_line sl; - apr_status_t status; - - status = serf_bucket_response_status(response, &sl); - if (SERF_BUCKET_READ_ERROR(status)) - { - return svn_error_wrap_apr(status, NULL); - } - - ctx->status_code = sl.code; - ctx->reason = sl.reason; - - /* 423 == Locked */ - if (sl.code == 423) - { - /* Older servers may not give a descriptive error, so we'll - make one of our own if we can't find one in the response. */ - err = svn_ra_serf__handle_server_error(request, response, pool); - if (!err) - { - err = svn_error_createf(SVN_ERR_FS_PATH_ALREADY_LOCKED, - NULL, - _("Lock request failed: %d %s"), - ctx->status_code, ctx->reason); - } - return err; - } - headers = serf_bucket_response_get_headers(response); val = serf_bucket_headers_get(headers, SVN_DAV_LOCK_OWNER_HEADER); @@ -403,25 +284,7 @@ handle_lock(serf_request_t *request, ctx->read_headers = TRUE; } - /* Forbidden when a lock doesn't exist. */ - if (ctx->status_code == 403) - { - /* If we get an "unexpected EOF" error, we'll wrap it with - generic request failure error. */ - err = svn_ra_serf__handle_discard_body(request, response, NULL, pool); - if (err && APR_STATUS_IS_EOF(err->apr_err)) - { - ctx->done = TRUE; - err = svn_error_createf(SVN_ERR_RA_DAV_FORBIDDEN, - err, - _("Lock request failed: %d %s"), - ctx->status_code, ctx->reason); - } - return err; - } - - return svn_ra_serf__handle_xml_parser(request, response, - handler_baton, pool); + return ctx->inner_handler(request, response, ctx->inner_baton, pool); } /* Implements svn_ra_serf__request_body_delegate_t */ @@ -453,7 +316,7 @@ setup_getlock_headers(serf_bucket_t *hea void *baton, apr_pool_t *pool) { - serf_bucket_headers_set(headers, "Depth", "0"); + serf_bucket_headers_setn(headers, "Depth", "0"); return SVN_NO_ERROR; } @@ -503,11 +366,10 @@ svn_ra_serf__get_lock(svn_ra_session_t * { svn_ra_serf__session_t *session = ra_session->priv; svn_ra_serf__handler_t *handler; - svn_ra_serf__xml_parser_t *parser_ctx; + svn_ra_serf__xml_context_t *xmlctx; lock_info_t *lock_ctx; const char *req_url; svn_error_t *err; - int status_code; req_url = svn_path_url_add_component2(session->session_url.path, path, pool); @@ -516,9 +378,12 @@ svn_ra_serf__get_lock(svn_ra_session_t * lock_ctx->pool = pool; lock_ctx->path = req_url; lock_ctx->lock = svn_lock_create(pool); - lock_ctx->lock->path = path; + lock_ctx->lock->path = apr_pstrdup(pool, path); /* be sure */ - handler = apr_pcalloc(pool, sizeof(*handler)); + xmlctx = svn_ra_serf__xml_context_create(locks_ttable, + NULL, locks_closed, lock_ctx, + pool); + handler = svn_ra_serf__create_expat_handler(xmlctx, pool); handler->method = "PROPFIND"; handler->path = req_url; @@ -526,29 +391,23 @@ svn_ra_serf__get_lock(svn_ra_session_t * handler->conn = session->conns[0]; handler->session = session; - parser_ctx = apr_pcalloc(pool, sizeof(*parser_ctx)); - - parser_ctx->pool = pool; - parser_ctx->user_data = lock_ctx; - parser_ctx->start = start_lock; - parser_ctx->end = end_lock; - parser_ctx->cdata = cdata_lock; - parser_ctx->done = &lock_ctx->done; - parser_ctx->status_code = &status_code; - handler->body_delegate = create_getlock_body; handler->body_delegate_baton = lock_ctx; handler->header_delegate = setup_getlock_headers; handler->header_delegate_baton = lock_ctx; + lock_ctx->inner_handler = handler->response_handler; + lock_ctx->inner_baton = handler->response_baton; handler->response_handler = handle_lock; - handler->response_baton = parser_ctx; + handler->response_baton = lock_ctx; - svn_ra_serf__request_create(handler); - err = svn_ra_serf__context_run_wait(&lock_ctx->done, session, pool); + lock_ctx->handler = handler; - if (status_code == 404) + err = svn_ra_serf__context_run_one(handler, pool); + err = determine_error(handler, err); + + if (handler->sline.code == 404) { return svn_error_create(SVN_ERR_RA_ILLEGAL_URL, err, _("Malformed URL for repository")); @@ -581,13 +440,16 @@ svn_ra_serf__lock(svn_ra_session_t *ra_s iterpool = svn_pool_create(scratch_pool); /* ### TODO for issue 2263: Send all the locks over the wire at once. This - loop is just a temporary shim. */ + ### loop is just a temporary shim. + ### an alternative, which is backwards-compat with all servers is to + ### pipeline these requests. ie. stop using run_wait/run_one. */ + for (hi = apr_hash_first(scratch_pool, path_revs); hi; hi = apr_hash_next(hi)) { svn_ra_serf__handler_t *handler; - svn_ra_serf__xml_parser_t *parser_ctx; + svn_ra_serf__xml_context_t *xmlctx; const char *req_url; lock_info_t *lock_ctx; svn_error_t *err; @@ -608,7 +470,10 @@ svn_ra_serf__lock(svn_ra_session_t *ra_s req_url = svn_path_url_add_component2(session->session_url.path, lock_ctx->path, iterpool); - handler = apr_pcalloc(iterpool, sizeof(*handler)); + xmlctx = svn_ra_serf__xml_context_create(locks_ttable, + NULL, locks_closed, lock_ctx, + iterpool); + handler = svn_ra_serf__create_expat_handler(xmlctx, iterpool); handler->method = "LOCK"; handler->path = req_url; @@ -616,26 +481,21 @@ svn_ra_serf__lock(svn_ra_session_t *ra_s handler->conn = session->conns[0]; handler->session = session; - parser_ctx = apr_pcalloc(iterpool, sizeof(*parser_ctx)); - - parser_ctx->pool = iterpool; - parser_ctx->user_data = lock_ctx; - parser_ctx->start = start_lock; - parser_ctx->end = end_lock; - parser_ctx->cdata = cdata_lock; - parser_ctx->done = &lock_ctx->done; - handler->header_delegate = set_lock_headers; handler->header_delegate_baton = lock_ctx; handler->body_delegate = create_lock_body; handler->body_delegate_baton = lock_ctx; + lock_ctx->inner_handler = handler->response_handler; + lock_ctx->inner_baton = handler->response_baton; handler->response_handler = handle_lock; - handler->response_baton = parser_ctx; + handler->response_baton = lock_ctx; + + lock_ctx->handler = handler; - svn_ra_serf__request_create(handler); - err = svn_ra_serf__context_run_wait(&lock_ctx->done, session, iterpool); + err = svn_ra_serf__context_run_one(handler, iterpool); + err = determine_error(handler, err); if (lock_func) new_err = lock_func(lock_baton, lock_ctx->path, TRUE, lock_ctx->lock, @@ -687,13 +547,15 @@ svn_ra_serf__unlock(svn_ra_session_t *ra iterpool = svn_pool_create(scratch_pool); /* ### TODO for issue 2263: Send all the locks over the wire at once. This - loop is just a temporary shim. */ + ### loop is just a temporary shim. + ### an alternative, which is backwards-compat with all servers is to + ### pipeline these requests. ie. stop using run_wait/run_one. */ + for (hi = apr_hash_first(scratch_pool, path_tokens); hi; hi = apr_hash_next(hi)) { svn_ra_serf__handler_t *handler; - svn_ra_serf__simple_request_context_t *ctx; const char *req_url, *path, *token; svn_lock_t *existing_lock = NULL; struct unlock_context_t unlock_ctx; @@ -703,9 +565,6 @@ svn_ra_serf__unlock(svn_ra_session_t *ra svn_pool_clear(iterpool); - ctx = apr_pcalloc(iterpool, sizeof(*ctx)); - ctx->pool = iterpool; - path = svn__apr_hash_index_key(hi); token = svn__apr_hash_index_val(hi); @@ -747,6 +606,7 @@ svn_ra_serf__unlock(svn_ra_session_t *ra handler = apr_pcalloc(iterpool, sizeof(*handler)); + handler->handler_pool = iterpool; handler->method = "UNLOCK"; handler->path = req_url; handler->conn = session->conns[0]; @@ -755,13 +615,12 @@ svn_ra_serf__unlock(svn_ra_session_t *ra handler->header_delegate = set_unlock_headers; handler->header_delegate_baton = &unlock_ctx; - handler->response_handler = svn_ra_serf__handle_status_only; - handler->response_baton = ctx; + handler->response_handler = svn_ra_serf__expect_empty_body; + handler->response_baton = handler; - svn_ra_serf__request_create(handler); - SVN_ERR(svn_ra_serf__context_run_wait(&ctx->done, session, iterpool)); + SVN_ERR(svn_ra_serf__context_run_one(handler, iterpool)); - switch (ctx->status) + switch (handler->sline.code) { case 204: break; /* OK */ @@ -769,12 +628,14 @@ svn_ra_serf__unlock(svn_ra_session_t *ra /* Api users expect this specific error code to detect failures */ err = svn_error_createf(SVN_ERR_FS_LOCK_OWNER_MISMATCH, NULL, _("Unlock request failed: %d %s"), - ctx->status, ctx->reason); + handler->sline.code, + handler->sline.reason); break; default: err = svn_error_createf(SVN_ERR_RA_DAV_REQUEST_FAILED, NULL, _("Unlock request failed: %d %s"), - ctx->status, ctx->reason); + handler->sline.code, + handler->sline.reason); } if (lock_func) Modified: subversion/branches/fix-rdump-editor/subversion/libsvn_ra_serf/log.c URL: http://svn.apache.org/viewvc/subversion/branches/fix-rdump-editor/subversion/libsvn_ra_serf/log.c?rev=1339349&r1=1339348&r2=1339349&view=diff ============================================================================== --- subversion/branches/fix-rdump-editor/subversion/libsvn_ra_serf/log.c (original) +++ subversion/branches/fix-rdump-editor/subversion/libsvn_ra_serf/log.c Wed May 16 20:32:43 2012 @@ -24,9 +24,6 @@ #include - -#include - #include #include "svn_pools.h" @@ -39,6 +36,8 @@ #include "svn_props.h" #include "private/svn_dav_protocol.h" +#include "private/svn_string_private.h" +#include "private/svn_subr_private.h" #include "svn_private_config.h" #include "ra_serf.h" @@ -48,8 +47,8 @@ /* * This enum represents the current state of our XML parsing for a REPORT. */ -typedef enum log_state_e { - NONE = 0, +enum { + INITIAL = 0, REPORT, ITEM, VERSION, @@ -63,27 +62,7 @@ typedef enum log_state_e { DELETED_PATH, MODIFIED_PATH, SUBTRACTIVE_MERGE -} log_state_e; - -typedef struct log_info_t { - apr_pool_t *pool; - - /* The currently collected value as we build it up, and its wire - * encoding (if any). - */ - const char *tmp; - apr_size_t tmp_len; - const char *tmp_encoding; - - /* Temporary change path - ultimately inserted into changed_paths hash. */ - svn_log_changed_path2_t *tmp_path; - - /* Log information */ - svn_log_entry_t *log_entry; - - /* Place to hold revprop name. */ - const char *revprop_name; -} log_info_t; +}; typedef struct log_context_t { apr_pool_t *pool; @@ -100,9 +79,11 @@ typedef struct log_context_t { int nest_level; /* used to track mergeinfo nesting levels */ int count; /* only incremented when nest_level == 0 */ - /* are we done? */ - svn_boolean_t done; - int status_code; + /* Collect information for storage into a log entry. Most of the entry + members are collected by individual states. revprops and paths are + N datapoints per entry. */ + apr_hash_t *collect_revprops; + apr_hash_t *collect_paths; /* log receiver function and baton */ svn_log_entry_receiver_t receiver; @@ -114,407 +95,312 @@ typedef struct log_context_t { svn_boolean_t want_message; } log_context_t; - -static log_info_t * -push_state(svn_ra_serf__xml_parser_t *parser, - log_context_t *log_ctx, - log_state_e state, - const char **attrs) -{ - svn_ra_serf__xml_push_state(parser, state); +#define D_ "DAV:" +#define S_ SVN_XML_NAMESPACE +static const svn_ra_serf__xml_transition_t log_ttable[] = { + { INITIAL, S_, "log-report", REPORT, + FALSE, { NULL }, FALSE, FALSE }, - if (state == ITEM) - { - log_info_t *info; - apr_pool_t *info_pool = svn_pool_create(parser->state->pool); + /* Note that we have an opener here. We need to construct a new LOG_ENTRY + to record multiple paths. */ + { REPORT, S_, "log-item", ITEM, + FALSE, { NULL }, TRUE, TRUE }, - info = apr_pcalloc(info_pool, sizeof(*info)); - info->pool = info_pool; - info->log_entry = svn_log_entry_create(info_pool); + { ITEM, D_, SVN_DAV__VERSION_NAME, VERSION, + TRUE, { NULL }, FALSE, TRUE }, - info->log_entry->revision = SVN_INVALID_REVNUM; + { ITEM, D_, "creator-displayname", CREATOR, + TRUE, { "?encoding", NULL }, FALSE, TRUE }, - parser->state->private = info; - } + { ITEM, S_, "date", DATE, + TRUE, { "?encoding", NULL }, FALSE, TRUE }, - if (state == ADDED_PATH || state == REPLACED_PATH || - state == DELETED_PATH || state == MODIFIED_PATH) - { - log_info_t *info = parser->state->private; + { ITEM, D_, "comment", COMMENT, + TRUE, { "?encoding", NULL }, FALSE, TRUE }, - if (!info->log_entry->changed_paths2) - { - info->log_entry->changed_paths2 = apr_hash_make(info->pool); - info->log_entry->changed_paths = info->log_entry->changed_paths2; - } + { ITEM, S_, "revprop", REVPROP, + TRUE, { "name", "?encoding", NULL }, FALSE, TRUE }, - info->tmp_path = svn_log_changed_path2_create(info->pool); - info->tmp_path->copyfrom_rev = SVN_INVALID_REVNUM; - } + { ITEM, S_, "has-children", HAS_CHILDREN, + FALSE, { NULL }, FALSE, TRUE }, - if (state == CREATOR || state == DATE || state == COMMENT - || state == REVPROP) - { - log_info_t *info = parser->state->private; + { ITEM, S_, "subtractive-merge", SUBTRACTIVE_MERGE, + FALSE, { NULL }, FALSE, TRUE }, - info->tmp_encoding = svn_xml_get_attr_value("encoding", attrs); - if (info->tmp_encoding) - info->tmp_encoding = apr_pstrdup(info->pool, info->tmp_encoding); + { ITEM, S_, "added-path", ADDED_PATH, + TRUE, { "?node-kind", "?text-mods", "?prop-mods", + "?copyfrom-path", "?copyfrom-rev", NULL }, FALSE, TRUE }, - if (!info->log_entry->revprops) - { - info->log_entry->revprops = apr_hash_make(info->pool); - } - } + { ITEM, S_, "replaced-path", REPLACED_PATH, + TRUE, { "?node-kind", "?text-mods", "?prop-mods", + "?copyfrom-path", "?copyfrom-rev", NULL }, FALSE, TRUE }, - return parser->state->private; -} + { ITEM, S_, "deleted-path", DELETED_PATH, + TRUE, { "?node-kind", "?text-mods", "?prop-mods", NULL }, FALSE, TRUE }, -/* Helper function to parse the common arguments availabe in ATTRS into CHANGE. */ -static svn_error_t * -read_changed_path_attributes(svn_log_changed_path2_t *change, const char **attrs) -{ - /* All these arguments are optional. The *_from_word() functions can handle - them for us */ + { ITEM, S_, "modified-path", MODIFIED_PATH, + TRUE, { "?node-kind", "?text-mods", "?prop-mods", NULL }, FALSE, TRUE }, - change->node_kind = svn_node_kind_from_word( - svn_xml_get_attr_value("node-kind", attrs)); - change->text_modified = svn_tristate__from_word( - svn_xml_get_attr_value("text-mods", attrs)); - change->props_modified = svn_tristate__from_word( - svn_xml_get_attr_value("prop-mods", attrs)); + { 0 } +}; - return SVN_NO_ERROR; -} + +/* Store CDATA into REVPROPS, associated with PROPNAME. If ENCODING is not + NULL, then it must base "base64" and CDATA will be decoded first. + NOTE: PROPNAME must live longer than REVPROPS. */ static svn_error_t * -start_log(svn_ra_serf__xml_parser_t *parser, - void *userData, - svn_ra_serf__dav_props_t name, - const char **attrs) +collect_revprop(apr_hash_t *revprops, + const char *propname, + const svn_string_t *cdata, + const char *encoding) { - log_context_t *log_ctx = userData; - log_state_e state; + apr_pool_t *result_pool = apr_hash_pool_get(revprops); + const svn_string_t *decoded; - state = parser->state->current_state; - - if (state == NONE && - strcmp(name.name, "log-report") == 0) - { - push_state(parser, log_ctx, REPORT, attrs); - } - else if (state == REPORT && - strcmp(name.name, "log-item") == 0) - { - push_state(parser, log_ctx, ITEM, attrs); - } - else if (state == ITEM) + if (encoding) { - log_info_t *info; - - if (strcmp(name.name, SVN_DAV__VERSION_NAME) == 0) - { - push_state(parser, log_ctx, VERSION, attrs); - } - else if (strcmp(name.name, "creator-displayname") == 0) - { - info = push_state(parser, log_ctx, CREATOR, attrs); - } - else if (strcmp(name.name, "date") == 0) - { - info = push_state(parser, log_ctx, DATE, attrs); - } - else if (strcmp(name.name, "comment") == 0) - { - info = push_state(parser, log_ctx, COMMENT, attrs); - } - else if (strcmp(name.name, "revprop") == 0) - { - const char *revprop_name = - svn_xml_get_attr_value("name", attrs); - if (revprop_name == NULL) - return svn_error_createf(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL, - _("Missing name attr in revprop element")); - info = push_state(parser, log_ctx, REVPROP, attrs); - info->revprop_name = apr_pstrdup(info->pool, revprop_name); - } - else if (strcmp(name.name, "has-children") == 0) - { - push_state(parser, log_ctx, HAS_CHILDREN, attrs); - } - else if (strcmp(name.name, "subtractive-merge") == 0) + /* Check for a known encoding type. This is easy -- there's + only one. */ + if (strcmp(encoding, "base64") != 0) { - push_state(parser, log_ctx, SUBTRACTIVE_MERGE, attrs); + return svn_error_createf(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL, + _("Unsupported encoding '%s'"), + encoding); } - else if (strcmp(name.name, "added-path") == 0) - { - const char *copy_path, *copy_rev_str; - - info = push_state(parser, log_ctx, ADDED_PATH, attrs); - info->tmp_path->action = 'A'; - - copy_path = svn_xml_get_attr_value("copyfrom-path", attrs); - copy_rev_str = svn_xml_get_attr_value("copyfrom-rev", attrs); - if (copy_path && copy_rev_str) - { - svn_revnum_t copy_rev; - - copy_rev = SVN_STR_TO_REV(copy_rev_str); - if (SVN_IS_VALID_REVNUM(copy_rev)) - { - info->tmp_path->copyfrom_path = apr_pstrdup(info->pool, - copy_path); - info->tmp_path->copyfrom_rev = copy_rev; - } - } - SVN_ERR(read_changed_path_attributes(info->tmp_path, attrs)); - } - else if (strcmp(name.name, "replaced-path") == 0) - { - const char *copy_path, *copy_rev_str; + decoded = svn_base64_decode_string(cdata, result_pool); + } + else + { + decoded = svn_string_dup(cdata, result_pool); + } - info = push_state(parser, log_ctx, REPLACED_PATH, attrs); - info->tmp_path->action = 'R'; + /* Caller has ensured PROPNAME has sufficient lifetime. */ + apr_hash_set(revprops, propname, APR_HASH_KEY_STRING, decoded); - copy_path = svn_xml_get_attr_value("copyfrom-path", attrs); - copy_rev_str = svn_xml_get_attr_value("copyfrom-rev", attrs); - if (copy_path && copy_rev_str) - { - svn_revnum_t copy_rev; + return SVN_NO_ERROR; +} - copy_rev = SVN_STR_TO_REV(copy_rev_str); - if (SVN_IS_VALID_REVNUM(copy_rev)) - { - info->tmp_path->copyfrom_path = apr_pstrdup(info->pool, - copy_path); - info->tmp_path->copyfrom_rev = copy_rev; - } - } - SVN_ERR(read_changed_path_attributes(info->tmp_path, attrs)); +/* Record ACTION on the path in CDATA into PATHS. Other properties about + the action are pulled from ATTRS. */ +static svn_error_t * +collect_path(apr_hash_t *paths, + char action, + const svn_string_t *cdata, + apr_hash_t *attrs) +{ + apr_pool_t *result_pool = apr_hash_pool_get(paths); + svn_log_changed_path2_t *lcp; + const char *copyfrom_path; + const char *copyfrom_rev; + const char *path; + + lcp = svn_log_changed_path2_create(result_pool); + lcp->action = action; + lcp->copyfrom_rev = SVN_INVALID_REVNUM; + + /* COPYFROM_* are only recorded for ADDED_PATH and REPLACED_PATH. */ + copyfrom_path = apr_hash_get(attrs, "copyfrom-path", APR_HASH_KEY_STRING); + copyfrom_rev = apr_hash_get(attrs, "copyfrom-rev", APR_HASH_KEY_STRING); + if (copyfrom_path && copyfrom_rev) + { + svn_revnum_t rev = SVN_STR_TO_REV(copyfrom_rev); + + if (SVN_IS_VALID_REVNUM(rev)) + { + lcp->copyfrom_path = apr_pstrdup(result_pool, copyfrom_path); + lcp->copyfrom_rev = rev; } - else if (strcmp(name.name, "deleted-path") == 0) - { - info = push_state(parser, log_ctx, DELETED_PATH, attrs); - info->tmp_path->action = 'D'; + } - SVN_ERR(read_changed_path_attributes(info->tmp_path, attrs)); - } - else if (strcmp(name.name, "modified-path") == 0) - { - info = push_state(parser, log_ctx, MODIFIED_PATH, attrs); - info->tmp_path->action = 'M'; + lcp->node_kind = svn_node_kind_from_word(apr_hash_get( + attrs, "node-kind", + APR_HASH_KEY_STRING)); + lcp->text_modified = svn_tristate__from_word(apr_hash_get( + attrs, "text-mods", + APR_HASH_KEY_STRING)); + lcp->props_modified = svn_tristate__from_word(apr_hash_get( + attrs, "prop-mods", + APR_HASH_KEY_STRING)); - SVN_ERR(read_changed_path_attributes(info->tmp_path, attrs)); - } - } + path = apr_pstrmemdup(result_pool, cdata->data, cdata->len); + apr_hash_set(paths, path, APR_HASH_KEY_STRING, lcp); return SVN_NO_ERROR; } -/* - * Set *DECODED_CDATA to a copy of current CDATA being tracked in INFO, - * decoded as necessary, and allocated from INFO->pool.. - */ + +/* Conforms to svn_ra_serf__xml_opened_t */ static svn_error_t * -maybe_decode_log_cdata(const svn_string_t **decoded_cdata, - log_info_t *info) +log_opened(svn_ra_serf__xml_estate_t *xes, + void *baton, + int entered_state, + apr_pool_t *scratch_pool) { - if (info->tmp_encoding) - { - svn_string_t in; - in.data = info->tmp; - in.len = info->tmp_len; + log_context_t *log_ctx = baton; + apr_pool_t *state_pool = svn_ra_serf__xml_state_pool(xes); - /* Check for a known encoding type. This is easy -- there's - only one. */ - if (strcmp(info->tmp_encoding, "base64") != 0) - { - return svn_error_createf(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL, - _("Unsupported encoding '%s'"), - info->tmp_encoding); - } + SVN_ERR_ASSERT(entered_state == ITEM); + + log_ctx->collect_revprops = apr_hash_make(state_pool); + log_ctx->collect_paths = apr_hash_make(state_pool); - *decoded_cdata = svn_base64_decode_string(&in, info->pool); - } - else - { - *decoded_cdata = svn_string_ncreate(info->tmp, info->tmp_len, - info->pool); - } return SVN_NO_ERROR; } + +/* Conforms to svn_ra_serf__xml_closed_t */ static svn_error_t * -end_log(svn_ra_serf__xml_parser_t *parser, - void *userData, - svn_ra_serf__dav_props_t name) +log_closed(svn_ra_serf__xml_estate_t *xes, + void *baton, + int leaving_state, + const svn_string_t *cdata, + apr_hash_t *attrs, + apr_pool_t *scratch_pool) { - log_context_t *log_ctx = userData; - log_state_e state; - log_info_t *info; - - state = parser->state->current_state; - info = parser->state->private; + log_context_t *log_ctx = baton; - if (state == REPORT && - strcmp(name.name, "log-report") == 0) - { - svn_ra_serf__xml_pop_state(parser); - } - else if (state == ITEM && - strcmp(name.name, "log-item") == 0) + if (leaving_state == ITEM) { + svn_log_entry_t *log_entry; + const char *rev_str; + if (log_ctx->limit && (log_ctx->nest_level == 0) && (++log_ctx->count > log_ctx->limit)) { return SVN_NO_ERROR; } + log_entry = svn_log_entry_create(scratch_pool); + + /* Pick up the paths from the context. These have the same lifetime + as this state. That is long enough for us to pass the paths to + the receiver callback. */ + if (apr_hash_count(log_ctx->collect_paths) > 0) + { + log_entry->changed_paths = log_ctx->collect_paths; + log_entry->changed_paths2 = log_ctx->collect_paths; + } + + /* ... and same story for the collected revprops. */ + log_entry->revprops = log_ctx->collect_revprops; + + log_entry->has_children = svn_hash__get_bool(attrs, + "has-children", + FALSE); + log_entry->subtractive_merge = svn_hash__get_bool(attrs, + "subtractive-merge", + FALSE); + + rev_str = apr_hash_get(attrs, "revision", APR_HASH_KEY_STRING); + if (rev_str) + log_entry->revision = SVN_STR_TO_REV(rev_str); + else + log_entry->revision = SVN_INVALID_REVNUM; + /* Give the info to the reporter */ SVN_ERR(log_ctx->receiver(log_ctx->receiver_baton, - info->log_entry, - info->pool)); + log_entry, + scratch_pool)); - if (info->log_entry->has_children) + if (log_entry->has_children) { log_ctx->nest_level++; } - if (! SVN_IS_VALID_REVNUM(info->log_entry->revision)) + if (! SVN_IS_VALID_REVNUM(log_entry->revision)) { SVN_ERR_ASSERT(log_ctx->nest_level); log_ctx->nest_level--; } - svn_pool_destroy(info->pool); - svn_ra_serf__xml_pop_state(parser); + /* These hash tables are going to be unusable once this state's + pool is destroyed. But let's not leave stale pointers in + structures that have a longer life. */ + log_ctx->collect_revprops = NULL; + log_ctx->collect_paths = NULL; } - else if (state == VERSION && - strcmp(name.name, SVN_DAV__VERSION_NAME) == 0) + else if (leaving_state == VERSION) { - info->log_entry->revision = SVN_STR_TO_REV(info->tmp); - info->tmp_len = 0; - svn_ra_serf__xml_pop_state(parser); + svn_ra_serf__xml_note(xes, ITEM, "revision", cdata->data); } - else if (state == CREATOR && - strcmp(name.name, "creator-displayname") == 0) + else if (leaving_state == CREATOR) { if (log_ctx->want_author) { - const svn_string_t *decoded_cdata; - SVN_ERR(maybe_decode_log_cdata(&decoded_cdata, info)); - apr_hash_set(info->log_entry->revprops, SVN_PROP_REVISION_AUTHOR, - APR_HASH_KEY_STRING, decoded_cdata); + SVN_ERR(collect_revprop(log_ctx->collect_revprops, + SVN_PROP_REVISION_AUTHOR, + cdata, + apr_hash_get(attrs, "encoding", + APR_HASH_KEY_STRING))); } - info->tmp_len = 0; - svn_ra_serf__xml_pop_state(parser); } - else if (state == DATE && - strcmp(name.name, "date") == 0) + else if (leaving_state == DATE) { if (log_ctx->want_date) { - const svn_string_t *decoded_cdata; - SVN_ERR(maybe_decode_log_cdata(&decoded_cdata, info)); - apr_hash_set(info->log_entry->revprops, SVN_PROP_REVISION_DATE, - APR_HASH_KEY_STRING, decoded_cdata); + SVN_ERR(collect_revprop(log_ctx->collect_revprops, + SVN_PROP_REVISION_DATE, + cdata, + apr_hash_get(attrs, "encoding", + APR_HASH_KEY_STRING))); } - info->tmp_len = 0; - svn_ra_serf__xml_pop_state(parser); } - else if (state == COMMENT && - strcmp(name.name, "comment") == 0) + else if (leaving_state == COMMENT) { if (log_ctx->want_message) { - const svn_string_t *decoded_cdata; - SVN_ERR(maybe_decode_log_cdata(&decoded_cdata, info)); - apr_hash_set(info->log_entry->revprops, SVN_PROP_REVISION_LOG, - APR_HASH_KEY_STRING, decoded_cdata); - } - info->tmp_len = 0; - svn_ra_serf__xml_pop_state(parser); - } - else if (state == REVPROP) - { - const svn_string_t *decoded_cdata; - SVN_ERR(maybe_decode_log_cdata(&decoded_cdata, info)); - apr_hash_set(info->log_entry->revprops, info->revprop_name, - APR_HASH_KEY_STRING, decoded_cdata); - info->tmp_len = 0; - svn_ra_serf__xml_pop_state(parser); - } - else if (state == HAS_CHILDREN && - strcmp(name.name, "has-children") == 0) - { - info->log_entry->has_children = TRUE; - svn_ra_serf__xml_pop_state(parser); - } - else if (state == SUBTRACTIVE_MERGE && - strcmp(name.name, "subtractive-merge") == 0) - { - info->log_entry->subtractive_merge = TRUE; - svn_ra_serf__xml_pop_state(parser); - } - else if ((state == ADDED_PATH && - strcmp(name.name, "added-path") == 0) || - (state == DELETED_PATH && - strcmp(name.name, "deleted-path") == 0) || - (state == MODIFIED_PATH && - strcmp(name.name, "modified-path") == 0) || - (state == REPLACED_PATH && - strcmp(name.name, "replaced-path") == 0)) - { - char *path; - - path = apr_pstrmemdup(info->pool, info->tmp, info->tmp_len); - info->tmp_len = 0; - - apr_hash_set(info->log_entry->changed_paths2, path, APR_HASH_KEY_STRING, - info->tmp_path); - svn_ra_serf__xml_pop_state(parser); + SVN_ERR(collect_revprop(log_ctx->collect_revprops, + SVN_PROP_REVISION_LOG, + cdata, + apr_hash_get(attrs, "encoding", + APR_HASH_KEY_STRING))); + } } + else if (leaving_state == REVPROP) + { + apr_pool_t *result_pool = apr_hash_pool_get(log_ctx->collect_revprops); - return SVN_NO_ERROR; -} + SVN_ERR(collect_revprop( + log_ctx->collect_revprops, + apr_pstrdup(result_pool, + apr_hash_get(attrs, "name", APR_HASH_KEY_STRING)), + cdata, + apr_hash_get(attrs, "encoding", APR_HASH_KEY_STRING) + )); + } + else if (leaving_state == HAS_CHILDREN) + { + svn_ra_serf__xml_note(xes, ITEM, "has-children", "yes"); + } + else if (leaving_state == SUBTRACTIVE_MERGE) + { + svn_ra_serf__xml_note(xes, ITEM, "subtractive-merge", "yes"); + } + else + { + char action; -static svn_error_t * -cdata_log(svn_ra_serf__xml_parser_t *parser, - void *userData, - const char *data, - apr_size_t len) -{ - log_context_t *log_ctx = userData; - log_state_e state; - log_info_t *info; - - UNUSED_CTX(log_ctx); - - state = parser->state->current_state; - info = parser->state->private; - - switch (state) - { - case VERSION: - case CREATOR: - case DATE: - case COMMENT: - case REVPROP: - case ADDED_PATH: - case REPLACED_PATH: - case DELETED_PATH: - case MODIFIED_PATH: - svn_ra_serf__expand_string(&info->tmp, &info->tmp_len, - data, len, info->pool); - break; - default: - break; + if (leaving_state == ADDED_PATH) + action = 'A'; + else if (leaving_state == REPLACED_PATH) + action = 'R'; + else if (leaving_state == DELETED_PATH) + action = 'D'; + else + { + SVN_ERR_ASSERT(leaving_state == MODIFIED_PATH); + action = 'M'; + } + + SVN_ERR(collect_path(log_ctx->collect_paths, action, cdata, attrs)); } return SVN_NO_ERROR; } + static svn_error_t * create_log_body(serf_bucket_t **body_bkt, void *baton, @@ -632,11 +518,11 @@ svn_ra_serf__get_log(svn_ra_session_t *r log_context_t *log_ctx; svn_ra_serf__session_t *session = ra_session->priv; svn_ra_serf__handler_t *handler; - svn_ra_serf__xml_parser_t *parser_ctx; + svn_ra_serf__xml_context_t *xmlctx; svn_boolean_t want_custom_revprops; svn_revnum_t peg_rev; svn_error_t *err; - const char *relative_url, *basecoll_url, *req_url; + const char *req_url; log_ctx = apr_pcalloc(pool, sizeof(*log_ctx)); log_ctx->pool = pool; @@ -651,7 +537,6 @@ svn_ra_serf__get_log(svn_ra_session_t *r log_ctx->include_merged_revisions = include_merged_revisions; log_ctx->revprops = revprops; log_ctx->nest_level = 0; - log_ctx->done = FALSE; want_custom_revprops = FALSE; if (revprops) @@ -691,12 +576,15 @@ svn_ra_serf__get_log(svn_ra_session_t *r */ peg_rev = (start > end) ? start : end; - SVN_ERR(svn_ra_serf__get_baseline_info(&basecoll_url, &relative_url, session, - NULL, NULL, peg_rev, NULL, pool)); - - req_url = svn_path_url_add_component2(basecoll_url, relative_url, pool); - - handler = apr_pcalloc(pool, sizeof(*handler)); + SVN_ERR(svn_ra_serf__get_stable_url(&req_url, NULL /* latest_revnum */, + session, NULL /* conn */, + NULL /* url */, peg_rev, + pool, pool)); + + xmlctx = svn_ra_serf__xml_context_create(log_ttable, + log_opened, log_closed, log_ctx, + pool); + handler = svn_ra_serf__create_expat_handler(xmlctx, pool); handler->method = "REPORT"; handler->path = req_url; @@ -706,27 +594,12 @@ svn_ra_serf__get_log(svn_ra_session_t *r handler->conn = session->conns[0]; handler->session = session; - parser_ctx = apr_pcalloc(pool, sizeof(*parser_ctx)); - - parser_ctx->pool = pool; - parser_ctx->user_data = log_ctx; - parser_ctx->start = start_log; - parser_ctx->end = end_log; - parser_ctx->cdata = cdata_log; - parser_ctx->done = &log_ctx->done; - parser_ctx->status_code = &log_ctx->status_code; - - handler->response_handler = svn_ra_serf__handle_xml_parser; - handler->response_baton = parser_ctx; - - svn_ra_serf__request_create(handler); - - err = svn_ra_serf__context_run_wait(&log_ctx->done, session, pool); + err = svn_ra_serf__context_run_one(handler, pool); SVN_ERR(svn_error_compose_create( - svn_ra_serf__error_on_status(log_ctx->status_code, + svn_ra_serf__error_on_status(handler->sline.code, req_url, - parser_ctx->location), + handler->location), err)); return SVN_NO_ERROR; Modified: subversion/branches/fix-rdump-editor/subversion/libsvn_ra_serf/merge.c URL: http://svn.apache.org/viewvc/subversion/branches/fix-rdump-editor/subversion/libsvn_ra_serf/merge.c?rev=1339349&r1=1339348&r2=1339349&view=diff ============================================================================== --- subversion/branches/fix-rdump-editor/subversion/libsvn_ra_serf/merge.c (original) +++ subversion/branches/fix-rdump-editor/subversion/libsvn_ra_serf/merge.c Wed May 16 20:32:43 2012 @@ -80,8 +80,8 @@ typedef struct merge_info_t { const char *prop_ns; const char *prop_name; - const char *prop_val; - apr_size_t prop_val_len; + svn_stringbuf_t *prop_value; + } merge_info_t; /* Structure associated with a MERGE request. */ @@ -90,6 +90,7 @@ struct svn_ra_serf__merge_context_t apr_pool_t *pool; svn_ra_serf__session_t *session; + svn_ra_serf__handler_t *handler; apr_hash_t *lock_tokens; svn_boolean_t keep_locks; @@ -97,8 +98,6 @@ struct svn_ra_serf__merge_context_t const char *merge_resource_url; /* URL of resource to be merged. */ const char *merge_url; /* URL at which the MERGE request is aimed. */ - int status; - svn_boolean_t done; svn_commit_info_t *commit_info; @@ -119,6 +118,7 @@ push_state(svn_ra_serf__xml_parser_t *pa info = apr_palloc(parser->state->pool, sizeof(*info)); info->pool = parser->state->pool; info->props = apr_hash_make(info->pool); + info->prop_value = svn_stringbuf_create_empty(info->pool); parser->state->private = info; } @@ -128,11 +128,11 @@ push_state(svn_ra_serf__xml_parser_t *pa static svn_error_t * start_merge(svn_ra_serf__xml_parser_t *parser, - void *userData, svn_ra_serf__dav_props_t name, - const char **attrs) + const char **attrs, + apr_pool_t *scratch_pool) { - svn_ra_serf__merge_context_t *ctx = userData; + svn_ra_serf__merge_context_t *ctx = parser->user_data; merge_state_e state; merge_info_t *info; @@ -163,9 +163,8 @@ start_merge(svn_ra_serf__xml_parser_t *p info = push_state(parser, ctx, PROP_VAL); info->prop_ns = name.namespace; - info->prop_name = apr_pstrdup(info->pool, name.name); - info->prop_val = NULL; - info->prop_val_len = 0; + info->prop_name = "href"; + svn_stringbuf_setempty(info->prop_value); } else if (state == RESPONSE && strcmp(name.name, "propstat") == 0) @@ -206,11 +205,9 @@ start_merge(svn_ra_serf__xml_parser_t *p strcmp(name.name, "checked-in") == 0) { info = push_state(parser, ctx, IGNORE_PROP_NAME); - info->prop_ns = name.namespace; - info->prop_name = apr_pstrdup(info->pool, name.name); - info->prop_val = NULL; - info->prop_val_len = 0; + info->prop_name = "checked-in"; + svn_stringbuf_setempty(info->prop_value); } else if (state == PROP) { @@ -225,8 +222,7 @@ start_merge(svn_ra_serf__xml_parser_t *p info = push_state(parser, ctx, PROP_VAL); info->prop_ns = name.namespace; info->prop_name = apr_pstrdup(info->pool, name.name); - info->prop_val = NULL; - info->prop_val_len = 0; + svn_stringbuf_setempty(info->prop_value); } else { @@ -238,10 +234,10 @@ start_merge(svn_ra_serf__xml_parser_t *p static svn_error_t * end_merge(svn_ra_serf__xml_parser_t *parser, - void *userData, - svn_ra_serf__dav_props_t name) + svn_ra_serf__dav_props_t name, + apr_pool_t *scratch_pool) { - svn_ra_serf__merge_context_t *ctx = userData; + svn_ra_serf__merge_context_t *ctx = parser->user_data; merge_state_e state; merge_info_t *info; @@ -349,24 +345,27 @@ end_merge(svn_ra_serf__xml_parser_t *par } else if (state == PROP_VAL) { + const char *value; + if (!info->prop_name) { + /* ### gstein sez: dunno what this is about. */ info->prop_name = apr_pstrdup(info->pool, name.name); } - info->prop_val = apr_pstrmemdup(info->pool, info->prop_val, - info->prop_val_len); + if (strcmp(info->prop_name, "href") == 0) - info->prop_val = svn_urlpath__canonicalize(info->prop_val, - info->pool); + value = svn_urlpath__canonicalize(info->prop_value->data, info->pool); + else + value = apr_pstrmemdup(info->pool, + info->prop_value->data, info->prop_value->len); /* Set our property. */ apr_hash_set(info->props, info->prop_name, APR_HASH_KEY_STRING, - info->prop_val); + value); info->prop_ns = NULL; info->prop_name = NULL; - info->prop_val = NULL; - info->prop_val_len = 0; + svn_stringbuf_setempty(info->prop_value); svn_ra_serf__xml_pop_state(parser); } @@ -376,11 +375,11 @@ end_merge(svn_ra_serf__xml_parser_t *par static svn_error_t * cdata_merge(svn_ra_serf__xml_parser_t *parser, - void *userData, const char *data, - apr_size_t len) + apr_size_t len, + apr_pool_t *scratch_pool) { - svn_ra_serf__merge_context_t *ctx = userData; + svn_ra_serf__merge_context_t *ctx = parser->user_data; merge_state_e state; merge_info_t *info; @@ -390,10 +389,7 @@ cdata_merge(svn_ra_serf__xml_parser_t *p info = parser->state->private; if (state == PROP_VAL) - { - svn_ra_serf__expand_string(&info->prop_val, &info->prop_val_len, - data, len, parser->state->pool); - } + svn_stringbuf_appendbytes(info->prop_value, data, len); return SVN_NO_ERROR; } @@ -538,6 +534,7 @@ svn_ra_serf__merge_create_req(svn_ra_ser handler = apr_pcalloc(pool, sizeof(*handler)); + handler->handler_pool = pool; handler->method = "MERGE"; handler->path = merge_ctx->merge_url; handler->body_delegate = create_merge_body; @@ -553,7 +550,6 @@ svn_ra_serf__merge_create_req(svn_ra_ser parser_ctx->end = end_merge; parser_ctx->cdata = cdata_merge; parser_ctx->done = &merge_ctx->done; - parser_ctx->status_code = &merge_ctx->status; handler->header_delegate = setup_merge_headers; handler->header_delegate_baton = merge_ctx; @@ -561,6 +557,8 @@ svn_ra_serf__merge_create_req(svn_ra_ser handler->response_handler = svn_ra_serf__handle_xml_parser; handler->response_baton = parser_ctx; + merge_ctx->handler = handler; + svn_ra_serf__request_create(handler); *ret_ctx = merge_ctx; @@ -583,5 +581,5 @@ svn_ra_serf__merge_get_commit_info(svn_r int svn_ra_serf__merge_get_status(svn_ra_serf__merge_context_t *ctx) { - return ctx->status; + return ctx->handler->sline.code; } Modified: subversion/branches/fix-rdump-editor/subversion/libsvn_ra_serf/mergeinfo.c URL: http://svn.apache.org/viewvc/subversion/branches/fix-rdump-editor/subversion/libsvn_ra_serf/mergeinfo.c?rev=1339349&r1=1339348&r2=1339349&view=diff ============================================================================== --- subversion/branches/fix-rdump-editor/subversion/libsvn_ra_serf/mergeinfo.c (original) +++ subversion/branches/fix-rdump-editor/subversion/libsvn_ra_serf/mergeinfo.c Wed May 16 20:32:43 2012 @@ -66,11 +66,11 @@ typedef struct mergeinfo_context_t { static svn_error_t * start_element(svn_ra_serf__xml_parser_t *parser, - void *userData, svn_ra_serf__dav_props_t name, - const char **attrs) + const char **attrs, + apr_pool_t *scratch_pool) { - mergeinfo_context_t *mergeinfo_ctx = userData; + mergeinfo_context_t *mergeinfo_ctx = parser->user_data; mergeinfo_state_e state; state = parser->state->current_state; @@ -99,10 +99,11 @@ start_element(svn_ra_serf__xml_parser_t } static svn_error_t * -end_element(svn_ra_serf__xml_parser_t *parser, void *userData, - svn_ra_serf__dav_props_t name) +end_element(svn_ra_serf__xml_parser_t *parser, + svn_ra_serf__dav_props_t name, + apr_pool_t *scratch_pool) { - mergeinfo_context_t *mergeinfo_ctx = userData; + mergeinfo_context_t *mergeinfo_ctx = parser->user_data; mergeinfo_state_e state; state = parser->state->current_state; @@ -149,10 +150,12 @@ end_element(svn_ra_serf__xml_parser_t *p static svn_error_t * -cdata_handler(svn_ra_serf__xml_parser_t *parser, void *userData, - const char *data, apr_size_t len) +cdata_handler(svn_ra_serf__xml_parser_t *parser, + const char *data, + apr_size_t len, + apr_pool_t *scratch_pool) { - mergeinfo_context_t *mergeinfo_ctx = userData; + mergeinfo_context_t *mergeinfo_ctx = parser->user_data; mergeinfo_state_e state; state = parser->state->current_state; @@ -238,21 +241,18 @@ svn_ra_serf__get_mergeinfo(svn_ra_sessio apr_pool_t *pool) { svn_error_t *err, *err2; - int status_code; - mergeinfo_context_t *mergeinfo_ctx; svn_ra_serf__session_t *session = ra_session->priv; svn_ra_serf__handler_t *handler; svn_ra_serf__xml_parser_t *parser_ctx; - const char *relative_url, *basecoll_url; const char *path; *catalog = NULL; - SVN_ERR(svn_ra_serf__get_baseline_info(&basecoll_url, &relative_url, session, - NULL, NULL, revision, NULL, pool)); - - path = svn_path_url_add_component2(basecoll_url, relative_url, pool); + SVN_ERR(svn_ra_serf__get_stable_url(&path, NULL /* latest_revnum */, + session, NULL /* conn */, + NULL /* url */, revision, + pool, pool)); mergeinfo_ctx = apr_pcalloc(pool, sizeof(*mergeinfo_ctx)); mergeinfo_ctx->pool = pool; @@ -267,6 +267,7 @@ svn_ra_serf__get_mergeinfo(svn_ra_sessio handler = apr_pcalloc(pool, sizeof(*handler)); + handler->handler_pool = pool; handler->method = "REPORT"; handler->path = path; handler->conn = session->conns[0]; @@ -283,7 +284,6 @@ svn_ra_serf__get_mergeinfo(svn_ra_sessio parser_ctx->end = end_element; parser_ctx->cdata = cdata_handler; parser_ctx->done = &mergeinfo_ctx->done; - parser_ctx->status_code = &status_code; handler->response_handler = svn_ra_serf__handle_xml_parser; handler->response_baton = parser_ctx; @@ -292,8 +292,8 @@ svn_ra_serf__get_mergeinfo(svn_ra_sessio err = svn_ra_serf__context_run_wait(&mergeinfo_ctx->done, session, pool); - err2 = svn_ra_serf__error_on_status(status_code, handler->path, - parser_ctx->location); + err2 = svn_ra_serf__error_on_status(handler->sline.code, handler->path, + handler->location); if (err2) { svn_error_clear(err);