subversion-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From julianf...@apache.org
Subject svn commit: r1515362 [6/13] - in /subversion/branches/move-tracking-1: ./ build/ build/ac-macros/ build/generator/ build/generator/templates/ notes/tree-conflicts/ subversion/bindings/cxxhl/include/ subversion/bindings/cxxhl/include/svncxxhl/ subversio...
Date Mon, 19 Aug 2013 11:21:06 GMT
Modified: subversion/branches/move-tracking-1/subversion/libsvn_ra_serf/replay.c
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-1/subversion/libsvn_ra_serf/replay.c?rev=1515362&r1=1515361&r2=1515362&view=diff
==============================================================================
--- subversion/branches/move-tracking-1/subversion/libsvn_ra_serf/replay.c (original)
+++ subversion/branches/move-tracking-1/subversion/libsvn_ra_serf/replay.c Mon Aug 19 11:21:01 2013
@@ -29,6 +29,7 @@
 #include "svn_pools.h"
 #include "svn_ra.h"
 #include "svn_dav.h"
+#include "svn_hash.h"
 #include "svn_xml.h"
 #include "../libsvn_ra/ra_loader.h"
 #include "svn_config.h"
@@ -46,55 +47,92 @@
  * This enum represents the current state of our XML parsing.
  */
 typedef enum replay_state_e {
-  NONE = 0,
-  REPORT,
-  OPEN_DIR,
-  ADD_DIR,
-  OPEN_FILE,
-  ADD_FILE,
-  DELETE_ENTRY,
-  APPLY_TEXTDELTA,
-  CHANGE_PROP
+  INITIAL = XML_STATE_INITIAL,
+
+  REPLAY_REPORT,
+  REPLAY_TARGET_REVISION,
+  REPLAY_OPEN_ROOT,
+  REPLAY_OPEN_DIRECTORY,
+  REPLAY_OPEN_FILE,
+  REPLAY_ADD_DIRECTORY,
+  REPLAY_ADD_FILE,
+  REPLAY_DELETE_ENTRY,
+  REPLAY_CLOSE_FILE,
+  REPLAY_CLOSE_DIRECTORY,
+  REPLAY_CHANGE_DIRECTORY_PROP,
+  REPLAY_CHANGE_FILE_PROP,
+  REPLAY_APPLY_TEXTDELTA,
 } replay_state_e;
 
-typedef struct replay_info_t replay_info_t;
+#define S_ SVN_XML_NAMESPACE
+static const svn_ra_serf__xml_transition_t replay_ttable[] = {
+  { INITIAL, S_, "editor-report", REPLAY_REPORT,
+    FALSE, { NULL }, TRUE },
 
-struct replay_info_t {
-  apr_pool_t *pool;
+  /* Replay just throws every operation as xml element directly
+     in the replay report, so we can't really use the nice exit
+     handling of the transition parser to handle clean callbacks */
 
-  void *baton;
-  svn_stream_t *stream;
+  { REPLAY_REPORT, S_, "target-revision", REPLAY_TARGET_REVISION,
+    FALSE, { "rev", NULL }, TRUE },
 
-  replay_info_t *parent;
-};
+  { REPLAY_REPORT, S_, "open-root", REPLAY_OPEN_ROOT,
+    FALSE, { "rev", NULL }, TRUE },
 
-typedef svn_error_t *
-(*change_prop_t)(void *baton,
-                 const char *name,
-                 const svn_string_t *value,
-                 apr_pool_t *pool);
+  { REPLAY_REPORT, S_, "open-directory", REPLAY_OPEN_DIRECTORY,
+    FALSE, { "name", "rev", NULL }, TRUE },
 
-typedef struct prop_info_t {
-  apr_pool_t *pool;
+  { REPLAY_REPORT, S_, "open-file", REPLAY_OPEN_FILE,
+    FALSE, { "name", "rev", NULL }, TRUE },
 
-  change_prop_t change;
+  { REPLAY_REPORT, S_, "add-directory", REPLAY_ADD_DIRECTORY,
+    FALSE, { "name", "?copyfrom-path", "?copyfrom-rev", NULL}, TRUE },
 
-  const char *name;
-  svn_boolean_t del_prop;
+  { REPLAY_REPORT, S_, "add-file", REPLAY_ADD_FILE,
+    FALSE, { "name", "?copyfrom-path", "?copyfrom-rev", NULL}, TRUE },
 
-  svn_stringbuf_t *prop_value;
+  { REPLAY_REPORT, S_, "delete-entry", REPLAY_DELETE_ENTRY,
+    FALSE, { "name", "rev", NULL }, TRUE },
 
-  replay_info_t *parent;
-} prop_info_t;
+  { REPLAY_REPORT, S_, "close-file", REPLAY_CLOSE_FILE,
+    FALSE, { "?checksum", NULL }, TRUE },
 
-typedef struct replay_context_t {
-  apr_pool_t *src_rev_pool;
-  apr_pool_t *dst_rev_pool;
-  /*file_pool is cleared after completion of each file. */
-  apr_pool_t *file_pool;
+  { REPLAY_REPORT, S_, "close-directory", REPLAY_CLOSE_DIRECTORY,
+    FALSE, { NULL }, TRUE },
 
-  /* Are we done fetching this file? */
-  svn_boolean_t done;
+  { REPLAY_REPORT, S_, "change-dir-prop", REPLAY_CHANGE_DIRECTORY_PROP,
+    TRUE, { "name", "?del", NULL }, TRUE },
+
+  { REPLAY_REPORT, S_, "change-file-prop", REPLAY_CHANGE_FILE_PROP,
+    TRUE, { "name", "?del", NULL }, TRUE },
+
+  { REPLAY_REPORT, S_, "apply-textdelta", REPLAY_APPLY_TEXTDELTA,
+    FALSE, { "?checksum", NULL }, TRUE },
+
+  { 0 }
+};
+
+/* Per directory/file state */
+typedef struct replay_node_t {
+  apr_pool_t *pool; /* pool allocating this node's data */
+  svn_boolean_t file; /* file or dir */
+
+  void *baton; /* node baton */
+  svn_stream_t *stream; /* stream while handling txdata */
+
+  struct replay_node_t *parent; /* parent node or NULL */
+} replay_node_t;
+
+/* Per revision replay report state */
+typedef struct revision_report_t {
+  apr_pool_t *pool; /* per revision pool */
+
+  struct replay_node_t *current_node;
+  struct replay_node_t *root_node;
+
+  /* Are we done fetching this file?
+     Handles book-keeping in multi-report case */
+  svn_boolean_t *done;
   svn_ra_serf__list_t **done_list;
   svn_ra_serf__list_t done_item;
 
@@ -126,81 +164,33 @@ typedef struct replay_context_t {
   apr_hash_t *revs_props;
   apr_hash_t *props;
 
-  /* Keep a reference to the XML parser ctx to report any errors. */
-  svn_ra_serf__xml_parser_t *parser_ctx;
-
   /* Handlers for the PROPFIND and REPORT for the current revision. */
   svn_ra_serf__handler_t *propfind_handler;
   svn_ra_serf__handler_t *report_handler;
 
-} replay_context_t;
-
-
-static void *
-push_state(svn_ra_serf__xml_parser_t *parser,
-           replay_context_t *replay_ctx,
-           replay_state_e state)
-{
-  svn_ra_serf__xml_push_state(parser, state);
-
-  if (state == OPEN_DIR || state == ADD_DIR ||
-      state == OPEN_FILE || state == ADD_FILE)
-    {
-      replay_info_t *info;
-
-      info = apr_palloc(replay_ctx->dst_rev_pool, sizeof(*info));
-
-      info->pool = replay_ctx->dst_rev_pool;
-      info->parent = parser->state->private;
-      info->baton = NULL;
-      info->stream = NULL;
-
-      parser->state->private = info;
-    }
-  else if (state == CHANGE_PROP)
-    {
-      prop_info_t *info;
-
-      info = apr_pcalloc(replay_ctx->dst_rev_pool, sizeof(*info));
-
-      info->pool = replay_ctx->dst_rev_pool;
-      info->parent = parser->state->private;
-      info->prop_value = svn_stringbuf_create_empty(info->pool);
-
-      parser->state->private = info;
-    }
-
-  return parser->state->private;
-}
+} revision_report_t;
 
+/* Conforms to svn_ra_serf__xml_opened_t */
 static svn_error_t *
-start_replay(svn_ra_serf__xml_parser_t *parser,
-             svn_ra_serf__dav_props_t name,
-             const char **attrs,
-             apr_pool_t *scratch_pool)
+replay_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)
 {
-  replay_context_t *ctx = parser->user_data;
-  replay_state_e state;
-
-  state = parser->state->current_state;
+  struct revision_report_t *ctx = baton;
 
-  if (state == NONE &&
-      strcmp(name.name, "editor-report") == 0)
+  if (entered_state == REPLAY_REPORT)
     {
-      push_state(parser, ctx, REPORT);
-
       /* Before we can continue, we need the revision properties. */
       SVN_ERR_ASSERT(!ctx->propfind_handler || ctx->propfind_handler->done);
 
       /* Create a pool for the commit editor. */
-      ctx->dst_rev_pool = svn_pool_create(ctx->src_rev_pool);
-      ctx->file_pool = svn_pool_create(ctx->dst_rev_pool);
-
       SVN_ERR(svn_ra_serf__select_revprops(&ctx->props,
                                            ctx->revprop_target,
                                            ctx->revprop_rev,
                                            ctx->revs_props,
-                                           ctx->dst_rev_pool,
+                                           ctx->pool,
                                            scratch_pool));
 
       if (ctx->revstart_func)
@@ -208,382 +198,298 @@ start_replay(svn_ra_serf__xml_parser_t *
           SVN_ERR(ctx->revstart_func(ctx->revision, ctx->replay_baton,
                                      &ctx->editor, &ctx->editor_baton,
                                      ctx->props,
-                                     ctx->dst_rev_pool));
+                                     ctx->pool));
         }
     }
-  else if (state == REPORT &&
-           strcmp(name.name, "target-revision") == 0)
+  else if (entered_state == REPLAY_APPLY_TEXTDELTA)
     {
-      const char *rev;
-
-      rev = svn_xml_get_attr_value("rev", attrs);
-      if (!rev)
-        {
-          return svn_error_create(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL,
-                    _("Missing revision attr in target-revision element"));
-        }
-
-      SVN_ERR(ctx->editor->set_target_revision(ctx->editor_baton,
-                                               SVN_STR_TO_REV(rev),
-                                               scratch_pool));
+       struct replay_node_t *node = ctx->current_node;
+       apr_hash_t *attrs;
+       const char *checksum;
+       svn_txdelta_window_handler_t handler;
+       void *handler_baton;
+
+       if (! node || ! node->file || node->stream)
+         return svn_error_create(SVN_ERR_XML_MALFORMED, NULL, NULL);
+
+       /* ### Is there a better way to access a specific attr here? */
+       attrs = svn_ra_serf__xml_gather_since(xes, REPLAY_APPLY_TEXTDELTA);
+       checksum = svn_hash_gets(attrs, "checksum");
+
+       SVN_ERR(ctx->editor->apply_textdelta(node->baton, checksum, node->pool,
+                                            &handler, &handler_baton));
+
+       if (handler != svn_delta_noop_window_handler)
+         {
+            node->stream = svn_base64_decode(
+                                    svn_txdelta_parse_svndiff(handler,
+                                                              handler_baton,
+                                                              TRUE,
+                                                              node->pool),
+                                    node->pool);
+         }
     }
