You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by hw...@apache.org on 2012/05/14 16:07:47 UTC

svn commit: r1338209 [2/4] - in /subversion/branches/ev2-export: ./ build/ac-macros/ subversion/bindings/javahl/src/org/apache/subversion/javahl/ subversion/include/ subversion/include/private/ subversion/libsvn_client/ subversion/libsvn_ra_serf/ subve...

Modified: subversion/branches/ev2-export/subversion/libsvn_client/util.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_client/util.c?rev=1338209&r1=1338208&r2=1338209&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_client/util.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_client/util.c Mon May 14 14:07:45 2012
@@ -232,6 +232,35 @@ svn_client__path_relative_to_root(const 
 }
 
 svn_error_t *
+svn_client__wc_node_get_base(svn_client__pathrev_t **base_p,
+                               const char *wc_abspath,
+                               svn_client_ctx_t *ctx,
+                               apr_pool_t *result_pool,
+                               apr_pool_t *scratch_pool)
+{
+  const char *relpath;
+
+  *base_p = apr_palloc(result_pool, sizeof(**base_p));
+
+  SVN_ERR(svn_wc__node_get_base(&(*base_p)->rev,
+                                &relpath,
+                                &(*base_p)->repos_root_url,
+                                &(*base_p)->repos_uuid,
+                                ctx->wc_ctx, wc_abspath,
+                                result_pool, scratch_pool));
+  if ((*base_p)->repos_root_url && relpath)
+    {
+      (*base_p)->url = svn_path_url_add_component2(
+                           (*base_p)->repos_root_url, relpath, result_pool);
+    }
+  else
+    {
+      *base_p = NULL;
+    }
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
 svn_client__wc_node_get_origin(svn_client__pathrev_t **origin_p,
                                const char *wc_abspath,
                                svn_client_ctx_t *ctx,

Modified: subversion/branches/ev2-export/subversion/libsvn_ra_serf/blame.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_ra_serf/blame.c?rev=1338209&r1=1338208&r2=1338209&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_ra_serf/blame.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_ra_serf/blame.c Mon May 14 14:07:45 2012
@@ -22,9 +22,6 @@
  */
 
 #include <apr_uri.h>
-
-#include <expat.h>
-
 #include <serf.h>
 
 #include "svn_pools.h"
@@ -50,6 +47,7 @@
  */
 typedef enum blame_state_e {
   NONE = 0,
+  INITIAL = 0,
   FILE_REVS_REPORT,
   FILE_REV,
   REV_PROP,
@@ -112,6 +110,42 @@ typedef struct blame_context_t {
   void *file_rev_baton;
 } blame_context_t;
 
+
+#if 0
+/* ### we cannot use this yet since the CDATA is unbounded and cannot be
+   ### collected by the parsing context. we need a streamy mechanism for
+   ### this report.  */
+
+#define D_ "DAV:"
+#define S_ SVN_XML_NAMESPACE
+static const svn_ra_serf__xml_transition_t blame_ttable[] = {
+  { INITIAL, S_, "file-revs-report", FILE_REVS_REPORT,
+    FALSE, { NULL }, FALSE, FALSE },
+
+  { FILE_REVS_REPORT, S_, "file-rev", FILE_REV,
+    FALSE, { "path", "rev", NULL }, FALSE, TRUE },
+
+  { FILE_REV, D_, "rev-prop", REV_PROP,
+    TRUE, { "name", "?encoding", NULL }, FALSE, TRUE },
+
+  { FILE_REV, D_, "set-prop", SET_PROP,
+    TRUE, { "name", "?encoding", NULL }, FALSE, TRUE },
+
+  { FILE_REV, D_, "remove-prop", REMOVE_PROP,
+    FALSE, { "name", "?encoding", NULL }, FALSE, TRUE },
+
+  { FILE_REV, D_, "merged-revision", MERGED_REVISION,
+    FALSE, { NULL }, FALSE, FALSE },
+
+  { FILE_REV, D_, "txdelta", TXDELTA,
+    TRUE, { NULL }, FALSE, TRUE },
+
+  { 0 }
+};
+
+#endif
+
+
 
 static blame_info_t *
 push_state(svn_ra_serf__xml_parser_t *parser,

Modified: subversion/branches/ev2-export/subversion/libsvn_ra_serf/commit.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_ra_serf/commit.c?rev=1338209&r1=1338208&r2=1338209&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_ra_serf/commit.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_ra_serf/commit.c Mon May 14 14:07:45 2012
@@ -22,9 +22,6 @@
  */
 
 #include <apr_uri.h>
-
-#include <expat.h>
-
 #include <serf.h>
 
 #include "svn_pools.h"
@@ -1661,14 +1658,10 @@ add_directory(const char *path,
         break;
 
       case 403:
-        if (handler->server_error)
-          SVN_ERR(handler->server_error->error);
         return svn_error_createf(SVN_ERR_RA_DAV_FORBIDDEN, NULL,
                                 _("Access to '%s' forbidden"),
                                  handler->path);
       default:
-        if (handler->server_error)
-          SVN_ERR(handler->server_error->error);
         return svn_error_createf(SVN_ERR_RA_DAV_REQUEST_FAILED, NULL,
                                  _("Adding directory failed: %s on %s "
                                    "(%d %s)"),

Modified: subversion/branches/ev2-export/subversion/libsvn_ra_serf/get_deleted_rev.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_ra_serf/get_deleted_rev.c?rev=1338209&r1=1338208&r2=1338209&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_ra_serf/get_deleted_rev.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_ra_serf/get_deleted_rev.c Mon May 14 14:07:45 2012
@@ -35,14 +35,13 @@
 /*
  * This enum represents the current state of our XML parsing for a REPORT.
  */
-typedef enum drev_state_e {
-  NONE = 0,
+enum drev_state_e {
+  INITIAL = 0,
+  REPORT,
   VERSION_NAME
-} drev_state_e;
+};
 
 typedef struct drev_context_t {
-  apr_pool_t *pool;
-
   const char *path;
   svn_revnum_t peg_revision;
   svn_revnum_t end_revision;
@@ -51,91 +50,41 @@ typedef struct drev_context_t {
      the range PEG_REVISION-END-END_REVISION? */
   svn_revnum_t *revision_deleted;
 
-  /* are we done? */
-  svn_boolean_t done;
-
 } drev_context_t;
 
-
-static void
-push_state(svn_ra_serf__xml_parser_t *parser,
-           drev_context_t *drev_ctx,
-           drev_state_e state)
-{
-  svn_ra_serf__xml_push_state(parser, state);
-
-  if (state == VERSION_NAME)
-    parser->state->private = NULL;
-}
-
-static svn_error_t *
-start_getdrev(svn_ra_serf__xml_parser_t *parser,
-              svn_ra_serf__dav_props_t name,
-              const char **attrs,
-              apr_pool_t *scratch_pool)
-{
-  drev_context_t *drev_ctx = parser->user_data;
-  drev_state_e state;
-
-  state = parser->state->current_state;
+#define D_ "DAV:"
+#define S_ SVN_XML_NAMESPACE
+static const svn_ra_serf__xml_transition_t getdrev_ttable[] = {
+  { INITIAL, S_, "get-deleted-rev-report", REPORT,
+    FALSE, { NULL }, FALSE, FALSE },
 
-  if (state == NONE &&
-      strcmp(name.name, SVN_DAV__VERSION_NAME) == 0)
-    {
-      push_state(parser, drev_ctx, VERSION_NAME);
-    }
+  { REPORT, D_, SVN_DAV__VERSION_NAME, VERSION_NAME,
+    TRUE, { NULL }, FALSE, TRUE },
 
-  return SVN_NO_ERROR;
-}
-
-static svn_error_t *
-end_getdrev(svn_ra_serf__xml_parser_t *parser,
-            svn_ra_serf__dav_props_t name,
-            apr_pool_t *scratch_pool)
-{
-  drev_context_t *drev_ctx = parser->user_data;
-  drev_state_e state;
-  svn_string_t *info;
-
-  state = parser->state->current_state;
-  info = parser->state->private;
-
-  if (state == VERSION_NAME &&
-      strcmp(name.name, SVN_DAV__VERSION_NAME) == 0 &&
-      info)
-    {
-      *drev_ctx->revision_deleted = SVN_STR_TO_REV(info->data);
-      svn_ra_serf__xml_pop_state(parser);
-    }
-
-  return SVN_NO_ERROR;
-}
+  { 0 }
+};
 
+
+/* Conforms to svn_ra_serf__xml_closed_t  */
 static svn_error_t *
-cdata_getdrev(svn_ra_serf__xml_parser_t *parser,
-              const char *data,
-              apr_size_t len,
-              apr_pool_t *scratch_pool)
+getdrev_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)
 {
-  drev_context_t *drev_ctx = parser->user_data;
-  drev_state_e state;
+  drev_context_t *drev_ctx = baton;
 
-  UNUSED_CTX(drev_ctx);
+  SVN_ERR_ASSERT(leaving_state == VERSION_NAME);
+  SVN_ERR_ASSERT(cdata != NULL);
 
-  state = parser->state->current_state;
-  switch (state)
-    {
-    case VERSION_NAME:
-        parser->state->private = svn_string_ncreate(data, len,
-                                                    parser->state->pool);
-        break;
-    default:
-        break;
-    }
+  *drev_ctx->revision_deleted = SVN_STR_TO_REV(cdata->data);
 
   return SVN_NO_ERROR;
 }
 
+
 /* Implements svn_ra_serf__request_body_delegate_t */
 static svn_error_t *
 create_getdrev_body(serf_bucket_t **body_bkt,
@@ -186,7 +135,7 @@ svn_ra_serf__get_deleted_rev(svn_ra_sess
   drev_context_t *drev_ctx;
   svn_ra_serf__session_t *ras = 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;
   svn_error_t *err;
 
@@ -194,38 +143,27 @@ svn_ra_serf__get_deleted_rev(svn_ra_sess
   drev_ctx->path = path;
   drev_ctx->peg_revision = peg_revision;
   drev_ctx->end_revision = end_revision;
-  drev_ctx->pool = pool;
   drev_ctx->revision_deleted = revision_deleted;
-  drev_ctx->done = FALSE;
 
   SVN_ERR(svn_ra_serf__get_stable_url(&req_url, NULL /* latest_revnum */,
                                       ras, NULL /* conn */,
                                       NULL /* url */, peg_revision,
                                       pool, pool));
 
-  parser_ctx = apr_pcalloc(pool, sizeof(*parser_ctx));
-  parser_ctx->pool = pool;
-  parser_ctx->user_data = drev_ctx;
-  parser_ctx->start = start_getdrev;
-  parser_ctx->end = end_getdrev;
-  parser_ctx->cdata = cdata_getdrev;
-  parser_ctx->done = &drev_ctx->done;
+  xmlctx = svn_ra_serf__xml_context_create(getdrev_ttable,
+                                           NULL, getdrev_closed, drev_ctx,
+                                           pool);
+  handler = svn_ra_serf__create_expat_handler(xmlctx, pool);
 
-  handler = apr_pcalloc(pool, sizeof(*handler));
-  handler->handler_pool = pool;
   handler->method = "REPORT";
   handler->path = req_url;
   handler->body_type = "text/xml";
-  handler->response_handler = svn_ra_serf__handle_xml_parser;
   handler->body_delegate = create_getdrev_body;
   handler->body_delegate_baton = drev_ctx;
   handler->conn = ras->conns[0];
   handler->session = ras;
-  handler->response_baton = parser_ctx;
 
-  svn_ra_serf__request_create(handler);
-
-  err = svn_ra_serf__context_run_wait(&drev_ctx->done, ras, pool);
+  err = svn_ra_serf__context_run_one(handler, pool);
 
   /* Map status 501: Method Not Implemented to our not implemented error.
      1.5.x servers and older don't support this report. */
@@ -234,5 +172,6 @@ svn_ra_serf__get_deleted_rev(svn_ra_sess
                              _("'%s' REPORT not implemented"),
                              "get-deleted-rev");
   SVN_ERR(err);
+
   return SVN_NO_ERROR;
 }

Modified: subversion/branches/ev2-export/subversion/libsvn_ra_serf/getdate.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_ra_serf/getdate.c?rev=1338209&r1=1338208&r2=1338209&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_ra_serf/getdate.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_ra_serf/getdate.c Mon May 14 14:07:45 2012
@@ -24,9 +24,6 @@
 
 
 #include <apr_uri.h>
-
-#include <expat.h>
-
 #include <serf.h>
 
 #include "svn_pools.h"
@@ -46,10 +43,11 @@
 /*
  * This enum represents the current state of our XML parsing for a REPORT.
  */
-typedef enum date_state_e {
-  NONE = 0,
+enum date_state_e {
+  INITIAL = 0,
+  REPORT,
   VERSION_NAME
-} date_state_e;
+};
 
 
 typedef struct date_context_t {
@@ -59,79 +57,41 @@ typedef struct date_context_t {
   /* What was the youngest revision at that time? */
   svn_revnum_t *revision;
 
-  /* are we done? */
-  svn_boolean_t done;
-
 } date_context_t;
 
+#define D_ "DAV:"
+#define S_ SVN_XML_NAMESPACE
+static const svn_ra_serf__xml_transition_t date_ttable[] = {
+  { INITIAL, S_, "dated-rev-report", REPORT,
+    FALSE, { NULL }, FALSE, FALSE },
 
-static svn_error_t *
-start_getdate(svn_ra_serf__xml_parser_t *parser,
-              svn_ra_serf__dav_props_t name,
-              const char **attrs,
-              apr_pool_t *scratch_pool)
-{
-  date_context_t *date_ctx = parser->user_data;
-  date_state_e state = parser->state->current_state;
-
-  UNUSED_CTX(date_ctx);
-
-  if (state == NONE &&
-      strcmp(name.name, SVN_DAV__VERSION_NAME) == 0)
-    {
-      svn_ra_serf__xml_push_state(parser, VERSION_NAME);
+  { REPORT, D_, SVN_DAV__VERSION_NAME, VERSION_NAME,
+    TRUE, { NULL }, FALSE, TRUE },
 
-      parser->state->private = svn_stringbuf_create_empty(parser->state->pool);
-    }
+  { 0 }
+};
 
-  return SVN_NO_ERROR;
-}
 
+/* Conforms to svn_ra_serf__xml_closed_t  */
 static svn_error_t *
-end_getdate(svn_ra_serf__xml_parser_t *parser,
-            svn_ra_serf__dav_props_t name,
+date_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)
 {
-  date_context_t *date_ctx = parser->user_data;
-  date_state_e state = parser->state->current_state;
-
-  if (state == VERSION_NAME &&
-      strcmp(name.name, SVN_DAV__VERSION_NAME) == 0)
-    {
-      const svn_stringbuf_t *datebuf = parser->state->private;
-
-      *date_ctx->revision = SVN_STR_TO_REV(datebuf->data);
-      svn_ra_serf__xml_pop_state(parser);
-    }
+  date_context_t *date_ctx = baton;
 
-  return SVN_NO_ERROR;
-}
+  SVN_ERR_ASSERT(leaving_state == VERSION_NAME);
+  SVN_ERR_ASSERT(cdata != NULL);
 
-static svn_error_t *
-cdata_getdate(svn_ra_serf__xml_parser_t *parser,
-              const char *data,
-              apr_size_t len,
-              apr_pool_t *scratch_pool)
-{
-  date_context_t *date_ctx = parser->user_data;
-  date_state_e state = parser->state->current_state;
-  svn_stringbuf_t *datebuf;
-
-  UNUSED_CTX(date_ctx);
-
-  switch (state)
-    {
-    case VERSION_NAME:
-        datebuf = parser->state->private;
-        svn_stringbuf_appendbytes(datebuf, data, len);
-        break;
-    default:
-        break;
-    }
+  *date_ctx->revision = SVN_STR_TO_REV(cdata->data);
 
   return SVN_NO_ERROR;
 }
 
+
 /* Implements svn_ra_serf__request_body_delegate_t */
 static svn_error_t *
 create_getdate_body(serf_bucket_t **body_bkt,
@@ -169,45 +129,32 @@ svn_ra_serf__get_dated_revision(svn_ra_s
   date_context_t *date_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 *report_target;
 
   date_ctx = apr_palloc(pool, sizeof(*date_ctx));
   date_ctx->time = tm;
   date_ctx->revision = revision;
-  date_ctx->done = FALSE;
 
   SVN_ERR(svn_ra_serf__report_resource(&report_target, session, NULL, pool));
 
-  handler = apr_pcalloc(pool, sizeof(*handler));
+  xmlctx = svn_ra_serf__xml_context_create(date_ttable,
+                                           NULL, date_closed, date_ctx,
+                                           pool);
+  handler = svn_ra_serf__create_expat_handler(xmlctx, pool);
 
-  handler->handler_pool = pool;
   handler->method = "REPORT";
   handler->path = report_target;
   handler->body_type = "text/xml";
   handler->conn = session->conns[0];
   handler->session = session;
 
-  parser_ctx = apr_pcalloc(pool, sizeof(*parser_ctx));
-
-  parser_ctx->pool = pool;
-  parser_ctx->user_data = date_ctx;
-  parser_ctx->start = start_getdate;
-  parser_ctx->end = end_getdate;
-  parser_ctx->cdata = cdata_getdate;
-  parser_ctx->done = &date_ctx->done;
-
   handler->body_delegate = create_getdate_body;
   handler->body_delegate_baton = date_ctx;
 
-  handler->response_handler = svn_ra_serf__handle_xml_parser;
-  handler->response_baton = parser_ctx;
-
-  svn_ra_serf__request_create(handler);
-
   *date_ctx->revision = SVN_INVALID_REVNUM;
 
   /* ### use svn_ra_serf__error_on_status() ?  */
 
-  return svn_ra_serf__context_run_wait(&date_ctx->done, session, pool);
+  return svn_error_trace(svn_ra_serf__context_run_one(handler, pool));
 }

Modified: subversion/branches/ev2-export/subversion/libsvn_ra_serf/getlocations.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_ra_serf/getlocations.c?rev=1338209&r1=1338208&r2=1338209&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_ra_serf/getlocations.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_ra_serf/getlocations.c Mon May 14 14:07:45 2012
@@ -41,18 +41,11 @@
 /*
  * This enum represents the current state of our XML parsing for a REPORT.
  */
-typedef enum loc_state_e {
+enum loc_state_e {
+  INITIAL = 0,
   REPORT,
   LOCATION
-} loc_state_e;
-
-typedef struct loc_state_list_t {
-  /* The current state that we are in now. */
-  loc_state_e state;
-
-  /* The previous state we were in. */
-  struct loc_state_list_t *prev;
-} loc_state_list_t;
+};
 
 typedef struct loc_context_t {
   /* pool to allocate memory from */
@@ -66,112 +59,49 @@ typedef struct loc_context_t {
   /* Returned location hash */
   apr_hash_t *paths;
 
-  /* Current state we're in */
-  loc_state_list_t *state;
-  loc_state_list_t *free_state;
-
-  svn_boolean_t done;
 } loc_context_t;
 
-
-static void
-push_state(loc_context_t *loc_ctx, loc_state_e state)
-{
-  loc_state_list_t *new_state;
-
-  if (!loc_ctx->free_state)
-    {
-      new_state = apr_palloc(loc_ctx->pool, sizeof(*loc_ctx->state));
-    }
-  else
-    {
-      new_state = loc_ctx->free_state;
-      loc_ctx->free_state = loc_ctx->free_state->prev;
-    }
-  new_state->state = state;
+#define D_ "DAV:"
+#define S_ SVN_XML_NAMESPACE
+static const svn_ra_serf__xml_transition_t getloc_ttable[] = {
+  { INITIAL, S_, "get-locations-report", REPORT,
+    FALSE, { NULL }, FALSE, FALSE },
 
-  /* Add it to the state chain. */
-  new_state->prev = loc_ctx->state;
-  loc_ctx->state = new_state;
-}
+  { REPORT, S_, "location", LOCATION,
+    FALSE, { "?rev", "?path", NULL }, FALSE, TRUE },
 
-static void pop_state(loc_context_t *loc_ctx)
-{
-  loc_state_list_t *free_state;
-  free_state = loc_ctx->state;
-  /* advance the current state */
-  loc_ctx->state = loc_ctx->state->prev;
-  free_state->prev = loc_ctx->free_state;
-  loc_ctx->free_state = free_state;
-}
+  { 0 }
+};
 
+
+/* Conforms to svn_ra_serf__xml_closed_t  */
 static svn_error_t *
-start_getloc(svn_ra_serf__xml_parser_t *parser,
-             svn_ra_serf__dav_props_t name,
-             const char **attrs,
-             apr_pool_t *scratch_pool)
+getloc_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)
 {
-  loc_context_t *loc_ctx = parser->user_data;
+  loc_context_t *loc_ctx = baton;
+  const char *revstr;
+  const char *path;
 
-  if (!loc_ctx->state && strcmp(name.name, "get-locations-report") == 0)
-    {
-      push_state(loc_ctx, REPORT);
-    }
-  else if (loc_ctx->state &&
-           loc_ctx->state->state == REPORT &&
-           strcmp(name.name, "location") == 0)
-    {
-      svn_revnum_t rev = SVN_INVALID_REVNUM;
-      const char *revstr, *path;
+  SVN_ERR_ASSERT(leaving_state == LOCATION);
 
-      revstr = svn_xml_get_attr_value("rev", attrs);
-      if (revstr)
-        {
-          rev = SVN_STR_TO_REV(revstr);
-        }
-
-      path = svn_xml_get_attr_value("path", attrs);
-
-      if (SVN_IS_VALID_REVNUM(rev) && path)
-        {
-          apr_hash_set(loc_ctx->paths,
-                       apr_pmemdup(loc_ctx->pool, &rev, sizeof(rev)),
-                       sizeof(rev),
-                       apr_pstrdup(loc_ctx->pool, path));
-        }
+  revstr = apr_hash_get(attrs, "rev", APR_HASH_KEY_STRING);
+  path = apr_hash_get(attrs, "path", APR_HASH_KEY_STRING);
+  if (revstr != NULL && path != NULL)
+    {
+      svn_revnum_t rev = SVN_STR_TO_REV(revstr);
+      apr_hash_set(loc_ctx->paths,
+                   apr_pmemdup(loc_ctx->pool, &rev, sizeof(rev)), sizeof(rev),
+                   apr_pstrdup(loc_ctx->pool, path));
     }
 
   return SVN_NO_ERROR;
 }
 
-static svn_error_t *
-end_getloc(svn_ra_serf__xml_parser_t *parser,
-           svn_ra_serf__dav_props_t name,
-           apr_pool_t *scratch_pool)
-{
-  loc_context_t *loc_ctx = parser->user_data;
-  loc_state_list_t *cur_state;
-
-  if (!loc_ctx->state)
-    {
-      return SVN_NO_ERROR;
-    }
-
-  cur_state = loc_ctx->state;
-
-  if (cur_state->state == REPORT &&
-      strcmp(name.name, "get-locations-report") == 0)
-    {
-      pop_state(loc_ctx);
-    }
-  else if (cur_state->state == LOCATION &&
-           strcmp(name.name, "location") == 0)
-    {
-      pop_state(loc_ctx);
-    }
-
-  return SVN_NO_ERROR;
-}
 
 /* Implements svn_ra_serf__request_body_delegate_t */
 static svn_error_t *
@@ -226,7 +156,7 @@ svn_ra_serf__get_locations(svn_ra_sessio
   loc_context_t *loc_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;
   svn_error_t *err;
 
@@ -235,7 +165,6 @@ svn_ra_serf__get_locations(svn_ra_sessio
   loc_ctx->path = path;
   loc_ctx->peg_revision = peg_revision;
   loc_ctx->location_revisions = location_revisions;
-  loc_ctx->done = FALSE;
   loc_ctx->paths = apr_hash_make(loc_ctx->pool);
 
   *locations = loc_ctx->paths;
@@ -245,9 +174,11 @@ svn_ra_serf__get_locations(svn_ra_sessio
                                       NULL /* url */, peg_revision,
                                       pool, pool));
 
-  handler = apr_pcalloc(pool, sizeof(*handler));
+  xmlctx = svn_ra_serf__xml_context_create(getloc_ttable,
+                                           NULL, getloc_closed, loc_ctx,
+                                           pool);
+  handler = svn_ra_serf__create_expat_handler(xmlctx, pool);
 
-  handler->handler_pool = pool;
   handler->method = "REPORT";
   handler->path = req_url;
   handler->body_delegate = create_get_locations_body;
@@ -256,20 +187,7 @@ svn_ra_serf__get_locations(svn_ra_sessio
   handler->conn = session->conns[0];
   handler->session = session;
 
-  parser_ctx = apr_pcalloc(pool, sizeof(*parser_ctx));
-
-  parser_ctx->pool = pool;
-  parser_ctx->user_data = loc_ctx;
-  parser_ctx->start = start_getloc;
-  parser_ctx->end = end_getloc;
-  parser_ctx->done = &loc_ctx->done;
-
-  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(&loc_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(handler->sline.code,

Modified: subversion/branches/ev2-export/subversion/libsvn_ra_serf/getlocationsegments.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_ra_serf/getlocationsegments.c?rev=1338209&r1=1338208&r2=1338209&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_ra_serf/getlocationsegments.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_ra_serf/getlocationsegments.c Mon May 14 14:07:45 2012
@@ -25,7 +25,6 @@
 
 
 #include <apr_uri.h>
-#include <expat.h>
 #include <serf.h>
 
 #include "svn_pools.h"
@@ -50,80 +49,60 @@ typedef struct gls_context_t {
   svn_location_segment_receiver_t receiver;
   void *receiver_baton;
 
-  /* subpool used only as long as a single receiver invocation */
-  apr_pool_t *subpool;
-
-  /* True iff we're looking at a child of the outer report tag */
-  svn_boolean_t inside_report;
-
-  svn_boolean_t done;
 } gls_context_t;
 
+enum {
+  INITIAL = 0,
+  REPORT,
+  SEGMENT
+};
+
+#define D_ "DAV:"
+#define S_ SVN_XML_NAMESPACE
+static const svn_ra_serf__xml_transition_t gls_ttable[] = {
+  { INITIAL, S_, "get-location-segments-report", REPORT,
+    FALSE, { NULL }, FALSE, FALSE },
 
-static svn_error_t *
-start_gls(svn_ra_serf__xml_parser_t *parser,
-          svn_ra_serf__dav_props_t name,
-          const char **attrs,
-          apr_pool_t *scratch_pool)
-{
-  gls_context_t *gls_ctx = parser->user_data;
+  { REPORT, S_, "location-segment", SEGMENT,
+    FALSE, { "?path", "range-start", "range-end", NULL }, FALSE, TRUE },
 
-  if ((! gls_ctx->inside_report)
-      && strcmp(name.name, "get-location-segments-report") == 0)
-    {
-      gls_ctx->inside_report = TRUE;
-    }
-  else if (gls_ctx->inside_report
-           && strcmp(name.name, "location-segment") == 0)
-    {
-      const char *rev_str;
-      svn_revnum_t range_start = SVN_INVALID_REVNUM;
-      svn_revnum_t range_end = SVN_INVALID_REVNUM;
-      const char *path = NULL;
-
-      path = svn_xml_get_attr_value("path", attrs);
-      rev_str = svn_xml_get_attr_value("range-start", attrs);
-      if (rev_str)
-        range_start = SVN_STR_TO_REV(rev_str);
-      rev_str = svn_xml_get_attr_value("range-end", attrs);
-      if (rev_str)
-        range_end = SVN_STR_TO_REV(rev_str);
-
-      if (SVN_IS_VALID_REVNUM(range_start) && SVN_IS_VALID_REVNUM(range_end))
-        {
-          svn_location_segment_t *segment = apr_pcalloc(gls_ctx->subpool,
-                                                        sizeof(*segment));
-          segment->path = path;
-          segment->range_start = range_start;
-          segment->range_end = range_end;
-          SVN_ERR(gls_ctx->receiver(segment,
-                                    gls_ctx->receiver_baton,
-                                    gls_ctx->subpool));
-          svn_pool_clear(gls_ctx->subpool);
-        }
-      else
-        {
-          return svn_error_create(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL,
-                                  _("Expected valid revision range"));
-        }
-    }
+  { 0 }
+};
 
-  return SVN_NO_ERROR;
-}
 
+/* Conforms to svn_ra_serf__xml_closed_t  */
 static svn_error_t *
-end_gls(svn_ra_serf__xml_parser_t *parser,
-        svn_ra_serf__dav_props_t name,
-        apr_pool_t *scratch_pool)
+gls_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)
 {
-  gls_context_t *gls_ctx = parser->user_data;
-
-  if (strcmp(name.name, "get-location-segments-report") == 0)
-    gls_ctx->inside_report = FALSE;
+  gls_context_t *gls_ctx = baton;
+  const char *path;
+  const char *start_str;
+  const char *end_str;
+  svn_location_segment_t segment;
+
+  SVN_ERR_ASSERT(leaving_state == SEGMENT);
+
+  path = apr_hash_get(attrs, "path", APR_HASH_KEY_STRING);
+  start_str = apr_hash_get(attrs, "range-start", APR_HASH_KEY_STRING);
+  end_str = apr_hash_get(attrs, "range-end", APR_HASH_KEY_STRING);
+
+  /* The transition table said these must exist.  */
+  SVN_ERR_ASSERT(start_str && end_str);
+
+  segment.path = path;  /* may be NULL  */
+  segment.range_start = SVN_STR_TO_REV(start_str);
+  segment.range_end = SVN_STR_TO_REV(end_str);
+  SVN_ERR(gls_ctx->receiver(&segment, gls_ctx->receiver_baton, scratch_pool));
 
   return SVN_NO_ERROR;
 }
 
+
 /* Implements svn_ra_serf__request_body_delegate_t */
 static svn_error_t *
 create_gls_body(serf_bucket_t **body_bkt,
@@ -180,7 +159,7 @@ svn_ra_serf__get_location_segments(svn_r
   gls_context_t *gls_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;
   svn_error_t *err;
 
@@ -191,18 +170,17 @@ svn_ra_serf__get_location_segments(svn_r
   gls_ctx->end_rev = end_rev;
   gls_ctx->receiver = receiver;
   gls_ctx->receiver_baton = receiver_baton;
-  gls_ctx->subpool = svn_pool_create(pool);
-  gls_ctx->inside_report = FALSE;
-  gls_ctx->done = FALSE;
 
   SVN_ERR(svn_ra_serf__get_stable_url(&req_url, NULL /* latest_revnum */,
                                       session, NULL /* conn */,
                                       NULL /* url */, peg_revision,
                                       pool, pool));
 
-  handler = apr_pcalloc(pool, sizeof(*handler));
+  xmlctx = svn_ra_serf__xml_context_create(gls_ttable,
+                                           NULL, gls_closed, gls_ctx,
+                                           pool);
+  handler = svn_ra_serf__create_expat_handler(xmlctx, pool);
 
-  handler->handler_pool = pool;
   handler->method = "REPORT";
   handler->path = req_url;
   handler->body_delegate = create_gls_body;
@@ -211,25 +189,7 @@ svn_ra_serf__get_location_segments(svn_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 = gls_ctx;
-  parser_ctx->start = start_gls;
-  parser_ctx->end = end_gls;
-  parser_ctx->done = &gls_ctx->done;
-
-  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(&gls_ctx->done, session, pool);
-
-  if (gls_ctx->inside_report)
-    err = svn_error_createf(SVN_ERR_RA_DAV_REQUEST_FAILED, err,
-                            _("Location segment report failed on '%s'@'%ld'"),
-                              path, peg_revision);
+  err = svn_ra_serf__context_run_one(handler, pool);
 
   err = svn_error_compose_create(
          svn_ra_serf__error_on_status(handler->sline.code,
@@ -237,8 +197,6 @@ svn_ra_serf__get_location_segments(svn_r
                                       handler->location),
          err);
 
-  svn_pool_destroy(gls_ctx->subpool);
-
   if (err && (err->apr_err == SVN_ERR_UNSUPPORTED_FEATURE))
     return svn_error_create(SVN_ERR_RA_NOT_IMPLEMENTED, err, NULL);
 

Modified: subversion/branches/ev2-export/subversion/libsvn_ra_serf/getlocks.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_ra_serf/getlocks.c?rev=1338209&r1=1338208&r2=1338209&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_ra_serf/getlocks.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_ra_serf/getlocks.c Mon May 14 14:07:45 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, 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->cdata = svn_stringbuf_create_empty(info->pool);
+  { LOCK, S_, "token", TOKEN,
+    TRUE, { NULL }, FALSE, TRUE },
 
-      parser->state->private = info;
-    }
-
-  return parser->state->private;
-}
+  { LOCK, S_, "owner", OWNER,
+    TRUE, { NULL }, FALSE, 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_, "comment", COMMENT,
+    TRUE, { NULL }, FALSE, TRUE },
 
-  state = parser->state->current_state;
+  { LOCK, S_, SVN_DAV__CREATIONDATE, CREATION_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);
-        }
-    }
+  { LOCK, S_, "expirationdate", EXPIRATION_DATE,
+    TRUE, { NULL }, FALSE, TRUE },
 
-  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,7 +234,7 @@ 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;
 
   req_url = svn_path_url_add_component2(session->session_url.path, path, pool);
@@ -336,37 +246,24 @@ 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->handler_pool = pool;
   handler->method = "REPORT";
   handler->path = req_url;
   handler->body_type = "text/xml";
   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;
-
   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/ev2-export/subversion/libsvn_ra_serf/locks.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_ra_serf/locks.c?rev=1338209&r1=1338208&r2=1338209&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_ra_serf/locks.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_ra_serf/locks.c Mon May 14 14:07:45 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;
@@ -72,240 +73,117 @@ typedef struct lock_info_t {
 
   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;
+
 } 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, 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,
-           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, 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,
-         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)
-    {
-      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)
+  if (leaving_state == TIMEOUT)
     {
-      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,
@@ -336,13 +214,6 @@ static svn_error_t *
 determine_error(svn_ra_serf__handler_t *handler,
                 svn_error_t *err)
 {
-  /* If we found an error in the response, then blend it in.  */
-  if (handler->server_error)
-    {
-      /* Client-side error takes precedence.  */
-      err = svn_error_compose_create(err, handler->server_error->error);
-    }
-  else
     {
       apr_status_t errcode;
 
@@ -353,9 +224,13 @@ determine_error(svn_ra_serf__handler_t *
       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, err,
+      err = svn_error_createf(errcode, NULL,
                               _("Lock request failed: %d %s"),
                               handler->sline.code,
                               handler->sline.reason);
@@ -372,8 +247,7 @@ 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;
+  lock_info_t *ctx = handler_baton;
 
   /* 403 (Forbidden) when a lock doesn't exist.
      423 (Locked) when a lock already exists.  */
@@ -410,8 +284,7 @@ handle_lock(serf_request_t *request,
       ctx->read_headers = TRUE;
     }
 
-  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 */
@@ -443,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;
 }
@@ -493,7 +366,7 @@ 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;
@@ -505,34 +378,29 @@ 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->handler_pool = pool;
   handler->method = "PROPFIND";
   handler->path = req_url;
   handler->body_type = "text/xml";
   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 = &handler->done;
-
   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;
 
   lock_ctx->handler = handler;
 
@@ -581,7 +449,7 @@ svn_ra_serf__lock(svn_ra_session_t *ra_s
        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;
@@ -602,32 +470,27 @@ 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->handler_pool = iterpool;
       handler->method = "LOCK";
       handler->path = req_url;
       handler->body_type = "text/xml";
       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 = &handler->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;
 

Modified: subversion/branches/ev2-export/subversion/libsvn_ra_serf/log.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_ra_serf/log.c?rev=1338209&r1=1338208&r2=1338209&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_ra_serf/log.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_ra_serf/log.c Mon May 14 14:07:45 2012
@@ -24,9 +24,6 @@
 
 
 #include <apr_uri.h>
-
-#include <expat.h>
-
 #include <serf.h>
 
 #include "svn_pools.h"

Modified: subversion/branches/ev2-export/subversion/libsvn_ra_serf/options.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_ra_serf/options.c?rev=1338209&r1=1338208&r2=1338209&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_ra_serf/options.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_ra_serf/options.c Mon May 14 14:07:45 2012
@@ -48,162 +48,68 @@
 /*
  * This enum represents the current state of our XML parsing for an OPTIONS.
  */
-typedef enum options_state_e {
+enum options_state_e {
+  INITIAL = 0,
   OPTIONS,
   ACTIVITY_COLLECTION,
   HREF
-} options_state_e;
-
-typedef struct options_state_list_t {
-  /* The current state that we are in now. */
-  options_state_e state;
-
-  /* The previous state we were in. */
-  struct options_state_list_t *prev;
-} options_state_list_t;
+};
 
 typedef struct options_context_t {
   /* pool to allocate memory from */
   apr_pool_t *pool;
 
-  /* Buffer for the activity-collection  */
-  svn_stringbuf_t *acbuf;
-  svn_boolean_t collect_cdata;
-
-  /* Current state we're in */
-  options_state_list_t *state;
-  options_state_list_t *free_state;
-
   /* Have we extracted options values from the headers already?  */
   svn_boolean_t headers_processed;
 
-  /* are we done? */
-  svn_boolean_t done;
-
   svn_ra_serf__session_t *session;
   svn_ra_serf__connection_t *conn;
   svn_ra_serf__handler_t *handler;
-  svn_ra_serf__xml_parser_t *parser_ctx;
+
+  svn_ra_serf__response_handler_t inner_handler;
+  void *inner_baton;
 
   const char *activity_collection;
   svn_revnum_t youngest_rev;
 
 } options_context_t;
 
+#define D_ "DAV:"
+#define S_ SVN_XML_NAMESPACE
+static const svn_ra_serf__xml_transition_t options_ttable[] = {
+  { INITIAL, D_, "options-response", OPTIONS,
+    FALSE, { NULL }, FALSE, FALSE },
 
-static void
-push_state(options_context_t *options_ctx, options_state_e state)
-{
-  options_state_list_t *new_state;
-
-  if (!options_ctx->free_state)
-    {
-      new_state = apr_palloc(options_ctx->pool, sizeof(*options_ctx->state));
-    }
-  else
-    {
-      new_state = options_ctx->free_state;
-      options_ctx->free_state = options_ctx->free_state->prev;
-    }
-  new_state->state = state;
+  { OPTIONS, D_, "activity-collection-set", ACTIVITY_COLLECTION,
+    FALSE, { NULL }, FALSE, FALSE },
 
-  /* Add it to the state chain. */
-  new_state->prev = options_ctx->state;
-  options_ctx->state = new_state;
-}
+  { ACTIVITY_COLLECTION, D_, "href", HREF,
+    TRUE, { NULL }, FALSE, TRUE },
 
-static void pop_state(options_context_t *options_ctx)
-{
-  options_state_list_t *free_state;
-  free_state = options_ctx->state;
-  /* advance the current state */
-  options_ctx->state = options_ctx->state->prev;
-  free_state->prev = options_ctx->free_state;
-  options_ctx->free_state = free_state;
-}
+  { 0 }
+};
 
-static svn_error_t *
-start_options(svn_ra_serf__xml_parser_t *parser,
-              svn_ra_serf__dav_props_t name,
-              const char **attrs,
-              apr_pool_t *scratch_pool)
-{
-  options_context_t *options_ctx = parser->user_data;
-
-  if (!options_ctx->state && strcmp(name.name, "options-response") == 0)
-    {
-      push_state(options_ctx, OPTIONS);
-    }
-  else if (!options_ctx->state)
-    {
-      /* Nothing to do. */
-      return SVN_NO_ERROR;
-    }
-  else if (options_ctx->state->state == OPTIONS &&
-           strcmp(name.name, "activity-collection-set") == 0)
-    {
-      push_state(options_ctx, ACTIVITY_COLLECTION);
-    }
-  else if (options_ctx->state->state == ACTIVITY_COLLECTION &&
-           strcmp(name.name, "href") == 0)
-    {
-      options_ctx->collect_cdata = TRUE;
-      push_state(options_ctx, HREF);
-    }
-
-  return SVN_NO_ERROR;
-}
 
+/* Conforms to svn_ra_serf__xml_closed_t  */
 static svn_error_t *
-end_options(svn_ra_serf__xml_parser_t *parser,
-            svn_ra_serf__dav_props_t name,
-            apr_pool_t *scratch_pool)
+options_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)
 {
-  options_context_t *options_ctx = parser->user_data;
-  options_state_list_t *cur_state;
-
-  if (!options_ctx->state)
-    {
-      return SVN_NO_ERROR;
-    }
+  options_context_t *opt_ctx = baton;
 
-  cur_state = options_ctx->state;
+  SVN_ERR_ASSERT(leaving_state == HREF);
+  SVN_ERR_ASSERT(cdata != NULL);
 
-  if (cur_state->state == OPTIONS &&
-      strcmp(name.name, "options-response") == 0)
-    {
-      pop_state(options_ctx);
-    }
-  else if (cur_state->state == ACTIVITY_COLLECTION &&
-           strcmp(name.name, "activity-collection-set") == 0)
-    {
-      pop_state(options_ctx);
-    }
-  else if (cur_state->state == HREF &&
-           strcmp(name.name, "href") == 0)
-    {
-      options_ctx->collect_cdata = FALSE;
-      options_ctx->activity_collection =
-        svn_urlpath__canonicalize(options_ctx->acbuf->data, options_ctx->pool);
-      pop_state(options_ctx);
-    }
+  opt_ctx->activity_collection = svn_urlpath__canonicalize(cdata->data,
+                                                           opt_ctx->pool);
 
   return SVN_NO_ERROR;
 }
 
-static svn_error_t *
-cdata_options(svn_ra_serf__xml_parser_t *parser,
-              const char *data,
-              apr_size_t len,
-              apr_pool_t *scratch_pool)
-{
-  options_context_t *ctx = parser->user_data;
-
-  if (ctx->collect_cdata)
-    svn_stringbuf_appendbytes(ctx->acbuf, data, len);
-
-  return SVN_NO_ERROR;
-}
 
 static svn_error_t *
 create_options_body(serf_bucket_t **body_bkt,
@@ -394,8 +300,7 @@ options_response_handler(serf_request_t 
     }
 
   /* Execute the 'real' response handler to XML-parse the repsonse body. */
-  return svn_ra_serf__handle_xml_parser(request, response,
-                                        opt_ctx->parser_ctx, pool);
+  return opt_ctx->inner_handler(request, response, opt_ctx->inner_baton, pool);
 }
 
 
@@ -406,22 +311,21 @@ create_options_req(options_context_t **o
                    apr_pool_t *pool)
 {
   options_context_t *new_ctx;
+  svn_ra_serf__xml_context_t *xmlctx;
   svn_ra_serf__handler_t *handler;
-  svn_ra_serf__xml_parser_t *parser_ctx;
 
   new_ctx = apr_pcalloc(pool, sizeof(*new_ctx));
-
   new_ctx->pool = pool;
-
-  new_ctx->acbuf = svn_stringbuf_create_empty(pool);
-  new_ctx->youngest_rev = SVN_INVALID_REVNUM;
-
   new_ctx->session = session;
   new_ctx->conn = conn;
 
-  handler = apr_pcalloc(pool, sizeof(*handler));
+  new_ctx->youngest_rev = SVN_INVALID_REVNUM;
+
+  xmlctx = svn_ra_serf__xml_context_create(options_ttable,
+                                           NULL, options_closed, new_ctx,
+                                           pool);
+  handler = svn_ra_serf__create_expat_handler(xmlctx, pool);
 
-  handler->handler_pool = pool;
   handler->method = "OPTIONS";
   handler->path = session->session_url.path;
   handler->body_delegate = create_options_body;
@@ -429,23 +333,13 @@ create_options_req(options_context_t **o
   handler->conn = conn;
   handler->session = session;
 
-  parser_ctx = apr_pcalloc(pool, sizeof(*parser_ctx));
-
-  parser_ctx->pool = pool;
-  parser_ctx->user_data = new_ctx;
-  parser_ctx->start = start_options;
-  parser_ctx->end = end_options;
-  parser_ctx->cdata = cdata_options;
-  parser_ctx->done = &new_ctx->done;
-
   new_ctx->handler = handler;
-  new_ctx->parser_ctx = parser_ctx;
 
+  new_ctx->inner_handler = handler->response_handler;
+  new_ctx->inner_baton = handler->response_baton;
   handler->response_handler = options_response_handler;
   handler->response_baton = new_ctx;
 
-  svn_ra_serf__request_create(handler);
-
   *opt_ctx = new_ctx;
 
   return SVN_NO_ERROR;
@@ -463,8 +357,7 @@ svn_ra_serf__v2_get_youngest_revnum(svn_
   SVN_ERR_ASSERT(SVN_RA_SERF__HAVE_HTTPV2_SUPPORT(session));
 
   SVN_ERR(create_options_req(&opt_ctx, session, conn, scratch_pool));
-  SVN_ERR(svn_ra_serf__context_run_wait(&opt_ctx->done, session,
-                                        scratch_pool));
+  SVN_ERR(svn_ra_serf__context_run_one(opt_ctx->handler, scratch_pool));
 
   *youngest = opt_ctx->youngest_rev;
 
@@ -484,8 +377,7 @@ svn_ra_serf__v1_get_activity_collection(
   SVN_ERR_ASSERT(!SVN_RA_SERF__HAVE_HTTPV2_SUPPORT(session));
 
   SVN_ERR(create_options_req(&opt_ctx, session, conn, scratch_pool));
-  SVN_ERR(svn_ra_serf__context_run_wait(&opt_ctx->done, session,
-                                        scratch_pool));
+  SVN_ERR(svn_ra_serf__context_run_one(opt_ctx->handler, scratch_pool));
 
   *activity_url = apr_pstrdup(result_pool, opt_ctx->activity_collection);
 
@@ -508,7 +400,7 @@ svn_ra_serf__exchange_capabilities(svn_r
   /* This routine automatically fills in serf_sess->capabilities */
   SVN_ERR(create_options_req(&opt_ctx, serf_sess, serf_sess->conns[0], pool));
 
-  err = svn_ra_serf__context_run_wait(&opt_ctx->done, serf_sess, pool);
+  err = svn_ra_serf__context_run_one(opt_ctx->handler, pool);
 
   /* If our caller cares about server redirections, and our response
      carries such a thing, report as much.  We'll disregard ERR --

Modified: subversion/branches/ev2-export/subversion/libsvn_ra_serf/property.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_ra_serf/property.c?rev=1338209&r1=1338208&r2=1338209&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_ra_serf/property.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_ra_serf/property.c Mon May 14 14:07:45 2012
@@ -1088,8 +1088,6 @@ get_baseline_info(const char **bc_url,
      revision (if needed) with an OPTIONS request.  */
   if (SVN_RA_SERF__HAVE_HTTPV2_SUPPORT(session))
     {
-      svn_revnum_t actual_revision;
-
       if (SVN_IS_VALID_REVNUM(revision))
         {
           *revnum_used = revision;
@@ -1098,7 +1096,7 @@ get_baseline_info(const char **bc_url,
         {
           SVN_ERR(svn_ra_serf__v2_get_youngest_revnum(
                     revnum_used, conn, pool));
-          if (! SVN_IS_VALID_REVNUM(actual_revision))
+          if (! SVN_IS_VALID_REVNUM(*revnum_used))
             return svn_error_create(SVN_ERR_RA_DAV_OPTIONS_REQ_FAILED, NULL,
                                     _("The OPTIONS response did not include "
                                       "the youngest revision"));

Modified: subversion/branches/ev2-export/subversion/libsvn_ra_serf/ra_serf.h
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_ra_serf/ra_serf.h?rev=1338209&r1=1338208&r2=1338209&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_ra_serf/ra_serf.h (original)
+++ subversion/branches/ev2-export/subversion/libsvn_ra_serf/ra_serf.h Mon May 14 14:07:45 2012
@@ -26,7 +26,7 @@
 
 
 #include <serf.h>
-#include <expat.h>
+#include <expat.h>  /* for XML_Parser  */
 #include <apr_uri.h>
 
 #include "svn_types.h"
@@ -608,6 +608,160 @@ struct svn_ra_serf__xml_parser_t {
   apr_off_t read_size; /* Number of bytes read from response */
 };
 
+
+/* v2 of the XML parsing functions  */
+
+/* The XML parsing context.  */
+typedef struct svn_ra_serf__xml_context_t svn_ra_serf__xml_context_t;
+
+
+/* An opaque structure for the XML parse element/state.  */
+typedef struct svn_ra_serf__xml_estate_t svn_ra_serf__xml_estate_t;
+
+/* Called just after the parser moves into ENTERED_STATE.  */
+typedef svn_error_t *
+(*svn_ra_serf__xml_opened_t)(svn_ra_serf__xml_estate_t *xes,
+                             void *baton,
+                             int entered_state,
+                             apr_pool_t *scratch_pool);
+
+
+/* Called just before the parser leaves LEAVING_STATE.
+
+   If cdata collection was enabled for this state, then CDATA will be
+   non-NULL and contain the collected cdata.
+
+   If attribute collection was enabled for this state, then ATTRS will
+   contain the attributes collected for this element only. Use
+   svn_ra_serf__xml_gather_since() to gather up data from outer states.
+   ATTRS is char* -> char*.
+
+   Temporary allocations may be made in SCRATCH_POOL.  */
+typedef svn_error_t *
+(*svn_ra_serf__xml_closed_t)(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);
+
+
+/* State transition table.
+
+   When the XML Context is constructed, it is in state 0. User states are
+   positive integers.
+
+   In a list of transitions, use { 0 } to indicate the end. Specifically,
+   the code looks for NS == NULL.
+
+   ### more docco
+*/
+typedef struct svn_ra_serf__xml_transition_t {
+  /* This transition applies when in this state  */
+  int from_state;
+
+  /* And when this tag is observed  */
+  const char *ns;
+  const char *name;
+
+  /* Moving to this state  */
+  int to_state;
+
+  /* Should the cdata of NAME be collected?  */
+  svn_boolean_t collect_cdata;
+
+  /* Which attributes of NAME should be collected? Terminate with NULL.
+     Maximum of 10 attributes may be collected. Note that attribute
+     namespaces are ignored at this time.
+
+     Attribute names beginning with "?" are optional. Other names must
+     exist on the element, or SVN_ERR_XML_ATTRIB_NOT_FOUND will be raised.  */
+  const char *collect_attrs[11];
+
+  /* When NAME is opened, should the callback be invoked?  */
+  svn_boolean_t custom_open;
+
+  /* When NAME is closed, should the callback be invoked?  */
+  svn_boolean_t custom_close;
+
+} svn_ra_serf__xml_transition_t;
+
+
+svn_ra_serf__xml_context_t *
+svn_ra_serf__xml_context_create(
+  const svn_ra_serf__xml_transition_t *ttable,
+  svn_ra_serf__xml_opened_t opened_cb,
+  svn_ra_serf__xml_closed_t closed_cb,
+  void *baton,
+  apr_pool_t *result_pool);
+
+
+/* Construct a handler with the response function/baton set up to parse
+   a response body using the given XML context. The handler and its
+   internal structures are allocated in RESULT_POOL.
+
+   This also initializes HANDLER_POOL to the given RESULT_POOL.  */
+svn_ra_serf__handler_t *
+svn_ra_serf__create_expat_handler(svn_ra_serf__xml_context_t *xmlctx,
+                                  apr_pool_t *result_pool);
+
+
+/* Allocated within XES->STATE_POOL. Changes are not allowd. Make a deep
+   copy, as appropriate.
+
+   The resulting hash maps char* names to char* values.  */
+apr_hash_t *
+svn_ra_serf__xml_gather_since(svn_ra_serf__xml_estate_t *xes,
+                              int stop_state);
+
+
+/* Attach the NAME/VALUE pair onto this/parent state identified by STATE.
+   The name and value will be copied into the target state's pool.
+
+   These values will be available to the CLOSED_CB for the target state,
+   or part of the gathered state via xml_gather_since().
+
+   Typically, this function is used by a child state's close callback,
+   or within an opening callback to store additional data.
+
+   Note: if the state is not found, then a programmer error has occurred,
+   so the function will invoke SVN_ERR_MALFUNCTION().  */
+void
+svn_ra_serf__xml_note(svn_ra_serf__xml_estate_t *xes,
+                      int state,
+                      const char *name,
+                      const char *value);
+
+
+/* Returns XES->STATE_POOL for allocating structures that should live
+   as long as the state identified by XES.  */
+apr_pool_t *
+svn_ra_serf__xml_state_pool(svn_ra_serf__xml_estate_t *xes);
+
+
+/* Any XML parser may be used. When an opening tag is seen, call this
+   function to feed the information into XMLCTX.  */
+svn_error_t *
+svn_ra_serf__xml_cb_start(svn_ra_serf__xml_context_t *xmlctx,
+                          const char *raw_name,
+                          const char *const *attrs);
+
+
+/* When a close tag is seen, call this function to feed the information
+   into XMLCTX.  */
+svn_error_t *
+svn_ra_serf__xml_cb_end(svn_ra_serf__xml_context_t *xmlctx,
+                        const char *raw_name);
+
+
+/* When cdata is parsed by the wrapping XML parser, call this function to
+   feed the cdata into the XMLCTX.  */
+svn_error_t *
+svn_ra_serf__xml_cb_cdata(svn_ra_serf__xml_context_t *xmlctx,
+                          const char *data,
+                          apr_size_t len);
+
+
 /*
  * Parses a server-side error message into a local Subversion error.
  */
@@ -814,12 +968,12 @@ svn_ra_serf__add_cdata_len_buckets(serf_
  * Look up the @a attrs array for namespace definitions and add each one
  * to the @a ns_list of namespaces.
  *
- * New namespaces will be allocated in @a pool.
+ * New namespaces will be allocated in RESULT_POOL.
  */
 void
 svn_ra_serf__define_ns(svn_ra_serf__ns_t **ns_list,
-                       const char **attrs,
-                       apr_pool_t *pool);
+                       const char *const *attrs,
+                       apr_pool_t *result_pool);
 
 /*
  * Look up @a name in the @a ns_list list for previously declared namespace
@@ -830,7 +984,7 @@ svn_ra_serf__define_ns(svn_ra_serf__ns_t
  */
 void
 svn_ra_serf__expand_ns(svn_ra_serf__dav_props_t *returned_prop_name,
-                       svn_ra_serf__ns_t *ns_list,
+                       const svn_ra_serf__ns_t *ns_list,
                        const char *name);
 
 

Modified: subversion/branches/ev2-export/subversion/libsvn_ra_serf/replay.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_ra_serf/replay.c?rev=1338209&r1=1338208&r2=1338209&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_ra_serf/replay.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_ra_serf/replay.c Mon May 14 14:07:45 2012
@@ -24,9 +24,6 @@
 
 
 #include <apr_uri.h>
-
-#include <expat.h>
-
 #include <serf.h>
 
 #include "svn_pools.h"

Modified: subversion/branches/ev2-export/subversion/libsvn_ra_serf/serf.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_ra_serf/serf.c?rev=1338209&r1=1338208&r2=1338209&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_ra_serf/serf.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_ra_serf/serf.c Mon May 14 14:07:45 2012
@@ -27,9 +27,6 @@
 #include <apr_want.h>
 
 #include <apr_uri.h>
-
-#include <expat.h>
-
 #include <serf.h>
 
 #include "svn_pools.h"

Modified: subversion/branches/ev2-export/subversion/libsvn_ra_serf/util.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_ra_serf/util.c?rev=1338209&r1=1338208&r2=1338209&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_ra_serf/util.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_ra_serf/util.c Mon May 14 14:07:45 2012
@@ -33,6 +33,8 @@
 #include <serf.h>
 #include <serf_bucket_types.h>
 
+#include <expat.h>
+
 #include "svn_dirent_uri.h"
 #include "svn_path.h"
 #include "svn_private_config.h"
@@ -56,6 +58,17 @@
 #define XML_STATUS_ERROR 0
 #endif
 
+#ifndef XML_VERSION_AT_LEAST
+#define XML_VERSION_AT_LEAST(major,minor,patch)                  \
+(((major) < XML_MAJOR_VERSION)                                       \
+ || ((major) == XML_MAJOR_VERSION && (minor) < XML_MINOR_VERSION)    \
+ || ((major) == XML_MAJOR_VERSION && (minor) == XML_MINOR_VERSION && \
+     (patch) <= XML_MICRO_VERSION))
+#endif /* APR_VERSION_AT_LEAST */
+
+#if XML_VERSION_AT_LEAST(1, 95, 8)
+#define EXPAT_HAS_STOPPARSER
+#endif
 
 /* Read/write chunks of this size into the spillbuf.  */
 #define PARSE_CHUNK_SIZE 8000
@@ -80,6 +93,19 @@ struct svn_ra_serf__pending_t {
                              && svn_spillbuf__get_size((p)->buf) != 0)
 
 
+struct expat_ctx_t {
+  svn_ra_serf__xml_context_t *xmlctx;
+  XML_Parser parser;
+  svn_ra_serf__handler_t *handler;
+
+  svn_error_t *inner_error;
+
+  /* Do not use this pool for allocation. It is merely recorded for running
+     the cleanup handler.  */
+  apr_pool_t *cleanup_pool;
+};
+
+
 static const apr_uint32_t serf_failure_map[][2] =
 {
   { SERF_SSL_CERT_NOTYETVALID,   SVN_AUTH_SSL_NOTYETVALID },
@@ -737,14 +763,21 @@ svn_error_t *
 svn_ra_serf__context_run_one(svn_ra_serf__handler_t *handler,
                              apr_pool_t *scratch_pool)
 {
+  svn_error_t *err;
+
   /* Create a serf request based on HANDLER.  */
   svn_ra_serf__request_create(handler);
 
   /* Wait until the response logic marks its DONE status.  */
-  return svn_error_trace(svn_ra_serf__context_run_wait(
-                           &handler->done,
-                           handler->session,
-                           scratch_pool));
+  err = svn_ra_serf__context_run_wait(&handler->done, handler->session,
+                                      scratch_pool);
+  if (handler->server_error)
+    {
+      err = svn_error_compose_create(err, handler->server_error->error);
+      handler->server_error = NULL;
+    }
+
+  return svn_error_trace(err);
 }
 
 
@@ -2247,3 +2280,175 @@ svn_ra_serf__register_editor_shim_callba
   session->shim_callbacks = callbacks;
   return SVN_NO_ERROR;
 }
+
+
+/* Conforms to Expat's XML_StartElementHandler  */
+static void
+expat_start(void *userData, const char *raw_name, const char **attrs)
+{
+  struct expat_ctx_t *ectx = userData;
+
+  if (ectx->inner_error != NULL)
+    return;
+
+  ectx->inner_error = svn_error_trace(
+                        svn_ra_serf__xml_cb_start(ectx->xmlctx,
+                                                  raw_name, attrs));
+
+#ifdef EXPAT_HAS_STOPPARSER
+  if (ectx->inner_error)
+    (void) XML_StopParser(ectx->parser, 0 /* resumable */);
+#endif
+}
+
+
+/* Conforms to Expat's XML_EndElementHandler  */
+static void
+expat_end(void *userData, const char *raw_name)
+{
+  struct expat_ctx_t *ectx = userData;
+
+  if (ectx->inner_error != NULL)
+    return;
+
+  ectx->inner_error = svn_error_trace(
+                        svn_ra_serf__xml_cb_end(ectx->xmlctx, raw_name));
+
+#ifdef EXPAT_HAS_STOPPARSER
+  if (ectx->inner_error)
+    (void) XML_StopParser(ectx->parser, 0 /* resumable */);
+#endif
+}
+
+
+/* Conforms to Expat's XML_CharacterDataHandler  */
+static void
+expat_cdata(void *userData, const char *data, int len)
+{
+  struct expat_ctx_t *ectx = userData;
+
+  if (ectx->inner_error != NULL)
+    return;
+
+  ectx->inner_error = svn_error_trace(
+                        svn_ra_serf__xml_cb_cdata(ectx->xmlctx, data, len));
+
+#ifdef EXPAT_HAS_STOPPARSER
+  if (ectx->inner_error)
+    (void) XML_StopParser(ectx->parser, 0 /* resumable */);
+#endif
+}
+
+
+/* Implements svn_ra_serf__response_handler_t */
+static svn_error_t *
+expat_response_handler(serf_request_t *request,
+                       serf_bucket_t *response,
+                       void *baton,
+                       apr_pool_t *scratch_pool)
+{
+  struct expat_ctx_t *ectx = baton;
+
+  SVN_ERR_ASSERT(ectx->parser != NULL);
+
+  /* ### should we bail on anything < 200 or >= 300 ??
+     ### actually: < 200 should really be handled by the core.  */
+  if (ectx->handler->sline.code == 404)
+    {
+      /* By deferring to expect_empty_body(), it will make a choice on
+         how to handle the body. Whatever the decision, the core handler
+         will take over, and we will not be called again.  */
+      return svn_error_trace(svn_ra_serf__expect_empty_body(
+                               request, response, ectx->handler,
+                               scratch_pool));
+    }
+
+  while (1)
+    {
+      apr_status_t status;
+      const char *data;
+      apr_size_t len;
+      int expat_status;
+
+      status = serf_bucket_read(response, PARSE_CHUNK_SIZE, &data, &len);
+      if (SERF_BUCKET_READ_ERROR(status))
+        return svn_error_wrap_apr(status, NULL);
+
+#if 0
+      /* ### move restart/skip into the core handler  */
+      ectx->handler->read_size += len;
+#endif
+
+      /* ### move PAUSED behavior to a new response handler that can feed
+         ### an inner handler, or can pause for a while.  */
+
+      /* ### should we have an IGNORE_ERRORS flag like the v1 parser?  */
+
+      expat_status = XML_Parse(ectx->parser, data, (int)len, 0 /* isFinal */);
+      if (expat_status == XML_STATUS_ERROR)
+        return svn_error_createf(SVN_ERR_XML_MALFORMED, NULL,
+                                 _("The %s response contains invalid XML"
+                                   " (%d %s)"),
+                                 ectx->handler->method,
+                                 ectx->handler->sline.code,
+                                 ectx->handler->sline.reason);
+
+      /* Was an error dropped off for us?  */
+      if (ectx->inner_error)
+        {
+          apr_pool_cleanup_run(ectx->cleanup_pool, &ectx->parser,
+                               xml_parser_cleanup);
+          return svn_error_trace(ectx->inner_error);
+        }
+
+      /* The parsing went fine. What has the bucket told us?  */
+
+      if (APR_STATUS_IS_EAGAIN(status))
+        return svn_error_wrap_apr(status, NULL);
+
+      if (APR_STATUS_IS_EOF(status))
+        {
+          /* Tell expat we've reached the end of the content. Ignore the
+             return status. We just don't care.  */
+          (void) XML_Parse(ectx->parser, NULL, 0, 1 /* isFinal */);
+
+          apr_pool_cleanup_run(ectx->cleanup_pool, &ectx->parser,
+                               xml_parser_cleanup);
+
+          /* ### should check XMLCTX to see if it has returned to the
+             ### INITIAL state. we may have ended early...  */
+
+          return svn_error_wrap_apr(status, NULL);
+        }
+    }
+
+  /* NOTREACHED */
+}
+
+
+svn_ra_serf__handler_t *
+svn_ra_serf__create_expat_handler(svn_ra_serf__xml_context_t *xmlctx,
+                                  apr_pool_t *result_pool)
+{
+  svn_ra_serf__handler_t *handler;
+  struct expat_ctx_t *ectx;
+
+  ectx = apr_pcalloc(result_pool, sizeof(*ectx));
+  ectx->xmlctx = xmlctx;
+  ectx->parser = XML_ParserCreate(NULL);
+  apr_pool_cleanup_register(result_pool, &ectx->parser,
+                            xml_parser_cleanup, apr_pool_cleanup_null);
+  XML_SetUserData(ectx->parser, ectx);
+  XML_SetElementHandler(ectx->parser, expat_start, expat_end);
+  XML_SetCharacterDataHandler(ectx->parser, expat_cdata);
+
+
+  handler = apr_pcalloc(result_pool, sizeof(*handler));
+  handler->handler_pool = result_pool;
+  handler->response_handler = expat_response_handler;
+  handler->response_baton = ectx;
+
+  ectx->handler = handler;
+
+  return handler;
+}