You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by br...@apache.org on 2012/08/16 12:18:03 UTC
svn commit: r1373783 [18/50] - in /subversion/branches/compressed-pristines:
./ build/ build/ac-macros/ build/generator/ build/generator/templates/
build/win32/ contrib/client-side/emacs/ contrib/client-side/svn-push/
contrib/client-side/svnmerge/ cont...
Modified: subversion/branches/compressed-pristines/subversion/libsvn_ra_serf/getlocks.c
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/libsvn_ra_serf/getlocks.c?rev=1373783&r1=1373782&r2=1373783&view=diff
==============================================================================
--- subversion/branches/compressed-pristines/subversion/libsvn_ra_serf/getlocks.c (original)
+++ subversion/branches/compressed-pristines/subversion/libsvn_ra_serf/getlocks.c Thu Aug 16 10:17:48 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,18 +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 */
- svn_stringbuf_t *cdata;
-
-} lock_info_t;
+};
typedef struct lock_context_t {
apr_pool_t *pool;
@@ -79,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 },
- if (state == LOCK)
- {
- lock_info_t *info;
+ { REPORT, S_, "lock", LOCK,
+ FALSE, { NULL }, TRUE },
- info = apr_pcalloc(parser->state->pool, sizeof(*info));
+ { LOCK, S_, "path", PATH,
+ TRUE, { NULL }, TRUE },
- info->pool = lock_ctx->pool;
- info->lock = svn_lock_create(lock_ctx->pool);
- info->cdata = svn_stringbuf_create_empty(info->pool);
+ { LOCK, S_, "token", TOKEN,
+ TRUE, { NULL }, TRUE },
- parser->state->private = info;
- }
+ { LOCK, S_, "owner", OWNER,
+ TRUE, { NULL }, TRUE },
- return parser->state->private;
-}
+ { LOCK, S_, "comment", COMMENT,
+ TRUE, { NULL }, TRUE },
-static svn_error_t *
-start_getlocks(svn_ra_serf__xml_parser_t *parser,
- svn_ra_serf__dav_props_t name,
- const char **attrs,
- apr_pool_t *scratch_pool)
-{
- lock_context_t *lock_ctx = parser->user_data;
- lock_state_e state;
+ { LOCK, S_, SVN_DAV__CREATIONDATE, CREATION_DATE,
+ TRUE, { NULL }, TRUE },
- state = parser->state->current_state;
+ { LOCK, S_, "expirationdate", EXPIRATION_DATE,
+ TRUE, { NULL }, 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,
- svn_ra_serf__dav_props_t name,
- apr_pool_t *scratch_pool)
+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 = parser->user_data;
- 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
@@ -190,108 +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->cdata->data, info->cdata->len);
- svn_stringbuf_setempty(info->cdata);
- svn_ra_serf__xml_pop_state(parser);
- }
- else if (state == TOKEN &&
- strcmp(name.name, "token") == 0)
- {
- info->lock->token = apr_pstrmemdup(info->pool,
- info->cdata->data, info->cdata->len);
- svn_stringbuf_setempty(info->cdata);
- svn_ra_serf__xml_pop_state(parser);
- }
- else if (state == OWNER &&
- strcmp(name.name, "owner") == 0)
- {
- info->lock->owner = apr_pstrmemdup(info->pool,
- info->cdata->data, info->cdata->len);
- svn_stringbuf_setempty(info->cdata);
- svn_ra_serf__xml_pop_state(parser);
- }
- else if (state == COMMENT &&
- strcmp(name.name, "comment") == 0)
- {
- info->lock->comment = apr_pstrmemdup(info->pool,
- info->cdata->data,
- info->cdata->len);
- svn_stringbuf_setempty(info->cdata);
- 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->cdata->data, info->pool));
- svn_stringbuf_setempty(info->cdata);
- 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->cdata->data, info->pool));
- svn_stringbuf_setempty(info->cdata);
- 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,
- const char *data,
- apr_size_t len,
- apr_pool_t *scratch_pool)
-{
- lock_context_t *lock_ctx = parser->user_data;
- 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_stringbuf_appendbytes(info->cdata, data, len);
- break;
- default:
- break;
- }
-
- return SVN_NO_ERROR;
-}
/* Implements svn_ra_serf__request_body_delegate_t */
static svn_error_t *
@@ -324,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,
@@ -337,9 +246,12 @@ 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, NULL,
+ lock_ctx,
+ pool);
+ handler = svn_ra_serf__create_expat_handler(xmlctx, pool);
handler->method = "REPORT";
handler->path = req_url;
@@ -347,25 +259,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/compressed-pristines/subversion/libsvn_ra_serf/locks.c
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/libsvn_ra_serf/locks.c?rev=1373783&r1=1373782&r2=1373783&view=diff
==============================================================================
--- subversion/branches/compressed-pristines/subversion/libsvn_ra_serf/locks.c (original)
+++ subversion/branches/compressed-pristines/subversion/libsvn_ra_serf/locks.c Thu Aug 16 10:17:48 2012
@@ -24,9 +24,6 @@
#include <apr_uri.h>
-
-#include <expat.h>
-
#include <serf.h>
#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,8 +55,9 @@ typedef enum lock_state_e {
DEPTH,
TIMEOUT,
LOCK_TOKEN,
- COMMENT
-} lock_state_e;
+ OWNER,
+ HREF
+};
typedef struct lock_info_t {
apr_pool_t *pool;
@@ -70,246 +71,119 @@ typedef struct lock_info_t {
svn_boolean_t read_headers;
- /* Our HTTP status code and reason. */
- int status_code;
- const char *reason;
+ 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 svn_stringbuf_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 =
- svn_stringbuf_create_empty(parser->state->pool);
- 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 },
+ { INITIAL, D_, "multistatus", MULTISTATUS,
+ FALSE, { NULL }, FALSE },
- return parser->state->private;
-}
+ { MULTISTATUS, D_, "response", RESPONSE,
+ FALSE, { NULL }, 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,
- svn_ra_serf__dav_props_t name,
- const char **attrs,
- apr_pool_t *scratch_pool)
-{
- lock_info_t *ctx = parser->user_data;
- lock_state_e state;
+ { RESPONSE, D_, "propstat", PROPSTAT,
+ FALSE, { NULL }, FALSE },
- state = parser->state->current_state;
+ { PROPSTAT, D_, "prop", PROP,
+ FALSE, { NULL }, 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 },
- return SVN_NO_ERROR;
-}
+ { LOCK_DISCOVERY, D_, "activelock", ACTIVE_LOCK,
+ FALSE, { NULL }, 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 },
+
+ { LOCK_TYPE, D_, "write", WRITE,
+ FALSE, { NULL }, TRUE },
+
+ { ACTIVE_LOCK, D_, "lockscope", LOCK_SCOPE,
+ FALSE, { NULL }, FALSE },
+
+ { LOCK_SCOPE, D_, "exclusive", EXCLUSIVE,
+ FALSE, { NULL }, TRUE },
+#endif /* 0 */
+
+ { ACTIVE_LOCK, D_, "timeout", TIMEOUT,
+ TRUE, { NULL }, TRUE },
+
+ { ACTIVE_LOCK, D_, "locktoken", LOCK_TOKEN,
+ FALSE, { NULL }, FALSE },
+
+ { LOCK_TOKEN, D_, "href", HREF,
+ TRUE, { NULL }, TRUE },
+
+ { ACTIVE_LOCK, D_, "owner", OWNER,
+ TRUE, { NULL }, 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,
- svn_ra_serf__dav_props_t name,
- apr_pool_t *scratch_pool)
+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 = parser->user_data;
- 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)
- {
- svn_stringbuf_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)
{
- svn_stringbuf_t *info = parser->state->private;
-
- if (!ctx->lock->token && info->len)
+ if (cdata->len)
{
- apr_collapse_spaces(info->data, info->data);
- ctx->lock->token = apr_pstrmemdup(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)
{
- svn_stringbuf_t *info = parser->state->private;
-
- if (info->len)
+ if (cdata->len)
{
- ctx->lock->comment = apr_pstrmemdup(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,
- const char *data,
- apr_size_t len,
- apr_pool_t *scratch_pool)
-{
- lock_info_t *lock_ctx = parser->user_data;
- lock_state_e state;
- svn_stringbuf_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_stringbuf_appendbytes(info, data, len);
- 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,
@@ -333,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,
@@ -340,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);
@@ -395,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 */
@@ -445,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;
}
@@ -495,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);
@@ -508,9 +378,13 @@ 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, NULL,
+ lock_ctx,
+ pool);
+ handler = svn_ra_serf__create_expat_handler(xmlctx, pool);
handler->method = "PROPFIND";
handler->path = req_url;
@@ -518,29 +392,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"));
@@ -573,13 +441,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;
@@ -600,7 +471,11 @@ 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, NULL,
+ lock_ctx,
+ iterpool);
+ handler = svn_ra_serf__create_expat_handler(xmlctx, iterpool);
handler->method = "LOCK";
handler->path = req_url;
@@ -608,26 +483,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,
@@ -679,13 +549,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;
@@ -695,9 +567,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);
@@ -739,6 +608,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];
@@ -747,13 +617,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 */
@@ -761,12 +630,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/compressed-pristines/subversion/libsvn_ra_serf/log.c
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/libsvn_ra_serf/log.c?rev=1373783&r1=1373782&r2=1373783&view=diff
==============================================================================
--- subversion/branches/compressed-pristines/subversion/libsvn_ra_serf/log.c (original)
+++ subversion/branches/compressed-pristines/subversion/libsvn_ra_serf/log.c Thu Aug 16 10:17:48 2012
@@ -24,9 +24,6 @@
#include <apr_uri.h>
-
-#include <expat.h>
-
#include <serf.h>
#include "svn_pools.h"
@@ -40,6 +37,7 @@
#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"
@@ -49,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,
@@ -64,26 +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).
- */
- svn_stringbuf_t *tmp;
- 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,411 +95,315 @@ 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 },
- 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 },
- info = apr_pcalloc(info_pool, sizeof(*info));
- info->pool = info_pool;
- info->tmp = svn_stringbuf_create_empty(info_pool);
- info->log_entry = svn_log_entry_create(info_pool);
+ { ITEM, D_, SVN_DAV__VERSION_NAME, VERSION,
+ TRUE, { NULL }, TRUE },
- info->log_entry->revision = SVN_INVALID_REVNUM;
+ { ITEM, D_, "creator-displayname", CREATOR,
+ TRUE, { "?encoding", NULL }, TRUE },
- parser->state->private = info;
- }
+ { ITEM, S_, "date", DATE,
+ TRUE, { "?encoding", NULL }, 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 }, 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 }, 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 }, 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 }, 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 }, 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 }, TRUE },
- return parser->state->private;
-}
+ { ITEM, S_, "deleted-path", DELETED_PATH,
+ TRUE, { "?node-kind", "?text-mods", "?prop-mods", NULL }, 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 }, 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,
- svn_ra_serf__dav_props_t name,
- const char **attrs,
- apr_pool_t *scratch_pool)
+collect_revprop(apr_hash_t *revprops,
+ const char *propname,
+ const svn_string_t *cdata,
+ const char *encoding)
{
- log_context_t *log_ctx = parser->user_data;
- log_state_e state;
-
- state = parser->state->current_state;
+ apr_pool_t *result_pool = apr_hash_pool_get(revprops);
+ const svn_string_t *decoded;
- 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)
- {
- push_state(parser, log_ctx, CREATOR, attrs);
- }
- else if (strcmp(name.name, "date") == 0)
- {
- push_state(parser, log_ctx, DATE, attrs);
- }
- else if (strcmp(name.name, "comment") == 0)
- {
- 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,
+ const svn_ra_serf__dav_props_t *tag,
+ apr_pool_t *scratch_pool)
{
+ log_context_t *log_ctx = baton;
- if (info->tmp_encoding)
+ if (entered_state == ITEM)
{
- svn_string_t tmp;
+ apr_pool_t *state_pool = svn_ra_serf__xml_state_pool(xes);
- /* Don't use morph_info_string cuz we need info->tmp to
- remain usable. */
- tmp.data = info->tmp->data;
- tmp.len = info->tmp->len;
-
- /* 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);
- }
-
- *decoded_cdata = svn_base64_decode_string(&tmp, info->pool);
- }
- else
- {
- *decoded_cdata = svn_string_create_from_buf(info->tmp, info->pool);
+ log_ctx->collect_revprops = apr_hash_make(state_pool);
+ log_ctx->collect_paths = apr_hash_make(state_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,
- svn_ra_serf__dav_props_t name,
- apr_pool_t *scratch_pool)
+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 = parser->user_data;
- 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->data);
- svn_stringbuf_setempty(info->tmp);
- 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)));
}
- svn_stringbuf_setempty(info->tmp);
- 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)));
}
- svn_stringbuf_setempty(info->tmp);
- 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);
- }
- svn_stringbuf_setempty(info->tmp);
- 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);
- svn_stringbuf_setempty(info->tmp);
- 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->data, info->tmp->len);
- svn_stringbuf_setempty(info->tmp);
-
- 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,
- const char *data,
- apr_size_t len,
- apr_pool_t *scratch_pool)
-{
- log_context_t *log_ctx = parser->user_data;
- 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_stringbuf_appendbytes(info->tmp, data, len);
- 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';
+ }
- default:
- break;
+ 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,
@@ -636,11 +521,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;
@@ -655,7 +540,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)
@@ -695,12 +579,16 @@ 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, NULL,
+ log_ctx,
+ pool);
+ handler = svn_ra_serf__create_expat_handler(xmlctx, pool);
handler->method = "REPORT";
handler->path = req_url;
@@ -710,27 +598,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/compressed-pristines/subversion/libsvn_ra_serf/merge.c
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/libsvn_ra_serf/merge.c?rev=1373783&r1=1373782&r2=1373783&view=diff
==============================================================================
--- subversion/branches/compressed-pristines/subversion/libsvn_ra_serf/merge.c (original)
+++ subversion/branches/compressed-pristines/subversion/libsvn_ra_serf/merge.c Thu Aug 16 10:17:48 2012
@@ -47,7 +47,7 @@
* This enum represents the current state of our XML parsing for a MERGE.
*/
typedef enum merge_state_e {
- NONE = 0,
+ INITIAL = 0,
MERGE_RESPONSE,
UPDATED_SET,
RESPONSE,
@@ -55,41 +55,26 @@ typedef enum merge_state_e {
PROPSTAT,
PROP,
RESOURCE_TYPE,
- AUTHOR,
- NAME,
- DATE,
- IGNORE_PROP_NAME,
- NEED_PROP_NAME,
- PROP_VAL
-} merge_state_e;
-
-typedef enum resource_type_e {
- UNSET,
BASELINE,
COLLECTION,
- CHECKED_IN
-} resource_type_e;
-
-typedef struct merge_info_t {
- /* Temporary allocations here please */
- apr_pool_t *pool;
-
- resource_type_e type;
-
- apr_hash_t *props;
+ SKIP_HREF,
+ CHECKED_IN,
+ VERSION_NAME,
+ DATE,
+ AUTHOR,
+ POST_COMMIT_ERR,
- const char *prop_ns;
- const char *prop_name;
- svn_stringbuf_t *prop_value;
+ PROP_VAL
+} merge_state_e;
-} merge_info_t;
/* Structure associated with a MERGE request. */
-struct svn_ra_serf__merge_context_t
+typedef struct 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,310 +82,194 @@ 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_commit_info_t *commit_info;
- svn_boolean_t done;
+} merge_context_t;
- svn_commit_info_t *commit_info;
-};
-
-static merge_info_t *
-push_state(svn_ra_serf__xml_parser_t *parser,
- svn_ra_serf__merge_context_t *ctx,
- merge_state_e state)
-{
- merge_info_t *info;
+#define D_ "DAV:"
+#define S_ SVN_XML_NAMESPACE
+static const svn_ra_serf__xml_transition_t merge_ttable[] = {
+ { INITIAL, D_, "merge-response", MERGE_RESPONSE,
+ FALSE, { NULL }, FALSE },
- svn_ra_serf__xml_push_state(parser, state);
+ { MERGE_RESPONSE, D_, "updated-set", UPDATED_SET,
+ FALSE, { NULL }, FALSE },
- if (state == RESPONSE)
- {
- 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);
+ { UPDATED_SET, D_, "response", RESPONSE,
+ FALSE, { NULL }, TRUE },
- parser->state->private = info;
- }
+ { RESPONSE, D_, "href", HREF,
+ TRUE, { NULL }, TRUE },
- return parser->state->private;
-}
+ { RESPONSE, D_, "propstat", PROPSTAT,
+ FALSE, { NULL }, FALSE },
-static svn_error_t *
-start_merge(svn_ra_serf__xml_parser_t *parser,
- svn_ra_serf__dav_props_t name,
- const char **attrs,
- apr_pool_t *scratch_pool)
-{
- svn_ra_serf__merge_context_t *ctx = parser->user_data;
- merge_state_e state;
- merge_info_t *info;
+#if 0
+ /* Not needed. */
+ { PROPSTAT, D_, "status", STATUS,
+ FALSE, { NULL }, FALSE },
+#endif
- state = parser->state->current_state;
+ { PROPSTAT, D_, "prop", PROP,
+ FALSE, { NULL }, FALSE },
- if (state == NONE &&
- strcmp(name.name, "merge-response") == 0)
- {
- push_state(parser, ctx, MERGE_RESPONSE);
- }
- else if (state == NONE)
- {
- /* do nothing as we haven't seen our valid start tag yet. */
- }
- else if (state == MERGE_RESPONSE &&
- strcmp(name.name, "updated-set") == 0)
- {
- push_state(parser, ctx, UPDATED_SET);
- }
- else if (state == UPDATED_SET &&
- strcmp(name.name, "response") == 0)
- {
- push_state(parser, ctx, RESPONSE);
- }
- else if (state == RESPONSE &&
- strcmp(name.name, "href") == 0)
- {
- info = push_state(parser, ctx, PROP_VAL);
+ { PROP, D_, "resourcetype", RESOURCE_TYPE,
+ FALSE, { NULL }, FALSE },
- info->prop_ns = name.namespace;
- info->prop_name = "href";
- svn_stringbuf_setempty(info->prop_value);
- }
- else if (state == RESPONSE &&
- strcmp(name.name, "propstat") == 0)
- {
- push_state(parser, ctx, PROPSTAT);
- }
- else if (state == PROPSTAT &&
- strcmp(name.name, "prop") == 0)
- {
- push_state(parser, ctx, PROP);
- }
- else if (state == PROPSTAT &&
- strcmp(name.name, "status") == 0)
- {
- /* Do nothing for now. */
- }
- else if (state == PROP &&
- strcmp(name.name, "resourcetype") == 0)
- {
- info = push_state(parser, ctx, RESOURCE_TYPE);
- info->type = UNSET;
- }
- else if (state == RESOURCE_TYPE &&
- strcmp(name.name, "baseline") == 0)
- {
- info = parser->state->private;
+ { RESOURCE_TYPE, D_, "baseline", BASELINE,
+ FALSE, { NULL }, TRUE },
- info->type = BASELINE;
- }
- else if (state == RESOURCE_TYPE &&
- strcmp(name.name, "collection") == 0)
- {
- info = parser->state->private;
+ { RESOURCE_TYPE, D_, "collection", COLLECTION,
+ FALSE, { NULL }, TRUE },
- info->type = COLLECTION;
- }
- else if (state == PROP &&
- strcmp(name.name, "checked-in") == 0)
- {
- info = push_state(parser, ctx, IGNORE_PROP_NAME);
- info->prop_ns = name.namespace;
- info->prop_name = "checked-in";
- svn_stringbuf_setempty(info->prop_value);
- }
- else if (state == PROP)
- {
- push_state(parser, ctx, PROP_VAL);
- }
- else if (state == IGNORE_PROP_NAME)
- {
- push_state(parser, ctx, PROP_VAL);
- }
- else if (state == NEED_PROP_NAME)
- {
- info = push_state(parser, ctx, PROP_VAL);
- info->prop_ns = name.namespace;
- info->prop_name = apr_pstrdup(info->pool, name.name);
- svn_stringbuf_setempty(info->prop_value);
- }
- else
- {
- SVN_ERR_MALFUNCTION();
- }
+ { PROP, D_, "checked-in", SKIP_HREF,
+ FALSE, { NULL }, FALSE },
- return SVN_NO_ERROR;
-}
+ { SKIP_HREF, D_, "href", CHECKED_IN,
+ TRUE, { NULL }, TRUE },
+
+ { PROP, D_, SVN_DAV__VERSION_NAME, VERSION_NAME,
+ TRUE, { NULL }, TRUE },
+
+ { PROP, D_, SVN_DAV__CREATIONDATE, DATE,
+ TRUE, { NULL }, TRUE },
+
+ { PROP, D_, "creator-displayname", AUTHOR,
+ TRUE, { NULL }, TRUE },
+ { PROP, S_, "post-commit-err", POST_COMMIT_ERR,
+ TRUE, { NULL }, TRUE },
+
+ { 0 }
+};
+
+
+/* Conforms to svn_ra_serf__xml_closed_t */
static svn_error_t *
-end_merge(svn_ra_serf__xml_parser_t *parser,
- svn_ra_serf__dav_props_t name,
- apr_pool_t *scratch_pool)
+merge_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)
{
- svn_ra_serf__merge_context_t *ctx = parser->user_data;
- merge_state_e state;
- merge_info_t *info;
+ merge_context_t *merge_ctx = baton;
- state = parser->state->current_state;
- info = parser->state->private;
-
- if (state == NONE)
+ if (leaving_state == RESPONSE)
{
- /* nothing to close yet. */
- return SVN_NO_ERROR;
- }
+ const char *rtype;
- if (state == RESPONSE &&
- strcmp(name.name, "response") == 0)
- {
- if (info->type == BASELINE)
+ rtype = apr_hash_get(attrs, "resourcetype", APR_HASH_KEY_STRING);
+
+ /* rtype can only be "baseline" or "collection" (or NULL). We can
+ keep this check simple. */
+ if (rtype && *rtype == 'b')
{
- const char *str;
+ const char *rev_str;
- str = apr_hash_get(info->props, SVN_DAV__VERSION_NAME,
- APR_HASH_KEY_STRING);
- if (str)
- {
- ctx->commit_info->revision = SVN_STR_TO_REV(str);
- }
+ rev_str = apr_hash_get(attrs, "revision", APR_HASH_KEY_STRING);
+ if (rev_str)
+ merge_ctx->commit_info->revision = SVN_STR_TO_REV(rev_str);
else
- {
- ctx->commit_info->revision = SVN_INVALID_REVNUM;
- }
+ merge_ctx->commit_info->revision = SVN_INVALID_REVNUM;
- ctx->commit_info->date =
- apr_pstrdup(ctx->pool,
- apr_hash_get(info->props, SVN_DAV__CREATIONDATE,
- APR_HASH_KEY_STRING));
-
- ctx->commit_info->author =
- apr_pstrdup(ctx->pool,
- apr_hash_get(info->props, "creator-displayname",
- APR_HASH_KEY_STRING));
-
- ctx->commit_info->post_commit_err =
- apr_pstrdup(ctx->pool,
- apr_hash_get(info->props,
+ merge_ctx->commit_info->date =
+ apr_pstrdup(merge_ctx->pool,
+ apr_hash_get(attrs, "date", APR_HASH_KEY_STRING));
+
+ merge_ctx->commit_info->author =
+ apr_pstrdup(merge_ctx->pool,
+ apr_hash_get(attrs, "author", APR_HASH_KEY_STRING));
+
+ merge_ctx->commit_info->post_commit_err =
+ apr_pstrdup(merge_ctx->pool,
+ apr_hash_get(attrs,
"post-commit-err", APR_HASH_KEY_STRING));
}
else
{
const char *href;
- href = apr_hash_get(info->props, "href", APR_HASH_KEY_STRING);
- if (! svn_urlpath__skip_ancestor(ctx->merge_url, href))
- {
- return svn_error_createf(SVN_ERR_RA_DAV_REQUEST_FAILED, NULL,
- _("A MERGE response for '%s' is not "
- "a child of the destination ('%s')"),
- href, ctx->merge_url);
- }
+ href = svn_urlpath__skip_ancestor(
+ merge_ctx->merge_url,
+ apr_hash_get(attrs, "href", APR_HASH_KEY_STRING));
+
+ if (href == NULL)
+ return svn_error_createf(SVN_ERR_RA_DAV_REQUEST_FAILED, NULL,
+ _("A MERGE response for '%s' is not "
+ "a child of the destination ('%s')"),
+ href, merge_ctx->merge_url);
/* We now need to dive all the way into the WC to update the
- * base VCC url.
- */
- if ((! SVN_RA_SERF__HAVE_HTTPV2_SUPPORT(ctx->session))
- && ctx->session->wc_callbacks->push_wc_prop)
+ base VCC url. */
+ if (!SVN_RA_SERF__HAVE_HTTPV2_SUPPORT(merge_ctx->session)
+ && merge_ctx->session->wc_callbacks->push_wc_prop)
{
- svn_string_t checked_in_str;
const char *checked_in;
+ svn_string_t checked_in_str;
- /* From the above check, we know that CTX->MERGE_URL is
- an ancestor of HREF. All that remains is to
- determine if HREF is the same as CTX->MERGE_URL, or --
- if not -- its relative value as a child thereof. */
- href = svn_urlpath__skip_ancestor(ctx->merge_url, href);
-
- checked_in = apr_hash_get(info->props, "checked-in",
- APR_HASH_KEY_STRING);
+ checked_in = apr_hash_get(attrs,
+ "checked-in", APR_HASH_KEY_STRING);
checked_in_str.data = checked_in;
checked_in_str.len = strlen(checked_in);
- SVN_ERR(ctx->session->wc_callbacks->push_wc_prop(
- ctx->session->wc_callback_baton, href,
- SVN_RA_SERF__WC_CHECKED_IN_URL, &checked_in_str, info->pool));
+ SVN_ERR(merge_ctx->session->wc_callbacks->push_wc_prop(
+ merge_ctx->session->wc_callback_baton,
+ href,
+ SVN_RA_SERF__WC_CHECKED_IN_URL,
+ &checked_in_str,
+ scratch_pool));
}
}
-
- svn_ra_serf__xml_pop_state(parser);
- }
- else if (state == PROPSTAT &&
- strcmp(name.name, "propstat") == 0)
- {
- svn_ra_serf__xml_pop_state(parser);
}
- else if (state == PROP &&
- strcmp(name.name, "prop") == 0)
+ else if (leaving_state == BASELINE)
{
- svn_ra_serf__xml_pop_state(parser);
+ svn_ra_serf__xml_note(xes, RESPONSE, "resourcetype", "baseline");
}
- else if (state == RESOURCE_TYPE &&
- strcmp(name.name, "resourcetype") == 0)
+ else if (leaving_state == COLLECTION)
{
- svn_ra_serf__xml_pop_state(parser);
+ svn_ra_serf__xml_note(xes, RESPONSE, "resourcetype", "collection");
}
- else if (state == IGNORE_PROP_NAME || state == NEED_PROP_NAME)
- {
- svn_ra_serf__xml_pop_state(parser);
- }
- else if (state == PROP_VAL)
+ else
{
- const char *value;
+ const char *name;
+ const char *value = cdata->data;
- if (!info->prop_name)
+ if (leaving_state == HREF)
{
- /* ### gstein sez: dunno what this is about. */
- info->prop_name = apr_pstrdup(info->pool, name.name);
+ name = "href";
+ value = svn_urlpath__canonicalize(value, scratch_pool);
}
-
- if (strcmp(info->prop_name, "href") == 0)
- value = svn_urlpath__canonicalize(info->prop_value->data, info->pool);
+ else if (leaving_state == CHECKED_IN)
+ {
+ name = "checked-in";
+ value = svn_urlpath__canonicalize(value, scratch_pool);
+ }
+ else if (leaving_state == VERSION_NAME)
+ name = "revision";
+ else if (leaving_state == DATE)
+ name = "date";
+ else if (leaving_state == AUTHOR)
+ name = "author";
+ else if (leaving_state == POST_COMMIT_ERR)
+ name = "post-commit-err";
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,
- value);
-
- info->prop_ns = NULL;
- info->prop_name = NULL;
- svn_stringbuf_setempty(info->prop_value);
+ SVN_ERR_MALFUNCTION();
- svn_ra_serf__xml_pop_state(parser);
+ svn_ra_serf__xml_note(xes, RESPONSE, name, value);
}
return SVN_NO_ERROR;
}
-static svn_error_t *
-cdata_merge(svn_ra_serf__xml_parser_t *parser,
- const char *data,
- apr_size_t len,
- apr_pool_t *scratch_pool)
-{
- svn_ra_serf__merge_context_t *ctx = parser->user_data;
- merge_state_e state;
- merge_info_t *info;
-
- UNUSED_CTX(ctx);
-
- state = parser->state->current_state;
- info = parser->state->private;
-
- if (state == PROP_VAL)
- svn_stringbuf_appendbytes(info->prop_value, data, len);
-
- return SVN_NO_ERROR;
-}
static svn_error_t *
setup_merge_headers(serf_bucket_t *headers,
void *baton,
apr_pool_t *pool)
{
- svn_ra_serf__merge_context_t *ctx = baton;
+ merge_context_t *ctx = baton;
if (!ctx->keep_locks)
{
@@ -465,7 +334,7 @@ create_merge_body(serf_bucket_t **bkt,
serf_bucket_alloc_t *alloc,
apr_pool_t *pool)
{
- svn_ra_serf__merge_context_t *ctx = baton;
+ merge_context_t *ctx = baton;
serf_bucket_t *body_bkt;
body_bkt = serf_bucket_aggregate_create(alloc);
@@ -507,21 +376,23 @@ create_merge_body(serf_bucket_t **bkt,
svn_error_t *
-svn_ra_serf__merge_create_req(svn_ra_serf__merge_context_t **ret_ctx,
- svn_ra_serf__session_t *session,
- svn_ra_serf__connection_t *conn,
- const char *merge_resource_url,
- apr_hash_t *lock_tokens,
- svn_boolean_t keep_locks,
- apr_pool_t *pool)
+svn_ra_serf__run_merge(const svn_commit_info_t **commit_info,
+ int *response_code,
+ svn_ra_serf__session_t *session,
+ svn_ra_serf__connection_t *conn,
+ const char *merge_resource_url,
+ apr_hash_t *lock_tokens,
+ svn_boolean_t keep_locks,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
{
- svn_ra_serf__merge_context_t *merge_ctx;
+ merge_context_t *merge_ctx;
svn_ra_serf__handler_t *handler;
- svn_ra_serf__xml_parser_t *parser_ctx;
+ svn_ra_serf__xml_context_t *xmlctx;
- merge_ctx = apr_pcalloc(pool, sizeof(*merge_ctx));
+ merge_ctx = apr_pcalloc(scratch_pool, sizeof(*merge_ctx));
- merge_ctx->pool = pool;
+ merge_ctx->pool = result_pool;
merge_ctx->session = session;
merge_ctx->merge_resource_url = merge_resource_url;
@@ -529,11 +400,15 @@ svn_ra_serf__merge_create_req(svn_ra_ser
merge_ctx->lock_tokens = lock_tokens;
merge_ctx->keep_locks = keep_locks;
- merge_ctx->commit_info = svn_create_commit_info(pool);
+ merge_ctx->commit_info = svn_create_commit_info(result_pool);
merge_ctx->merge_url = session->session_url.path;
- handler = apr_pcalloc(pool, sizeof(*handler));
+ xmlctx = svn_ra_serf__xml_context_create(merge_ttable,
+ NULL, merge_closed, NULL,
+ merge_ctx,
+ scratch_pool);
+ handler = svn_ra_serf__create_expat_handler(xmlctx, scratch_pool);
handler->method = "MERGE";
handler->path = merge_ctx->merge_url;
@@ -542,43 +417,15 @@ svn_ra_serf__merge_create_req(svn_ra_ser
handler->conn = conn;
handler->session = session;
- parser_ctx = apr_pcalloc(pool, sizeof(*parser_ctx));
-
- parser_ctx->pool = pool;
- parser_ctx->user_data = merge_ctx;
- parser_ctx->start = start_merge;
- 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;
- handler->response_handler = svn_ra_serf__handle_xml_parser;
- handler->response_baton = parser_ctx;
+ merge_ctx->handler = handler;
- svn_ra_serf__request_create(handler);
+ SVN_ERR(svn_ra_serf__context_run_one(handler, scratch_pool));
- *ret_ctx = merge_ctx;
+ *commit_info = merge_ctx->commit_info;
+ *response_code = handler->sline.code;
return SVN_NO_ERROR;
}
-
-svn_boolean_t*
-svn_ra_serf__merge_get_done_ptr(svn_ra_serf__merge_context_t *ctx)
-{
- return &ctx->done;
-}
-
-svn_commit_info_t*
-svn_ra_serf__merge_get_commit_info(svn_ra_serf__merge_context_t *ctx)
-{
- return ctx->commit_info;
-}
-
-int
-svn_ra_serf__merge_get_status(svn_ra_serf__merge_context_t *ctx)
-{
- return ctx->status;
-}