-  else if (state == REPORT &&
-           strcmp(name.name, "open-root") == 0)
-    {
-      const char *rev;
-      replay_info_t *info;
 
-      rev = svn_xml_get_attr_value("rev", attrs);
-
-      if (!rev)
-        {
-          return svn_error_create(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL,
-                    _("Missing revision attr in open-root element"));
-        }
+  return SVN_NO_ERROR;
+}
 
-      info = push_state(parser, ctx, OPEN_DIR);
+/* Conforms to svn_ra_serf__xml_closed_t  */
+static svn_error_t *
+replay_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)
+{
+  struct revision_report_t *ctx = baton;
 
-      SVN_ERR(ctx->editor->open_root(ctx->editor_baton,
-                                     SVN_STR_TO_REV(rev),
-                                     ctx->dst_rev_pool,
-                                     &info->baton));
-    }
-  else if ((state == OPEN_DIR || state == ADD_DIR) &&
-           strcmp(name.name, "delete-entry") == 0)
+  if (leaving_state == REPLAY_REPORT)
     {
-      const char *file_name, *rev;
-      replay_info_t *info;
+      if (ctx->current_node)
+        return svn_error_create(SVN_ERR_XML_MALFORMED, NULL, NULL);
 
-      file_name = svn_xml_get_attr_value("name", attrs);
-      if (!file_name)
-        {
-          return svn_error_create(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL,
-                    _("Missing name attr in delete-entry element"));
-        }
-      rev = svn_xml_get_attr_value("rev", attrs);
-      if (!rev)
+      if (ctx->revfinish_func)
         {
-          return svn_error_create(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL,
-                    _("Missing revision attr in delete-entry element"));
+          SVN_ERR(ctx->revfinish_func(ctx->revision, ctx->replay_baton,
+                                      ctx->editor, ctx->editor_baton,
+                                      ctx->props,
+                                      scratch_pool));
         }
-
-      info = push_state(parser, ctx, DELETE_ENTRY);
-
-      SVN_ERR(ctx->editor->delete_entry(file_name, SVN_STR_TO_REV(rev),
-                                        info->baton, scratch_pool));
-
-      svn_ra_serf__xml_pop_state(parser);
     }
-  else if ((state == OPEN_DIR || state == ADD_DIR) &&
-           strcmp(name.name, "open-directory") == 0)
+  else if (leaving_state == REPLAY_TARGET_REVISION)
     {
-      const char *rev, *dir_name;
-      replay_info_t *info;
-
-      dir_name = svn_xml_get_attr_value("name", attrs);
-      if (!dir_name)
-        {
-          return svn_error_create(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL,
-                    _("Missing name attr in open-directory element"));
-        }
-      rev = svn_xml_get_attr_value("rev", attrs);
-      if (!rev)
-        {
-          return svn_error_create(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL,
-                    _("Missing revision attr in open-directory element"));
-        }
-
-      info = push_state(parser, ctx, OPEN_DIR);
+      const char *revstr = svn_hash_gets(attrs, "rev");
+      apr_int64_t rev;
 
-      SVN_ERR(ctx->editor->open_directory(dir_name, info->parent->baton,
-                                          SVN_STR_TO_REV(rev),
-                                          ctx->dst_rev_pool, &info->baton));
+      SVN_ERR(svn_cstring_atoi64(&rev, revstr));
+      SVN_ERR(ctx->editor->set_target_revision(ctx->editor_baton,
+                                               (svn_revnum_t)rev,
+                                               scratch_pool));
     }
-  else if ((state == OPEN_DIR || state == ADD_DIR) &&
-           strcmp(name.name, "add-directory") == 0)
+  else if (leaving_state == REPLAY_OPEN_ROOT)
     {
-      const char *dir_name, *copyfrom, *copyrev;
-      svn_revnum_t rev;
-      replay_info_t *info;
+      const char *revstr = svn_hash_gets(attrs, "rev");
+      apr_int64_t rev;
+      apr_pool_t *root_pool = svn_pool_create(ctx->pool);
 
-      dir_name = svn_xml_get_attr_value("name", attrs);
-      if (!dir_name)
-        {
-          return svn_error_create(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL,
-                    _("Missing name attr in add-directory element"));
-        }
-      copyfrom = svn_xml_get_attr_value("copyfrom-path", attrs);
-      copyrev = svn_xml_get_attr_value("copyfrom-rev", attrs);
+      if (ctx->current_node || ctx->root_node)
+        return svn_error_create(SVN_ERR_XML_MALFORMED, NULL, NULL);
 
-      if (copyrev)
-        rev = SVN_STR_TO_REV(copyrev);
-      else
-        rev = SVN_INVALID_REVNUM;
+      ctx->root_node = apr_pcalloc(root_pool, sizeof(*ctx->root_node));
+      ctx->root_node->pool = root_pool;
 
-      info = push_state(parser, ctx, ADD_DIR);
+      ctx->current_node = ctx->root_node;
 
-      SVN_ERR(ctx->editor->add_directory(dir_name, info->parent->baton,
-                                         copyfrom, rev,
-                                         ctx->dst_rev_pool, &info->baton));
+      SVN_ERR(svn_cstring_atoi64(&rev, revstr));
+      SVN_ERR(ctx->editor->open_root(ctx->editor_baton, (svn_revnum_t)rev,
+                                     root_pool,
+                                     &ctx->current_node->baton));
     }
-  else if ((state == OPEN_DIR || state == ADD_DIR) &&
-           strcmp(name.name, "close-directory") == 0)
+  else if (leaving_state == REPLAY_OPEN_DIRECTORY
+           || leaving_state == REPLAY_OPEN_FILE
+           || leaving_state == REPLAY_ADD_DIRECTORY
+           || leaving_state == REPLAY_ADD_FILE)
     {
-      replay_info_t *info = parser->state->private;
+      struct replay_node_t *node;
+      apr_pool_t *node_pool;
+      const char *name = svn_hash_gets(attrs, "name");
+      const char *rev_str;
+      apr_int64_t rev;
 
-      SVN_ERR(ctx->editor->close_directory(info->baton, scratch_pool));
+      if (!ctx->current_node || ctx->current_node->file)
+        return svn_error_create(SVN_ERR_XML_MALFORMED, NULL, NULL);
 
-      svn_ra_serf__xml_pop_state(parser);
-    }
-  else if ((state == OPEN_DIR || state == ADD_DIR) &&
-           strcmp(name.name, "open-file") == 0)
-    {
-      const char *file_name, *rev;
-      replay_info_t *info;
+      node_pool = svn_pool_create(ctx->current_node->pool);
+      node = apr_pcalloc(node_pool, sizeof(*node));
+      node->pool = node_pool;
+      node->parent = ctx->current_node;
 
-      svn_pool_clear(ctx->file_pool);
-      file_name = svn_xml_get_attr_value("name", attrs);
-      if (!file_name)
+      if (leaving_state == REPLAY_OPEN_DIRECTORY
+          || leaving_state == REPLAY_OPEN_FILE)
         {
-          return svn_error_create(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL,
-                    _("Missing name attr in open-file element"));
+          rev_str = svn_hash_gets(attrs, "rev");
         }
-      rev = svn_xml_get_attr_value("rev", attrs);
-      if (!rev)
-        {
-          return svn_error_create(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL,
-                    _("Missing revision attr in open-file element"));
-        }
-
-      info = push_state(parser, ctx, OPEN_FILE);
-
-      SVN_ERR(ctx->editor->open_file(file_name, info->parent->baton,
-                                     SVN_STR_TO_REV(rev),
-                                     ctx->file_pool, &info->baton));
-    }
-  else if ((state == OPEN_DIR || state == ADD_DIR) &&
-           strcmp(name.name, "add-file") == 0)
-    {
-      const char *file_name, *copyfrom, *copyrev;
-      svn_revnum_t rev;
-      replay_info_t *info;
-
-      svn_pool_clear(ctx->file_pool);
-      file_name = svn_xml_get_attr_value("name", attrs);
-      if (!file_name)
-        {
-          return svn_error_create(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL,
-                    _("Missing name attr in add-file element"));
-        }
-      copyfrom = svn_xml_get_attr_value("copyfrom-path", attrs);
-      copyrev = svn_xml_get_attr_value("copyfrom-rev", attrs);
-
-      info = push_state(parser, ctx, ADD_FILE);
+      else
+        rev_str = svn_hash_gets(attrs, "copyfrom-rev");
 
-      if (copyrev)
-        rev = SVN_STR_TO_REV(copyrev);
+      if (rev_str)
+        SVN_ERR(svn_cstring_atoi64(&rev, rev_str));
       else
         rev = SVN_INVALID_REVNUM;
 
-      SVN_ERR(ctx->editor->add_file(file_name, info->parent->baton,
-                                    copyfrom, rev,
-                                    ctx->file_pool, &info->baton));
-    }
-  else if ((state == OPEN_FILE || state == ADD_FILE) &&
-           strcmp(name.name, "apply-textdelta") == 0)
-    {
-      const char *checksum;
-      replay_info_t *info;
-      svn_txdelta_window_handler_t textdelta;
-      void *textdelta_baton;
-      svn_stream_t *delta_stream;
-
-      info = push_state(parser, ctx, APPLY_TEXTDELTA);
-
-      checksum = svn_xml_get_attr_value("checksum", attrs);
-      if (checksum)
+      switch (leaving_state)
         {
-          checksum = apr_pstrdup(info->pool, checksum);
-        }
-
-      SVN_ERR(ctx->editor->apply_textdelta(info->baton, checksum,
-                                           ctx->file_pool,
-                                           &textdelta,
-                                           &textdelta_baton));
-
-      delta_stream = svn_txdelta_parse_svndiff(textdelta, textdelta_baton,
-                                               TRUE, info->pool);
-      info->stream = svn_base64_decode(delta_stream, info->pool);
-    }
-  else if ((state == OPEN_FILE || state == ADD_FILE) &&
-           strcmp(name.name, "close-file") == 0)
-    {
-      replay_info_t *info = parser->state->private;
-      const char *checksum;
+          case REPLAY_OPEN_DIRECTORY:
+            node->file = FALSE;
+            SVN_ERR(ctx->editor->open_directory(name,
+                                    ctx->current_node->baton,
+                                    (svn_revnum_t)rev,
+                                    node->pool,
+                                    &node->baton));
+            break;
+          case REPLAY_OPEN_FILE:
+            node->file = TRUE;
+            SVN_ERR(ctx->editor->open_file(name,
+                                    ctx->current_node->baton,
+                                    (svn_revnum_t)rev,
+                                    node->pool,
+                                    &node->baton));
+            break;
+          case REPLAY_ADD_DIRECTORY:
+            node->file = FALSE;
+            SVN_ERR(ctx->editor->add_directory(
+                                    name,
+                                    ctx->current_node->baton,
+                                    SVN_IS_VALID_REVNUM(rev)
+                                        ? svn_hash_gets(attrs, "copyfrom-path")
+                                        : NULL,
+                                    (svn_revnum_t)rev,
+                                    node->pool,
+                                    &node->baton));
+            break;
+          case REPLAY_ADD_FILE:
+            node->file = TRUE;
+            SVN_ERR(ctx->editor->add_file(
+                                    name,
+                                    ctx->current_node->baton,
+                                    SVN_IS_VALID_REVNUM(rev)
+                                        ? svn_hash_gets(attrs, "copyfrom-path")
+                                        : NULL,
+                                    (svn_revnum_t)rev,
+                                    node->pool,
+                                    &node->baton));
+            break;
+          /* default: unreachable */
+        }
+      ctx->current_node = node;
+    }
+  else if (leaving_state == REPLAY_CLOSE_FILE)
+    {
+      struct replay_node_t *node = ctx->current_node;
+
+      if (! node || ! node->file)
+        return svn_error_create(SVN_ERR_XML_MALFORMED, NULL, NULL);
+
+      SVN_ERR(ctx->editor->close_file(node->baton,
+                                      svn_hash_gets(attrs, "checksum"),
+                                      node->pool));
+      ctx->current_node = node->parent;
+      svn_pool_destroy(node->pool);
+    }
+  else if (leaving_state == REPLAY_CLOSE_DIRECTORY)
+    {
+      struct replay_node_t *node = ctx->current_node;
+
+      if (! node || node->file)
+        return svn_error_create(SVN_ERR_XML_MALFORMED, NULL, NULL);
+
+      SVN_ERR(ctx->editor->close_directory(node->baton, node->pool));
+      ctx->current_node = node->parent;
+      svn_pool_destroy(node->pool);
+    }
+  else if (leaving_state == REPLAY_DELETE_ENTRY)
+    {
+      struct replay_node_t *parent_node = ctx->current_node;
+      const char *name = svn_hash_gets(attrs, "name");
+      const char *revstr = svn_hash_gets(attrs, "rev");
+      apr_int64_t rev;
+
+      if (! parent_node || parent_node->file)
+        return svn_error_create(SVN_ERR_XML_MALFORMED, NULL, NULL);
+
+      SVN_ERR(svn_cstring_atoi64(&rev, revstr));
+      SVN_ERR(ctx->editor->delete_entry(name,
+                                        (svn_revnum_t)rev,
+                                        parent_node->baton,
+                                        scratch_pool));
+    }
+  else if (leaving_state == REPLAY_CHANGE_FILE_PROP
+           || leaving_state == REPLAY_CHANGE_DIRECTORY_PROP)
+    {
+      struct replay_node_t *node = ctx->current_node;
+      const char *name;
+      const svn_string_t *value;
 
-      checksum = svn_xml_get_attr_value("checksum", attrs);
+      if (! node || node->file != (leaving_state == REPLAY_CHANGE_FILE_PROP))
+        return svn_error_create(SVN_ERR_XML_MALFORMED, NULL, NULL);
 
-      SVN_ERR(ctx->editor->close_file(info->baton, checksum, scratch_pool));
+      name = svn_hash_gets(attrs, "name");
 
-      svn_ra_serf__xml_pop_state(parser);
-    }
-  else if (((state == OPEN_FILE || state == ADD_FILE) &&
-            strcmp(name.name, "change-file-prop") == 0) ||
-           ((state == OPEN_DIR || state == ADD_DIR) &&
-            strcmp(name.name, "change-dir-prop") == 0))
-    {
-      const char *prop_name;
-      prop_info_t *info;
-
-      prop_name = svn_xml_get_attr_value("name", attrs);
-      if (!prop_name)
-        {
-          return svn_error_createf(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL,
-                                   _("Missing name attr in %s element"),
-                                   name.name);
-        }
-
-      info = push_state(parser, ctx, CHANGE_PROP);
-
-
-      if (svn_xml_get_attr_value("del", attrs))
-        info->del_prop = TRUE;
+      if (svn_hash_gets(attrs, "del"))
+        value = NULL;
       else
-        info->del_prop = FALSE;
+        value = svn_base64_decode_string(cdata, scratch_pool);
 
-      if (state == OPEN_FILE || state == ADD_FILE)
+      if (node->file)
         {
-          info->name = apr_pstrdup(ctx->file_pool, prop_name);
-          info->change = ctx->editor->change_file_prop;
+          SVN_ERR(ctx->editor->change_file_prop(node->baton, name, value,
+                                                scratch_pool));
         }
       else
         {
-          info->name = apr_pstrdup(ctx->dst_rev_pool, prop_name);
-          info->change = ctx->editor->change_dir_prop;
+          SVN_ERR(ctx->editor->change_dir_prop(node->baton, name, value,
+                                               scratch_pool));
         }
-
     }
+  else if (leaving_state == REPLAY_APPLY_TEXTDELTA)
+    {
+      struct replay_node_t *node = ctx->current_node;
+
+      if (! node || ! node->file || ! node->stream)
+        return svn_error_create(SVN_ERR_XML_MALFORMED, NULL, NULL);
+
+      SVN_ERR(svn_stream_close(node->stream));
 
+      node->stream = NULL;
+    }
   return SVN_NO_ERROR;
 }
 
+/* Conforms to svn_ra_serf__xml_cdata_t  */
 static svn_error_t *
-end_replay(svn_ra_serf__xml_parser_t *parser,
-           svn_ra_serf__dav_props_t name,
-           apr_pool_t *scratch_pool)
+replay_cdata(svn_ra_serf__xml_estate_t *xes,
+             void *baton,
+             int current_state,
+             const char *data,
+             apr_size_t len,
+             apr_pool_t *scratch_pool)
 {
-  replay_context_t *ctx = parser->user_data;
-  replay_state_e state;
+  struct revision_report_t *ctx = baton;
 
-  state = parser->state->current_state;
-
-  if (state == REPORT &&
-      strcmp(name.name, "editor-report") == 0)
-    {
-      svn_ra_serf__xml_pop_state(parser);
-      if (ctx->revfinish_func)
-        {
-          SVN_ERR(ctx->revfinish_func(ctx->revision, ctx->replay_baton,
-                                      ctx->editor, ctx->editor_baton,
-                                      ctx->props,
-                                      ctx->dst_rev_pool));
-        }
-      svn_pool_destroy(ctx->dst_rev_pool);
-    }
-  else if (state == OPEN_DIR && strcmp(name.name, "open-directory") == 0)
-    {
-      /* Don't do anything. */
-    }
-  else if (state == ADD_DIR && strcmp(name.name, "add-directory") == 0)
-    {
-      /* Don't do anything. */
-    }
-  else if (state == OPEN_FILE && strcmp(name.name, "open-file") == 0)
-    {
-      /* Don't do anything. */
-    }
-  else if (state == ADD_FILE && strcmp(name.name, "add-file") == 0)
-    {
-      /* Don't do anything. */
-    }
-  else if ((state == OPEN_FILE || state == ADD_FILE) &&
-           strcmp(name.name, "close-file") == 0)
-    {
-      /* Don't do anything. */
-    }
-  else if ((state == APPLY_TEXTDELTA) &&
-           strcmp(name.name, "apply-textdelta") == 0)
+  if (current_state == REPLAY_APPLY_TEXTDELTA)
     {
-      replay_info_t *info = parser->state->private;
-      SVN_ERR(svn_stream_close(info->stream));
-      svn_ra_serf__xml_pop_state(parser);
-    }
-  else if (state == CHANGE_PROP &&
-           (strcmp(name.name, "change-file-prop") == 0 ||
-            strcmp(name.name, "change-dir-prop") == 0))
-    {
-      prop_info_t *info = parser->state->private;
-      const svn_string_t *prop_val;
+      struct replay_node_t *node = ctx->current_node;
 
-      if (info->del_prop)
-        {
-          prop_val = NULL;
-        }
-      else
-        {
-          const svn_string_t *morph;
+      if (! node || ! node->file)
+        return svn_error_create(SVN_ERR_XML_MALFORMED, NULL, NULL);
 
-          morph = svn_stringbuf__morph_into_string(info->prop_value);
-#ifdef SVN_DEBUG
-          info->prop_value = NULL;  /* morph killed the stringbuf.  */
-#endif
+      if (node->stream)
+        {
+          apr_size_t written = len;
 
-          if (strcmp(name.name, "change-file-prop") == 0)
-            prop_val = svn_base64_decode_string(morph, ctx->file_pool);
-          else
-            prop_val = svn_base64_decode_string(morph, ctx->dst_rev_pool);
+          SVN_ERR(svn_stream_write(node->stream, data, &written));
+          if (written != len)
+            return svn_error_create(SVN_ERR_STREAM_UNEXPECTED_EOF, NULL,
+                                    _("Error writing stream: unexpected EOF"));
         }
-
-      SVN_ERR(info->change(info->parent->baton, info->name, prop_val,
-                           info->parent->pool));
-      svn_ra_serf__xml_pop_state(parser);
     }
 
   return SVN_NO_ERROR;
 }
 
+/* Conforms to svn_ra_serf__xml_done_t  */
 static svn_error_t *
-cdata_replay(svn_ra_serf__xml_parser_t *parser,
-             const char *data,
-             apr_size_t len,
-             apr_pool_t *scratch_pool)
+replay_done(void *baton,
+           apr_pool_t *scratch_pool)
 {
-  replay_context_t *replay_ctx = parser->user_data;
-  replay_state_e state;
-
-  UNUSED_CTX(replay_ctx);
+  struct revision_report_t *ctx = baton;
 
-  state = parser->state->current_state;
+  *ctx->done = TRUE; /* Breaks out svn_ra_serf__context_run_wait */
 
-  if (state == APPLY_TEXTDELTA)
-    {
-      replay_info_t *info = parser->state->private;
-      apr_size_t written;
-
-      written = len;
-
-      SVN_ERR(svn_stream_write(info->stream, data, &written));
-
-      if (written != len)
-        return svn_error_create(SVN_ERR_STREAM_UNEXPECTED_EOF, NULL,
-                                _("Error writing stream: unexpected EOF"));
-    }
-  else if (state == CHANGE_PROP)
-    {
-      prop_info_t *info = parser->state->private;
-
-      svn_stringbuf_appendbytes(info->prop_value, data, len);
-    }
+  ctx->done_item.data = ctx;
+  ctx->done_item.next = *ctx->done_list;
+  *ctx->done_list = &ctx->done_item;
 
   return SVN_NO_ERROR;
 }
@@ -594,7 +500,7 @@ create_replay_body(serf_bucket_t **bkt,
                    serf_bucket_alloc_t *alloc,
                    apr_pool_t *pool)
 {
-  replay_context_t *ctx = baton;
+  struct revision_report_t *ctx = baton;
   serf_bucket_t *body_bkt;
 
   body_bkt = serf_bucket_aggregate_create(alloc);
@@ -617,17 +523,17 @@ create_replay_body(serf_bucket_t **bkt,
     {
       svn_ra_serf__add_tag_buckets(body_bkt,
                                    "S:revision",
-                                   apr_ltoa(ctx->src_rev_pool, ctx->revision),
+                                   apr_ltoa(pool, ctx->revision),
                                    alloc);
     }
   svn_ra_serf__add_tag_buckets(body_bkt,
                                "S:low-water-mark",
-                               apr_ltoa(ctx->src_rev_pool, ctx->low_water_mark),
+                               apr_ltoa(pool, ctx->low_water_mark),
                                alloc);
 
   svn_ra_serf__add_tag_buckets(body_bkt,
                                "S:send-deltas",
-                               apr_ltoa(ctx->src_rev_pool, ctx->send_deltas),
+                               apr_ltoa(pool, ctx->send_deltas),
                                alloc);
 
   svn_ra_serf__add_close_tag_buckets(body_bkt, alloc, "S:replay-report");
@@ -643,60 +549,52 @@ svn_ra_serf__replay(svn_ra_session_t *ra
                     svn_boolean_t send_deltas,
                     const svn_delta_editor_t *editor,
                     void *edit_baton,
-                    apr_pool_t *pool)
+                    apr_pool_t *scratch_pool)
 {
-  replay_context_t *replay_ctx;
+  struct revision_report_t ctx = { NULL };
   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_error_t *err;
   const char *report_target;
 
-  SVN_ERR(svn_ra_serf__report_resource(&report_target, session, NULL, pool));
+  SVN_ERR(svn_ra_serf__report_resource(&report_target, session, NULL,
+                                       scratch_pool));
 
-  replay_ctx = apr_pcalloc(pool, sizeof(*replay_ctx));
-  replay_ctx->src_rev_pool = pool;
-  replay_ctx->editor = editor;
-  replay_ctx->editor_baton = edit_baton;
-  replay_ctx->done = FALSE;
-  replay_ctx->revision = revision;
-  replay_ctx->low_water_mark = low_water_mark;
-  replay_ctx->send_deltas = send_deltas;
-  replay_ctx->revs_props = apr_hash_make(replay_ctx->src_rev_pool);
+  ctx.pool = svn_pool_create(scratch_pool);
+  ctx.editor = editor;
+  ctx.editor_baton = edit_baton;
+  ctx.done = FALSE;
+  ctx.revision = revision;
+  ctx.low_water_mark = low_water_mark;
+  ctx.send_deltas = send_deltas;
+  ctx.revs_props = apr_hash_make(scratch_pool);
+
+  xmlctx = svn_ra_serf__xml_context_create(replay_ttable,
+                                           replay_opened, replay_closed,
+                                           replay_cdata,
+                                           NULL,
+                                           &ctx,
+                                           scratch_pool);
 
-  handler = apr_pcalloc(pool, sizeof(*handler));
+  handler = svn_ra_serf__create_expat_handler(xmlctx, NULL, scratch_pool);
 
-  handler->handler_pool = pool;
   handler->method = "REPORT";
   handler->path = session->session_url.path;
   handler->body_delegate = create_replay_body;
-  handler->body_delegate_baton = replay_ctx;
+  handler->body_delegate_baton = &ctx;
   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 = replay_ctx;
-  parser_ctx->start = start_replay;
-  parser_ctx->end = end_replay;
-  parser_ctx->cdata = cdata_replay;
-  parser_ctx->done = &replay_ctx->done;
-
-  handler->response_handler = svn_ra_serf__handle_xml_parser;
-  handler->response_baton = parser_ctx;
-
-  /* This is only needed to handle errors during XML parsing. */
-  replay_ctx->parser_ctx = parser_ctx;
-  replay_ctx->report_handler = handler; /* unused */
+  ctx.report_handler = handler; /* unused */
 
   svn_ra_serf__request_create(handler);
 
-  err = svn_ra_serf__context_run_wait(&replay_ctx->done, session, pool);
+  err = svn_ra_serf__context_run_wait(&handler->done, session, scratch_pool);
 
   SVN_ERR(svn_error_compose_create(
-              svn_ra_serf__error_on_status(handler->sline.code,
+              svn_ra_serf__error_on_status(handler->sline,
                                            handler->path,
                                            handler->location),
               err));
@@ -751,6 +649,8 @@ svn_ra_serf__replay_range(svn_ra_session
   const char *report_target;
   int active_reports = 0;
   const char *include_path;
+  svn_boolean_t done;
+  svn_ra_serf__list_t *done_reports = NULL;
 
   SVN_ERR(svn_ra_serf__report_resource(&report_target, session, NULL, pool));
 
@@ -785,10 +685,6 @@ svn_ra_serf__replay_range(svn_ra_session
 
   while (active_reports || rev <= end_revision)
     {
-      svn_ra_serf__list_t *done_list;
-      svn_ra_serf__list_t *done_reports = NULL;
-      replay_context_t *replay_ctx;
-
       if (session->cancel_func)
         SVN_ERR(session->cancel_func(session->cancel_baton));
 
@@ -796,17 +692,19 @@ svn_ra_serf__replay_range(svn_ra_session
          requests to MAX_OUTSTANDING_REQUESTS. */
       if (rev <= end_revision  && active_reports < MAX_OUTSTANDING_REQUESTS)
         {
+          struct revision_report_t *replay_ctx;
           svn_ra_serf__handler_t *handler;
-          svn_ra_serf__xml_parser_t *parser_ctx;
           apr_pool_t *ctx_pool = svn_pool_create(pool);
+          svn_ra_serf__xml_context_t *xmlctx;
           const char *replay_target;
 
           replay_ctx = apr_pcalloc(ctx_pool, sizeof(*replay_ctx));
-          replay_ctx->src_rev_pool = ctx_pool;
+          replay_ctx->pool = ctx_pool;
           replay_ctx->revstart_func = revstart_func;
           replay_ctx->revfinish_func = revfinish_func;
           replay_ctx->replay_baton = replay_baton;
-          replay_ctx->done = FALSE;
+          replay_ctx->done = &done;
+          replay_ctx->done_list = &done_reports;
           replay_ctx->include_path = include_path;
           replay_ctx->revision = rev;
           replay_ctx->low_water_mark = low_water_mark;
@@ -814,7 +712,7 @@ svn_ra_serf__replay_range(svn_ra_session
           replay_ctx->done_item.data = replay_ctx;
 
           /* Request all properties of a certain revision. */
-          replay_ctx->revs_props = apr_hash_make(replay_ctx->src_rev_pool);
+          replay_ctx->revs_props = apr_hash_make(replay_ctx->pool);
 
           if (SVN_RA_SERF__HAVE_HTTPV2_SUPPORT(session))
             {
@@ -835,7 +733,7 @@ svn_ra_serf__replay_range(svn_ra_session
                                              replay_ctx->revprop_rev,
                                              "0", all_props,
                                              NULL,
-                                             replay_ctx->src_rev_pool));
+                                             replay_ctx->pool));
 
           /* Spin up the serf request for the PROPFIND.  */
           svn_ra_serf__request_create(replay_ctx->propfind_handler);
@@ -851,9 +749,14 @@ svn_ra_serf__replay_range(svn_ra_session
               replay_target = session->session_url.path;
             }
 
-          handler = apr_pcalloc(replay_ctx->src_rev_pool, sizeof(*handler));
+          xmlctx = svn_ra_serf__xml_context_create(replay_ttable,
+                                           replay_opened, replay_closed,
+                                           replay_cdata, replay_done,
+                                           replay_ctx,
+                                           ctx_pool);
+
+          handler = svn_ra_serf__create_expat_handler(xmlctx, NULL, ctx_pool);
 
-          handler->handler_pool = replay_ctx->src_rev_pool;
           handler->method = "REPORT";
           handler->path = replay_target;
           handler->body_delegate = create_replay_body;
@@ -861,31 +764,7 @@ svn_ra_serf__replay_range(svn_ra_session
           handler->conn = session->conns[0];
           handler->session = session;
 
-          parser_ctx = apr_pcalloc(replay_ctx->src_rev_pool,
-                                   sizeof(*parser_ctx));
-
-          /* Setup the XML parser context.
-             Because we have not one but a list of requests, the 'done' property
-             on the replay_ctx is not of much use. Instead, use 'done_list'.
-             On each handled response (succesfully or not), the parser will add
-             done_item to done_list, so by keeping track of the state of
-             done_list we know how many requests have been handled completely.
-          */
-          parser_ctx->pool = replay_ctx->src_rev_pool;
-          parser_ctx->user_data = replay_ctx;
-          parser_ctx->start = start_replay;
-          parser_ctx->end = end_replay;
-          parser_ctx->cdata = cdata_replay;
-          parser_ctx->done = &replay_ctx->done;
-          parser_ctx->done_list = &done_reports;
-          parser_ctx->done_item = &replay_ctx->done_item;
-          handler->response_handler = svn_ra_serf__handle_xml_parser;
-          handler->response_baton = parser_ctx;
           replay_ctx->report_handler = handler;
-
-          /* This is only needed to handle errors during XML parsing. */
-          replay_ctx->parser_ctx = parser_ctx;
-
           svn_ra_serf__request_create(handler);
 
           rev++;
@@ -893,26 +772,32 @@ svn_ra_serf__replay_range(svn_ra_session
         }
 
       /* Run the serf loop. */
-      SVN_ERR(svn_ra_serf__context_run_wait(&replay_ctx->done, session, pool));
+      SVN_ERR(svn_ra_serf__context_run_wait(&done, session, pool));
 
       /* Substract the number of completely handled responses from our
          total nr. of open requests', so we'll know when to stop this loop.
          Since the message is completely handled, we can destroy its pool. */
-      done_list = done_reports;
-      while (done_list)
-        {
-          replay_context_t *ctx = (replay_context_t *)done_list->data;
-          svn_ra_serf__handler_t *done_handler = ctx->report_handler;
+      {
+        svn_ra_serf__list_t *done_list;
 
-          done_list = done_list->next;
-          SVN_ERR(svn_ra_serf__error_on_status(done_handler->sline.code,
-                                               done_handler->path,
-                                               done_handler->location));
-          svn_pool_destroy(ctx->src_rev_pool);
-          active_reports--;
-        }
+        done_list = done_reports;
+
+        done = FALSE;
+        done_reports = NULL;
 
-      done_reports = NULL;
+        while (done_list)
+          {
+            revision_report_t *ctx = (revision_report_t *)done_list->data;
+            svn_ra_serf__handler_t *done_handler = ctx->report_handler;
+
+            done_list = done_list->next;
+            SVN_ERR(svn_ra_serf__error_on_status(done_handler->sline,
+                                                 done_handler->path,
+                                                 done_handler->location));
+            svn_pool_clear(ctx->pool);
+            active_reports--;
+          }
+      }
     }
 
   return SVN_NO_ERROR;

Modified: subversion/branches/move-tracking-1/subversion/libsvn_ra_serf/serf.c
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-1/subversion/libsvn_ra_serf/serf.c?rev=1515362&r1=1515361&r2=1515362&view=diff
==============================================================================
--- subversion/branches/move-tracking-1/subversion/libsvn_ra_serf/serf.c (original)
+++ subversion/branches/move-tracking-1/subversion/libsvn_ra_serf/serf.c Mon Aug 19 11:21:01 2013
@@ -225,6 +225,12 @@ load_config(svn_ra_serf__session_t *sess
                                SVN_CONFIG_OPTION_HTTP_MAX_CONNECTIONS,
                                SVN_CONFIG_DEFAULT_OPTION_HTTP_MAX_CONNECTIONS));
 
+  /* Is this proxy potentially busted? Do we need to take special care?  */
+  SVN_ERR(svn_config_get_bool(config, &session->busted_proxy,
+                              SVN_CONFIG_SECTION_GLOBAL,
+                              SVN_CONFIG_OPTION_BUSTED_PROXY,
+                              FALSE));
+
   if (config)
     server_group = svn_config_find_group(config,
                                          session->session_url.hostname,
@@ -281,6 +287,13 @@ load_config(svn_ra_serf__session_t *sess
                                    server_group,
                                    SVN_CONFIG_OPTION_HTTP_MAX_CONNECTIONS,
                                    session->max_connections));
+
+      /* Do we need to take care with this proxy?  */
+      SVN_ERR(svn_config_get_bool(
+               config, &session->busted_proxy,
+               server_group,
+               SVN_CONFIG_OPTION_BUSTED_PROXY,
+               session->busted_proxy));
     }
 
   /* Don't allow the http-max-connections value to be larger than our
@@ -392,6 +405,7 @@ svn_ra_serf__open(svn_ra_session_t *sess
   svn_ra_serf__session_t *serf_sess;
   apr_uri_t url;
   const char *client_string = NULL;
+  svn_error_t *err;
 
   if (corrected_url)
     *corrected_url = NULL;
@@ -441,6 +455,10 @@ svn_ra_serf__open(svn_ra_session_t *sess
      HTTP/1.1 is supported, we can upgrade. */
   serf_sess->http10 = TRUE;
 
+  /* If we switch to HTTP/1.1, then we will use chunked requests. We may disable
+     this, if we find an intervening proxy does not support chunked requests.  */
+  serf_sess->using_chunked_requests = TRUE;
+
   SVN_ERR(load_config(serf_sess, config, serf_sess->pool));
 
   serf_sess->conns[0] = apr_pcalloc(serf_sess->pool,
@@ -479,7 +497,23 @@ svn_ra_serf__open(svn_ra_session_t *sess
 
   session->priv = serf_sess;
 
-  return svn_ra_serf__exchange_capabilities(serf_sess, corrected_url, pool);
+  err = svn_ra_serf__exchange_capabilities(serf_sess, corrected_url, pool);
+
+  /* serf should produce a usable error code instead of APR_EGENERAL */
+  if (err && err->apr_err == APR_EGENERAL)
+    err = svn_error_createf(SVN_ERR_RA_DAV_REQUEST_FAILED, err,
+                            _("Connection to '%s' failed"), session_URL);
+  SVN_ERR(err);
+
+  /* We have set up a useful connection (that doesn't indication a redirect).
+     If we've been told there is possibly a busted proxy in our path to the
+     server AND we switched to HTTP/1.1 (chunked requests), then probe for
+     problems in any proxy.  */
+  if ((corrected_url == NULL || *corrected_url == NULL)
+      && serf_sess->busted_proxy && !serf_sess->http10)
+    SVN_ERR(svn_ra_serf__probe_proxy(serf_sess, pool));
+
+  return SVN_NO_ERROR;
 }
 
 /* Implements svn_ra__vtable_t.reparent(). */

Modified: subversion/branches/move-tracking-1/subversion/libsvn_ra_serf/update.c
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-1/subversion/libsvn_ra_serf/update.c?rev=1515362&r1=1515361&r2=1515362&view=diff
==============================================================================
--- subversion/branches/move-tracking-1/subversion/libsvn_ra_serf/update.c (original)
+++ subversion/branches/move-tracking-1/subversion/libsvn_ra_serf/update.c Mon Aug 19 11:21:01 2013
@@ -49,6 +49,10 @@
 #include "ra_serf.h"
 #include "../libsvn_ra/ra_loader.h"
 
+/*
+#define USE_TRANSITION_PARSER
+*/
+
 
 /*
  * This enum represents the current state of our XML parsing for a REPORT.
@@ -64,7 +68,7 @@
  */
 typedef enum report_state_e {
     NONE = 0,
-    INITIAL = 0,
+    INITIAL = XML_STATE_INITIAL /* = 0 */,
     UPDATE_REPORT,
     TARGET_REVISION,
     OPEN_DIR,
@@ -77,6 +81,17 @@ typedef enum report_state_e {
     IGNORE_PROP_NAME,
     NEED_PROP_NAME,
     TXDELTA
+
+#ifdef USE_TRANSITION_PARSER
+    ,
+
+    CHECKED_IN,
+    CHECKED_IN_HREF,
+
+    SET_PROP,
+
+    MD5_CHECKSUM
+#endif
 } report_state_e;
 
 
@@ -375,9 +390,6 @@ struct report_context_t {
   /* The path to the REPORT request */
   const char *path;
 
-  /* Are we done parsing the REPORT response? */
-  svn_boolean_t done;
-
   /* Did we receive all data from the network? */
   svn_boolean_t report_received;
 
@@ -392,13 +404,14 @@ struct report_context_t {
 };
 
 
-#ifdef NOT_USED_YET
+#ifdef USE_TRANSITION_PARSER
 
 #define D_ "DAV:"
 #define S_ SVN_XML_NAMESPACE
+#define V_ SVN_DAV_PROP_NS_DAV
 static const svn_ra_serf__xml_transition_t update_ttable[] = {
   { INITIAL, S_, "update-report", UPDATE_REPORT,
-    FALSE, { NULL }, FALSE },
+    FALSE, { NULL }, TRUE },
 
   { UPDATE_REPORT, S_, "target-revision", TARGET_REVISION,
     FALSE, { "rev", NULL }, TRUE },
@@ -410,19 +423,19 @@ static const svn_ra_serf__xml_transition
     FALSE, { "rev", "name", NULL }, TRUE },
 
   { OPEN_DIR, S_, "add-directory", ADD_DIR,
-    FALSE, { "rev", "name", "?copyfrom-path", "?copyfrom-rev", NULL }, TRUE },
+    FALSE, { "name", "?rev", "?copyfrom-path", "?copyfrom-rev", NULL }, TRUE },
 
   { ADD_DIR, S_, "add-directory", ADD_DIR,
-    FALSE, { "rev", "name", "?copyfrom-path", "?copyfrom-rev", NULL }, TRUE },
+    FALSE, { "name", "?rev", "?copyfrom-path", "?copyfrom-rev", NULL }, TRUE },
 
   { OPEN_DIR, S_, "open-file", OPEN_FILE,
     FALSE, { "rev", "name", NULL }, TRUE },
 
   { OPEN_DIR, S_, "add-file", ADD_FILE,
-    FALSE, { "rev", "name", "?copyfrom-path", "?copyfrom-rev", NULL }, TRUE },
+    FALSE, { "name", "?rev", "?copyfrom-path", "?copyfrom-rev", NULL }, TRUE },
 
   { ADD_DIR, S_, "add-file", ADD_FILE,
-    FALSE, { "rev", "name", "?copyfrom-path", "?copyfrom-rev", NULL }, TRUE },
+    FALSE, { "name", "?rev", "?copyfrom-path", "?copyfrom-rev", NULL }, TRUE },
 
   { OPEN_DIR, S_, "delete-entry", OPEN_FILE,
     FALSE, { "?rev", "name", NULL }, TRUE },
@@ -439,65 +452,45 @@ static const svn_ra_serf__xml_transition
   { ADD_DIR, S_, "absent-file", ABSENT_FILE,
     FALSE, { "name", NULL }, TRUE },
 
-  { 0 }
-};
 
+  { OPEN_DIR, D_, "checked-in", CHECKED_IN,
+    FALSE, { NULL }, FALSE },
 
+  { ADD_DIR, D_, "checked-in", CHECKED_IN,
+    FALSE, { NULL }, FALSE },
 
-/* Conforms to svn_ra_serf__xml_opened_t  */
-static svn_error_t *
-update_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)
-{
-  report_context_t *ctx = baton;
+  { ADD_FILE, D_, "checked-in", CHECKED_IN,
+    FALSE, { NULL }, FALSE },
 
-  return SVN_NO_ERROR;
-}
 
+  { OPEN_DIR, S_, "set-prop", SET_PROP,
+    TRUE, { "name", "?encoding", NULL }, TRUE },
 
+  { ADD_DIR, S_, "set-prop", SET_PROP,
+    TRUE, { "name", "?encoding", NULL }, TRUE },
 
-/* Conforms to svn_ra_serf__xml_closed_t  */
-static svn_error_t *
-update_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)
-{
-  report_context_t *ctx = baton;
+  { OPEN_FILE, S_, "set-prop", SET_PROP,
+    TRUE, { "name", "?encoding", NULL }, TRUE },
 
-  if (leaving_state == TARGET_REVISION)
-    {
-      const char *rev = svn_hash_gets(attrs, "rev");
+  { ADD_FILE, S_, "set-prop", SET_PROP,
+    TRUE, { "name", "?encoding", NULL }, TRUE },
 
-      SVN_ERR(ctx->update_editor->set_target_revision(ctx->update_baton,
-                                                      SVN_STR_TO_REV(rev),
-                                                      ctx->sess->pool));
-    }
 
-  return SVN_NO_ERROR;
-}
+  { OPEN_FILE, S_, "prop", PROP,
+    FALSE, { NULL }, FALSE },
+  { ADD_FILE, S_, "prop", PROP,
+    FALSE, { NULL }, FALSE },
 
+  { CHECKED_IN, D_, "href", CHECKED_IN_HREF,
+    TRUE, { NULL }, TRUE },
 
-/* Conforms to svn_ra_serf__xml_cdata_t  */
-static svn_error_t *
-update_cdata(svn_ra_serf__xml_estate_t *xes,
-             void *baton,
-             int current_state,
-             const char *data,
-             apr_size_t len,
-             apr_pool_t *scratch_pool)
-{
-  report_context_t *ctx = baton;
+  { PROP, V_, "md5-checksum", MD5_CHECKSUM,
+    TRUE, { NULL }, TRUE },
 
-  return SVN_NO_ERROR;
-}
+  { 0 }
+};
 
-#endif /* NOT_USED_YET */
+#endif /* USE_TRANSITION_PARSER */
 
 
 /* Returns best connection for fetching files/properties. */
@@ -1268,7 +1261,7 @@ handle_stream(serf_request_t *request,
   /* ### new field. make sure we didn't miss some initialization.  */
   SVN_ERR_ASSERT(fetch_ctx->handler != NULL);
 
-  err = svn_ra_serf__error_on_status(fetch_ctx->handler->sline.code,
+  err = svn_ra_serf__error_on_status(fetch_ctx->handler->sline,
                                      fetch_ctx->info->name,
                                      fetch_ctx->handler->location);
   if (err)
@@ -2539,6 +2532,72 @@ cdata_report(svn_ra_serf__xml_parser_t *
   return SVN_NO_ERROR;
 }
 
+#ifdef USE_TRANSITION_PARSER
+/* Conforms to svn_ra_serf__xml_opened_t  */
+static svn_error_t *
+update_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)
+{
+  report_context_t *ctx = baton;
+  SVN_DBG(("Enter state: %d", entered_state));
+
+  return SVN_NO_ERROR;
+}
+
+
+
+/* Conforms to svn_ra_serf__xml_closed_t  */
+static svn_error_t *
+update_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)
+{
+  report_context_t *ctx = baton;
+
+  SVN_DBG(("Leaving state: %d", leaving_state));
+
+  if (leaving_state == UPDATE_REPORT)
+    {
+      ctx->report_completed = TRUE;
+    }
+  else if (leaving_state == TARGET_REVISION)
+    {
+      const char *revstr = svn_hash_gets(attrs, "rev");
+      apr_int64_t rev;
+
+      SVN_ERR(svn_cstring_atoi64(&rev, revstr));
+
+      SVN_ERR(ctx->update_editor->set_target_revision(ctx->update_baton,
+                                                      (svn_revnum_t)rev,
+                                                      ctx->sess->pool));
+    }
+
+
+  return SVN_NO_ERROR;
+}
+
+
+/* Conforms to svn_ra_serf__xml_cdata_t  */
+static svn_error_t *
+update_cdata(svn_ra_serf__xml_estate_t *xes,
+             void *baton,
+             int current_state,
+             const char *data,
+             apr_size_t len,
+             apr_pool_t *scratch_pool)
+{
+  report_context_t *ctx = baton;
+  SVN_DBG(("Got CDATA in state %d\n", current_state));
+  return SVN_NO_ERROR;
+}
+#endif /* USE_TRANSITION_PARSER */
+
 
 /** Editor callbacks given to callers to create request body */
 
@@ -2739,7 +2798,7 @@ setup_update_report_headers(serf_bucket_
   if (report->sess->using_compression)
     {
       serf_bucket_headers_setn(headers, "Accept-Encoding",
-                               "gzip;svndiff1;q=0.9,svndiff;q=0.8");
+                               "gzip,svndiff1;q=0.9,svndiff;q=0.8");
     }
   else
     {
@@ -2757,7 +2816,11 @@ finish_report(void *report_baton,
   report_context_t *report = report_baton;
   svn_ra_serf__session_t *sess = report->sess;
   svn_ra_serf__handler_t *handler;
+#ifdef USE_TRANSITION_PARSER
+  svn_ra_serf__xml_context_t *xmlctx;
+#else
   svn_ra_serf__xml_parser_t *parser_ctx;
+#endif
   const char *report_target;
   svn_stringbuf_t *buf = NULL;
   apr_pool_t *iterpool = svn_pool_create(pool);
@@ -2787,7 +2850,16 @@ finish_report(void *report_baton,
   /* create and deliver request */
   report->path = report_target;
 
+#ifdef USE_TRANSITION_PARSER
+  xmlctx = svn_ra_serf__xml_context_create(update_ttable,
+                                           update_opened, update_closed,
+                                           update_cdata,
+                                           report,
+                                           pool);
+  handler = svn_ra_serf__create_expat_handler(xmlctx, pool);
+#else
   handler = apr_pcalloc(pool, sizeof(*handler));
+#endif
 
   handler->handler_pool = pool;
   handler->method = "REPORT";
@@ -2801,6 +2873,7 @@ finish_report(void *report_baton,
   handler->conn = sess->conns[0];
   handler->session = sess;
 
+#ifndef USE_TRANSITION_PARSER
   parser_ctx = apr_pcalloc(pool, sizeof(*parser_ctx));
 
   parser_ctx->pool = pool;
@@ -2809,12 +2882,13 @@ finish_report(void *report_baton,
   parser_ctx->start = start_report;
   parser_ctx->end = end_report;
   parser_ctx->cdata = cdata_report;
-  parser_ctx->done = &report->done;
+  parser_ctx->done = &handler->done;
 
   handler->response_handler = svn_ra_serf__handle_xml_parser;
   handler->response_baton = parser_ctx;
 
   report->parser_ctx = parser_ctx;
+#endif
 
   svn_ra_serf__request_create(handler);
 
@@ -2828,7 +2902,7 @@ finish_report(void *report_baton,
      network or because we've spooled the entire response into our "pending"
      content of the XML parser. The DONE flag will get set when all the
      XML content has been received *and* parsed.  */
-  while (!report->done
+  while (!handler->done
          || report->num_active_fetches
          || report->num_active_propfinds)
     {
@@ -2865,8 +2939,10 @@ finish_report(void *report_baton,
          the connection timed out.  */
       if (APR_STATUS_IS_TIMEUP(status))
         {
-          svn_error_clear(err);
-          err = SVN_NO_ERROR;
+          /* If there is a pending error, handle it.
+             Unlikely case, as this should have made serf_context run return
+             an error but we shouldn't ignore true errors */
+          SVN_ERR(err);
           status = 0;
 
           if (sess->timeout)
@@ -2891,7 +2967,7 @@ finish_report(void *report_baton,
         {
           return svn_error_trace(
                     svn_error_compose_create(
-                        svn_ra_serf__error_on_status(handler->sline.code,
+                        svn_ra_serf__error_on_status(handler->sline,
                                                      handler->path,
                                                      handler->location),
                         err));
@@ -3068,6 +3144,7 @@ finish_report(void *report_baton,
         }
       report->done_dir_propfinds = NULL;
 
+#ifndef USE_TRANSITION_PARSER
       /* If the parser is paused, and the number of active requests has
          dropped far enough, then resume parsing.  */
       if (parser_ctx->paused
@@ -3082,6 +3159,7 @@ finish_report(void *report_baton,
         SVN_ERR(svn_ra_serf__process_pending(parser_ctx,
                                              &report->report_received,
                                              iterpool_inner));
+#endif
 
       /* Debugging purposes only! */
       for (i = 0; i < sess->num_conns; i++)
@@ -3202,7 +3280,6 @@ make_update_reporter(svn_ra_session_t *r
 
   report->update_editor = update_editor;
   report->update_baton = update_baton;
-  report->done = FALSE;
 
   *reporter = &ra_serf_reporter;
   *report_baton = report;
@@ -3250,6 +3327,14 @@ make_update_reporter(svn_ra_session_t *r
              supports inlining properties in update editor report. */
           if (sess->supports_inline_props)
             {
+              /* NOTE: both inlined properties and server->allows_bulk_update
+                 (flag SVN_DAV_ALLOW_BULK_UPDATES) were added in 1.8.0, so
+                 this code is never reached with a released version of
+                 mod_dav_svn.
+
+                 Basically by default a 1.8.0 client connecting to a 1.7.x or
+                 older server will always use bulk updates. */
+
               /* Inline props supported: do not use bulk updates. */
               use_bulk_updates = FALSE;
             }

Modified: subversion/branches/move-tracking-1/subversion/libsvn_ra_serf/util.c
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-1/subversion/libsvn_ra_serf/util.c?rev=1515362&r1=1515361&r2=1515362&view=diff
==============================================================================
--- subversion/branches/move-tracking-1/subversion/libsvn_ra_serf/util.c (original)
+++ subversion/branches/move-tracking-1/subversion/libsvn_ra_serf/util.c Mon Aug 19 11:21:01 2013
@@ -99,6 +99,7 @@ struct expat_ctx_t {
   svn_ra_serf__xml_context_t *xmlctx;
   XML_Parser parser;
   svn_ra_serf__handler_t *handler;
+  const int *expected_status;
 
   svn_error_t *inner_error;
 
@@ -641,8 +642,9 @@ setup_serf_req(serf_request_t *request,
   serf_bucket_alloc_t *allocator = serf_request_get_alloc(request);
 
   svn_spillbuf_t *buf;
+  svn_boolean_t set_CL = session->http10 || !session->using_chunked_requests;
 
-  if (session->http10 && body_bkt != NULL)
+  if (set_CL && body_bkt != NULL)
     {
       /* Ugh. Use HTTP/1.0 to talk to the server because we don't know if
          it speaks HTTP/1.1 (and thus, chunked requests), or because the
@@ -670,7 +672,7 @@ setup_serf_req(serf_request_t *request,
 
   /* Set the Content-Length value. This will also trigger an HTTP/1.0
      request (rather than the default chunked request).  */
-  if (session->http10)
+  if (set_CL)
     {
       if (body_bkt == NULL)
         serf_bucket_request_set_CL(*req_bkt, 0);
@@ -2386,17 +2388,17 @@ svn_ra_serf__report_resource(const char 
 }
 
 svn_error_t *
-svn_ra_serf__error_on_status(int status_code,
+svn_ra_serf__error_on_status(serf_status_line sline,
                              const char *path,
                              const char *location)
 {
-  switch(status_code)
+  switch(sline.code)
     {
       case 301:
       case 302:
       case 307:
         return svn_error_createf(SVN_ERR_RA_DAV_RELOCATED, NULL,
-                                 (status_code == 301)
+                                 (sline.code == 301)
                                  ? _("Repository moved permanently to '%s';"
                                      " please relocate")
                                  : _("Repository moved temporarily to '%s';"
@@ -2411,8 +2413,18 @@ svn_ra_serf__error_on_status(int status_
       case 423:
         return svn_error_createf(SVN_ERR_FS_NO_LOCK_TOKEN, NULL,
                                  _("'%s': no lock token available"), path);
+
+      case 411:
+        return svn_error_createf(SVN_ERR_RA_DAV_REQUEST_FAILED, NULL,
+                                _("DAV request failed: "
+                                  "Content length required"));
     }
 
+  if (sline.code >= 300)
+    return svn_error_createf(SVN_ERR_RA_DAV_REQUEST_FAILED, NULL,
+                             _("Unexpected HTTP status %d '%s' on '%s'\n"),
+                             sline.code, sline.reason, path);
+
   return SVN_NO_ERROR;
 }
 
@@ -2493,38 +2505,65 @@ expat_response_handler(serf_request_t *r
                        apr_pool_t *scratch_pool)
 {
   struct expat_ctx_t *ectx = baton;
+  svn_boolean_t got_expected_status;
 
-  if (!ectx->parser)
+  if (ectx->expected_status)
     {
-      ectx->parser = XML_ParserCreate(NULL);
-      apr_pool_cleanup_register(ectx->cleanup_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);
+      const int *status = ectx->expected_status;
+      got_expected_status = FALSE;
+
+      while (*status && ectx->handler->sline.code != *status)
+        status++;
+
+      got_expected_status = (*status) != 0;
     }
+  else
+    got_expected_status = (ectx->handler->sline.code == 200);
 
-  /* ### TODO: sline.code < 200 should really be handled by the core */
-  if ((ectx->handler->sline.code < 200) || (ectx->handler->sline.code >= 300))
+  if ((ectx->handler->sline.code < 200) || (ectx->handler->sline.code >= 300)
+      || ! got_expected_status)
     {
       /* 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.  */
+
+      /* ### This handles xml bodies as svn-errors (returned via serf context
+         ### loop), but ignores non-xml errors.
+
+         Current code depends on this behavior and checks itself while other
+         continues, and then verifies if work has been performed.
+
+         ### TODO: Make error checking consistent */
+
+      /* ### If !GOT_EXPECTED_STATUS, this should always produce an error */
       return svn_error_trace(svn_ra_serf__expect_empty_body(
                                request, response, ectx->handler,
                                scratch_pool));
     }
 
+  if (!ectx->parser)
+    {
+      ectx->parser = XML_ParserCreate(NULL);
+      apr_pool_cleanup_register(ectx->cleanup_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);
+    }
+
   while (1)
     {
       apr_status_t status;
       const char *data;
       apr_size_t len;
       int expat_status;
+      svn_boolean_t at_eof = FALSE;
 
       status = serf_bucket_read(response, PARSE_CHUNK_SIZE, &data, &len);
       if (SERF_BUCKET_READ_ERROR(status))
         return svn_ra_serf__wrap_err(status, NULL);
+      else if (APR_STATUS_IS_EOF(status))
+        at_eof = TRUE;
 
 #if 0
       /* ### move restart/skip into the core handler  */
@@ -2536,7 +2575,17 @@ expat_response_handler(serf_request_t *r
 
       /* ### should we have an IGNORE_ERRORS flag like the v1 parser?  */
 
-      expat_status = XML_Parse(ectx->parser, data, (int)len, 0 /* isFinal */);
+      expat_status = XML_Parse(ectx->parser, data, (int)len,
+                               at_eof /* isFinal */);
+
+      if (at_eof 
+          || ectx->inner_error
+          || expat_status != XML_STATUS_OK)
+        {
+          /* Release xml parser state/tables. */
+          apr_pool_cleanup_run(ectx->cleanup_pool, &ectx->parser,
+                               xml_parser_cleanup);
+        }
 
       /* We need to check INNER_ERROR first. This is an error from the
          callbacks that has been "dropped off" for us to retrieve. On
@@ -2545,15 +2594,9 @@ expat_response_handler(serf_request_t *r
 
          If an error is not present, THEN we go ahead and look for parsing
          errors.  */
-      if (ectx->inner_error)
-        {
-          apr_pool_cleanup_run(ectx->cleanup_pool, &ectx->parser,
-                               xml_parser_cleanup);
-          return svn_error_trace(ectx->inner_error);
-        }
-      if (expat_status == XML_STATUS_ERROR)
-        return svn_error_createf(SVN_ERR_XML_MALFORMED,
-                                 ectx->inner_error,
+      SVN_ERR(ectx->inner_error);
+      if (expat_status != XML_STATUS_OK)
+        return svn_error_createf(SVN_ERR_XML_MALFORMED, NULL,
                                  _("The %s response contains invalid XML"
                                    " (%d %s)"),
                                  ectx->handler->method,
@@ -2562,18 +2605,10 @@ expat_response_handler(serf_request_t *r
 
       /* The parsing went fine. What has the bucket told us?  */
 
-      if (APR_STATUS_IS_EOF(status))
+      if (at_eof)
         {
-          /* 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 */);
-
-          svn_ra_serf__xml_context_destroy(ectx->xmlctx);
-          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...  */
+          /* Make sure we actually got xml and clean up after parsing */
+          SVN_ERR(svn_ra_serf__xml_context_done(ectx->xmlctx));
         }
 
       if (status && !SERF_BUCKET_READ_ERROR(status))
@@ -2588,6 +2623,7 @@ expat_response_handler(serf_request_t *r
 
 svn_ra_serf__handler_t *
 svn_ra_serf__create_expat_handler(svn_ra_serf__xml_context_t *xmlctx,
+                                  const int *expected_status,
                                   apr_pool_t *result_pool)
 {
   svn_ra_serf__handler_t *handler;
@@ -2596,6 +2632,7 @@ svn_ra_serf__create_expat_handler(svn_ra
   ectx = apr_pcalloc(result_pool, sizeof(*ectx));
   ectx->xmlctx = xmlctx;
   ectx->parser = NULL;
+  ectx->expected_status = expected_status;
   ectx->cleanup_pool = result_pool;
 
 

Modified: subversion/branches/move-tracking-1/subversion/libsvn_ra_serf/xml.c
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-1/subversion/libsvn_ra_serf/xml.c?rev=1515362&r1=1515361&r2=1515362&view=diff
==============================================================================
--- subversion/branches/move-tracking-1/subversion/libsvn_ra_serf/xml.c (original)
+++ subversion/branches/move-tracking-1/subversion/libsvn_ra_serf/xml.c Mon Aug 19 11:21:01 2013
@@ -57,6 +57,7 @@ struct svn_ra_serf__xml_context_t {
   svn_ra_serf__xml_opened_t opened_cb;
   svn_ra_serf__xml_closed_t closed_cb;
   svn_ra_serf__xml_cdata_t cdata_cb;
+  svn_ra_serf__xml_done_t done_cb;
   void *baton;
 
   /* Linked list of free states.  */
@@ -458,11 +459,58 @@ lazy_create_pool(void *baton)
   return xes->state_pool;
 }
 
-void
-svn_ra_serf__xml_context_destroy(
-  svn_ra_serf__xml_context_t *xmlctx)
+svn_error_t *
+svn_ra_serf__xml_context_done(svn_ra_serf__xml_context_t *xmlctx)
 {
+  if (xmlctx->current->prev)
+    {
+      /* Probably unreachable as this would be an xml parser error */
+      return svn_error_createf(SVN_ERR_XML_MALFORMED, NULL,
+                               _("XML stream truncated: closing '%s' missing"),
+                               xmlctx->current->tag.name);
+    }
+  else if (! xmlctx->free_states)
+    {
+      /* If we have no items on the free_states list, we didn't push anything,
+         which tells us that we found an empty xml body */
+      const svn_ra_serf__xml_transition_t *scan;
+      const svn_ra_serf__xml_transition_t *document = NULL;
+      const char *msg;
+
+      for (scan = xmlctx->ttable; scan->ns != NULL; ++scan)
+        {
+          if (scan->from_state == XML_STATE_INITIAL)
+            {
+              if (document != NULL)
+                {
+                  document = NULL; /* Multiple document elements defined */
+                  break;
+                }
+              document = scan;
+            }
+        }
+
+      if (document)
+        msg = apr_psprintf(xmlctx->scratch_pool, "'%s' element not found",
+                            document->name);
+      else
+        msg = _("document element not found");
+
+      return svn_error_createf(SVN_ERR_XML_MALFORMED, NULL,
+                               _("XML stream truncated: %s"),
+                               msg);
+    }
+
+  if (xmlctx->done_cb != NULL)
+    {
+      START_CALLBACK(xmlctx);
+      SVN_ERR(xmlctx->done_cb(xmlctx->baton,
+                              xmlctx->scratch_pool));
+      END_CALLBACK(xmlctx);
+    }
+
   svn_pool_destroy(xmlctx->scratch_pool);
+  return SVN_NO_ERROR;
 }
 
 svn_ra_serf__xml_context_t *
@@ -471,6 +519,7 @@ svn_ra_serf__xml_context_create(
   svn_ra_serf__xml_opened_t opened_cb,
   svn_ra_serf__xml_closed_t closed_cb,
   svn_ra_serf__xml_cdata_t cdata_cb,
+  svn_ra_serf__xml_done_t done_cb,
   void *baton,
   apr_pool_t *result_pool)
 {
@@ -482,6 +531,7 @@ svn_ra_serf__xml_context_create(
   xmlctx->opened_cb = opened_cb;
   xmlctx->closed_cb = closed_cb;
   xmlctx->cdata_cb = cdata_cb;
+  xmlctx->done_cb = done_cb;
   xmlctx->baton = baton;
   xmlctx->scratch_pool = svn_pool_create(result_pool);
 
@@ -615,6 +665,14 @@ svn_ra_serf__xml_cb_start(svn_ra_serf__x
     }
   if (scan->ns == NULL)
     {
+      if (current->state == XML_STATE_INITIAL)
+        {
+          return svn_error_createf(
+                        SVN_ERR_XML_UNEXPECTED_ELEMENT, NULL,
+                        _("XML Parsing failed: Unexpected root element '%s'"),
+                        elemname.name);
+        }
+
       xmlctx->waiting = elemname;
       /* ### return?  */
       return SVN_NO_ERROR;
@@ -669,10 +727,11 @@ svn_ra_serf__xml_cb_start(svn_ra_serf__x
                   name = *saveattr;
                   value = svn_xml_get_attr_value(name, attrs);
                   if (value == NULL)
-                    return svn_error_createf(SVN_ERR_XML_ATTRIB_NOT_FOUND,
-                                             NULL,
-                                             _("Missing XML attribute: '%s'"),
-                                             name);
+                    return svn_error_createf(
+                                SVN_ERR_XML_ATTRIB_NOT_FOUND,
+                                NULL,
+                                _("Missing XML attribute '%s' on '%s' element"),
+                                name, scan->name);
                 }
 
               if (value)

Modified: subversion/branches/move-tracking-1/subversion/libsvn_ra_svn/client.c
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-1/subversion/libsvn_ra_svn/client.c?rev=1515362&r1=1515361&r2=1515362&view=diff
==============================================================================
--- subversion/branches/move-tracking-1/subversion/libsvn_ra_svn/client.c (original)
+++ subversion/branches/move-tracking-1/subversion/libsvn_ra_svn/client.c Mon Aug 19 11:21:01 2013
@@ -978,6 +978,28 @@ static svn_error_t *ra_svn_commit(svn_ra
   const svn_string_t *log_msg = svn_hash_gets(revprop_table,
                                               SVN_PROP_REVISION_LOG);
 
+  if (log_msg == NULL &&
+      ! svn_ra_svn_has_capability(conn, SVN_RA_SVN_CAP_COMMIT_REVPROPS))
+    {
+      return svn_error_createf(SVN_ERR_BAD_PROPERTY_VALUE, NULL,
+                               _("ra_svn does not support not specifying "
+                                 "a log message with pre-1.5 servers; "
+                                 "consider passing an empty one, or upgrading "
+                                 "the server"));
+    } 
+  else if (log_msg == NULL)
+    /* 1.5+ server.  Set LOG_MSG to something, since the 'logmsg' argument
+       to the 'commit' protocol command is non-optional; on the server side,
+       only REVPROP_TABLE will be used, and LOG_MSG will be ignored.  The 
+       "svn:log" member of REVPROP_TABLE table is NULL, therefore the commit
+       will have a NULL log message (not just "", really NULL).
+
+       svnserve 1.5.x+ has always ignored LOG_MSG when REVPROP_TABLE was
+       present; this was elevated to a protocol promise in r1498550 (and
+       later documented in this comment) in order to fix the segmentation
+       fault bug described in the log message of r1498550.*/
+    log_msg = svn_string_create("", pool);
+
   /* If we're sending revprops other than svn:log, make sure the server won't
      silently ignore them. */
   if (apr_hash_count(revprop_table) > 1 &&
@@ -1597,8 +1619,7 @@ static svn_error_t *ra_svn_log(svn_ra_se
               if (elt->kind != SVN_RA_SVN_LIST)
                 return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
                                         _("Changed-path entry not a list"));
-              SVN_ERR(svn_ra_svn__parse_tuple(elt->u.list, iterpool,
-                                              "sw(?cr)?(?c?BB)",
+              SVN_ERR(svn_ra_svn__read_data_log_changed_entry(elt->u.list,
                                               &cpath, &action, &copy_path,
                                               &copy_rev, &kind_str,
                                               &text_mods, &prop_mods));

Modified: subversion/branches/move-tracking-1/subversion/libsvn_ra_svn/marshal.c
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-1/subversion/libsvn_ra_svn/marshal.c?rev=1515362&r1=1515361&r2=1515362&view=diff
==============================================================================
--- subversion/branches/move-tracking-1/subversion/libsvn_ra_svn/marshal.c (original)
+++ subversion/branches/move-tracking-1/subversion/libsvn_ra_svn/marshal.c Mon Aug 19 11:21:01 2013
@@ -1025,7 +1025,6 @@ static svn_error_t *read_item(svn_ra_svn
 {
   char c = first_char;
   apr_uint64_t val;
-  svn_stringbuf_t *str;
   svn_ra_svn_item_t *listitem;
 
   if (++level >= ITEM_NESTING_LIMIT)
@@ -2423,3 +2422,161 @@ svn_ra_svn__write_data_log_entry(svn_ra_
   
   return SVN_NO_ERROR;
 }
+
+/* If condition COND is not met, return a "malformed network data" error.
+ */
+#define CHECK_PROTOCOL_COND(cond)\
+  if (!(cond)) \
+    return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL, \
+                            _("Malformed network data"));
+
+/* In *RESULT, return the SVN-style string at index IDX in tuple ITEMS.
+ */
+static svn_error_t *
+svn_ra_svn__read_string(const apr_array_header_t *items,
+                        int idx,
+                        svn_string_t **result)
+{
+  svn_ra_svn_item_t *elt = &APR_ARRAY_IDX(items, idx, svn_ra_svn_item_t);
+  CHECK_PROTOCOL_COND(elt->kind == SVN_RA_SVN_STRING);
+  *result = elt->u.string;
+    
+  return SVN_NO_ERROR;
+}
+
+/* In *RESULT, return the C-style string at index IDX in tuple ITEMS.
+ */
+static svn_error_t *
+svn_ra_svn__read_cstring(const apr_array_header_t *items,
+                         int idx,
+                         const char **result)
+{
+  svn_ra_svn_item_t *elt = &APR_ARRAY_IDX(items, idx, svn_ra_svn_item_t);
+  CHECK_PROTOCOL_COND(elt->kind == SVN_RA_SVN_STRING);
+  *result = elt->u.string->data;
+    
+  return SVN_NO_ERROR;
+}
+
+/* In *RESULT, return the word at index IDX in tuple ITEMS.
+ */
+static svn_error_t *
+svn_ra_svn__read_word(const apr_array_header_t *items,
+                      int idx,
+                      const char **result)
+{
+  svn_ra_svn_item_t *elt = &APR_ARRAY_IDX(items, idx, svn_ra_svn_item_t);
+  CHECK_PROTOCOL_COND(elt->kind == SVN_RA_SVN_WORD);
+  *result = elt->u.word;
+   
+  return SVN_NO_ERROR;
+}
+
+/* In *RESULT, return the revision at index IDX in tuple ITEMS.
+ */
+static svn_error_t *
+svn_ra_svn__read_revision(const apr_array_header_t *items,
+                          int idx,
+                          svn_revnum_t *result)
+{
+  svn_ra_svn_item_t *elt = &APR_ARRAY_IDX(items, idx, svn_ra_svn_item_t);
+  CHECK_PROTOCOL_COND(elt->kind == SVN_RA_SVN_NUMBER);
+  *result = (svn_revnum_t)elt->u.number;
+    
+  return SVN_NO_ERROR;
+}
+
+/* In *RESULT, return the boolean at index IDX in tuple ITEMS.
+ */
+static svn_error_t *
+svn_ra_svn__read_boolean(const apr_array_header_t *items,
+                         int idx,
+                         apr_uint64_t *result)
+{
+  svn_ra_svn_item_t *elt = &APR_ARRAY_IDX(items, idx, svn_ra_svn_item_t);
+  CHECK_PROTOCOL_COND(elt->kind == SVN_RA_SVN_WORD);
+  if (elt->u.word[0] == 't' && strcmp(elt->u.word, "true") == 0)
+    *result = TRUE;
+  else if (strcmp(elt->u.word, "false") == 0)
+    *result = FALSE;
+  else
+    CHECK_PROTOCOL_COND(FALSE);
+    
+  return SVN_NO_ERROR;
+}
+
+/* In *RESULT, return the tuple at index IDX in tuple ITEMS.
+ */
+static svn_error_t *
+svn_ra_svn__read_list(const apr_array_header_t *items,
+                      int idx,
+                      const apr_array_header_t **result)
+{
+  svn_ra_svn_item_t *elt  = &APR_ARRAY_IDX(items, idx, svn_ra_svn_item_t);
+  CHECK_PROTOCOL_COND(elt->kind == SVN_RA_SVN_LIST);
+
+  *result = elt->u.list;
+  return SVN_NO_ERROR;
+}
+
+/* Verify the tuple ITEMS contains at least MIN and at most MAX elements.
+ */
+static svn_error_t *
+svn_ra_svn__read_check_array_size(const apr_array_header_t *items,
+                                  int min,
+                                  int max)
+{
+  CHECK_PROTOCOL_COND(items->nelts >= min && items->nelts <= max);
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_ra_svn__read_data_log_changed_entry(const apr_array_header_t *items,
+                                        svn_string_t **cpath,
+                                        const char **action,
+                                        const char **copy_path,
+                                        svn_revnum_t *copy_rev,
+                                        const char **kind_str,
+                                        apr_uint64_t *text_mods,
+                                        apr_uint64_t *prop_mods)
+{
+  const apr_array_header_t *sub_items;
+
+  /* initialize optional values */
+  *copy_path = NULL;
+  *copy_rev = SVN_INVALID_REVNUM;
+  *kind_str = NULL;
+  *text_mods = SVN_RA_SVN_UNSPECIFIED_NUMBER;
+  *prop_mods = SVN_RA_SVN_UNSPECIFIED_NUMBER;
+
+  /* top-level elements (mandatory) */
+  SVN_ERR(svn_ra_svn__read_check_array_size(items, 3, 4));
+  SVN_ERR(svn_ra_svn__read_string(items, 0, cpath));
+  SVN_ERR(svn_ra_svn__read_word(items, 1, action));
+
+  /* first sub-structure (mandatory) */
+  SVN_ERR(svn_ra_svn__read_list(items, 2, &sub_items));
+  if (sub_items->nelts)
+    {
+      SVN_ERR(svn_ra_svn__read_check_array_size(sub_items, 2, 2));
+      SVN_ERR(svn_ra_svn__read_cstring(sub_items, 0, copy_path));
+      SVN_ERR(svn_ra_svn__read_revision(sub_items, 1, copy_rev));
+    }
+
+  /* second sub-structure (optional) */
+  if (items->nelts == 4)
+    {
+      SVN_ERR(svn_ra_svn__read_list(items, 3, &sub_items));
+      SVN_ERR(svn_ra_svn__read_check_array_size(sub_items, 0, 3));
+
+      switch (sub_items->nelts)
+        {
+          case 3 : SVN_ERR(svn_ra_svn__read_boolean(sub_items, 2, prop_mods));
+          case 2 : SVN_ERR(svn_ra_svn__read_boolean(sub_items, 1, text_mods));
+          case 1 : SVN_ERR(svn_ra_svn__read_cstring(sub_items, 0, kind_str));
+          default: break;
+        }
+    }
+
+  return SVN_NO_ERROR;
+}

Modified: subversion/branches/move-tracking-1/subversion/libsvn_ra_svn/protocol
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-1/subversion/libsvn_ra_svn/protocol?rev=1515362&r1=1515361&r2=1515362&view=diff
==============================================================================
--- subversion/branches/move-tracking-1/subversion/libsvn_ra_svn/protocol (original)
+++ subversion/branches/move-tracking-1/subversion/libsvn_ra_svn/protocol Mon Aug 19 11:21:01 2013
@@ -294,8 +294,12 @@ second place for auth-request point as n
     Upon receiving response, client switches to editor command set.
     Upon successful completion of edit, server sends auth-request.
     After auth exchange completes, server sends commit-info.
+    If rev-props is present, logmsg is ignored.  Only the svn:log entry in
+    rev-props (if any) will be used.
     commit-info: ( new-rev:number date:string author:string
                    ? ( post-commit-err:string ) )
+    NOTE: when revving this, make 'logmsg' optional, or delete that parameter
+          and have the log message specified in 'rev-props'.
 
   get-file
     params:   ( path:string [ rev:number ] want-props:bool want-contents:bool

Modified: subversion/branches/move-tracking-1/subversion/libsvn_repos/commit.c
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-1/subversion/libsvn_repos/commit.c?rev=1515362&r1=1515361&r2=1515362&view=diff
==============================================================================
--- subversion/branches/move-tracking-1/subversion/libsvn_repos/commit.c (original)
+++ subversion/branches/move-tracking-1/subversion/libsvn_repos/commit.c Mon Aug 19 11:21:01 2013
@@ -1133,15 +1133,15 @@ static svn_error_t *
 alter_file_cb(void *baton,
               const char *relpath,
               svn_revnum_t revision,
-              apr_hash_t *props,
               const svn_checksum_t *checksum,
               svn_stream_t *contents,
+              apr_hash_t *props,
               apr_pool_t *scratch_pool)
 {
   struct ev2_baton *eb = baton;
 
-  SVN_ERR(svn_editor_alter_file(eb->inner, relpath, revision, props,
-                                checksum, contents));
+  SVN_ERR(svn_editor_alter_file(eb->inner, relpath, revision,
+                                checksum, contents, props));
   return SVN_NO_ERROR;
 }
 
@@ -1151,14 +1151,14 @@ static svn_error_t *
 alter_symlink_cb(void *baton,
                  const char *relpath,
                  svn_revnum_t revision,
-                 apr_hash_t *props,
                  const char *target,
+                 apr_hash_t *props,
                  apr_pool_t *scratch_pool)
 {
   struct ev2_baton *eb = baton;
 
-  SVN_ERR(svn_editor_alter_symlink(eb->inner, relpath, revision, props,
-                                   target));
+  SVN_ERR(svn_editor_alter_symlink(eb->inner, relpath, revision,
+                                   target, props));
   return SVN_NO_ERROR;
 }
 

Modified: subversion/branches/move-tracking-1/subversion/libsvn_repos/deprecated.c
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-1/subversion/libsvn_repos/deprecated.c?rev=1515362&r1=1515361&r2=1515362&view=diff
==============================================================================
--- subversion/branches/move-tracking-1/subversion/libsvn_repos/deprecated.c (original)
+++ subversion/branches/move-tracking-1/subversion/libsvn_repos/deprecated.c Mon Aug 19 11:21:01 2013
@@ -727,6 +727,27 @@ svn_repos_dump_fs2(svn_repos_t *repos,
 }
 
 svn_error_t *
+svn_repos_verify_fs2(svn_repos_t *repos,
+                     svn_revnum_t start_rev,
+                     svn_revnum_t end_rev,
+                     svn_repos_notify_func_t notify_func,
+                     void *notify_baton,
+                     svn_cancel_func_t cancel_func,
+                     void *cancel_baton,
+                     apr_pool_t *pool)
+{
+  return svn_error_trace(svn_repos_verify_fs3(repos,
+                                              start_rev,
+                                              end_rev,
+                                              FALSE,
+                                              notify_func,
+                                              notify_baton,
+                                              cancel_func,
+                                              cancel_baton,
+                                              pool));
+}
+
+svn_error_t *
 svn_repos_verify_fs(svn_repos_t *repos,
                     svn_stream_t *feedback_stream,
                     svn_revnum_t start_rev,



Mime
View raw message