You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by br...@apache.org on 2014/01/15 18:47:24 UTC

svn commit: r1558485 [4/4] - in /subversion/branches/fsfs-ucsnorm: ./ subversion/bindings/javahl/native/ subversion/bindings/javahl/native/jniwrapper/ subversion/bindings/javahl/src/org/apache/subversion/javahl/ subversion/bindings/javahl/tests/org/apa...

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/util.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/util.c?rev=1558485&r1=1558484&r2=1558485&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/util.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/util.c Wed Jan 15 17:47:23 2014
@@ -33,64 +33,21 @@
 #include <serf.h>
 #include <serf_bucket_types.h>
 
-#include <expat.h>
-
 #include "svn_private_config.h"
 #include "svn_hash.h"
 #include "svn_dirent_uri.h"
 #include "svn_path.h"
 #include "svn_string.h"
-#include "svn_xml.h"
 #include "svn_props.h"
 #include "svn_dirent_uri.h"
 
 #include "../libsvn_ra/ra_loader.h"
 #include "private/svn_dep_compat.h"
 #include "private/svn_fspath.h"
-#include "private/svn_subr_private.h"
 #include "private/svn_auth_private.h"
 
 #include "ra_serf.h"
 
-
-/* Fix for older expat 1.95.x's that do not define
- * XML_STATUS_OK/XML_STATUS_ERROR
- */
-#ifndef XML_STATUS_OK
-#define XML_STATUS_OK    1
-#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
-
-
-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;
-
-  /* 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 },
@@ -973,23 +930,6 @@ svn_ra_serf__context_run_one(svn_ra_serf
   /* Wait until the response logic marks its DONE status.  */
   err = svn_ra_serf__context_run_wait(&handler->done, handler->session,
                                       scratch_pool);
-
-  /* A callback invocation has been canceled. In this simple case of
-     context_run_one, we can keep the ra-session operational by resetting
-     the connection.
-
-     If we don't do this, the next context run will notice that the connection
-     is still in the error state and will just return SVN_ERR_CEASE_INVOCATION
-     (=the last error for the connection) again  */
-  if (err && err->apr_err == SVN_ERR_CEASE_INVOCATION)
-    {
-      apr_status_t status = serf_connection_reset(handler->conn->conn);
-
-      if (status)
-        err = svn_error_compose_create(err,
-                                       svn_ra_serf__wrap_err(status, NULL));
-    }
-
   return svn_error_trace(err);
 }
 
@@ -1136,215 +1076,6 @@ svn_ra_serf__expect_empty_body(serf_requ
   return SVN_NO_ERROR;
 }
 
-/* Conforms to Expat's XML_StartElementHandler  */
-static void
-start_xml(void *userData, const char *raw_name, const char **attrs)
-{
-  svn_ra_serf__xml_parser_t *parser = userData;
-  svn_ra_serf__dav_props_t name;
-  apr_pool_t *scratch_pool;
-  svn_error_t *err;
-
-  if (parser->error)
-    return;
-
-  if (!parser->state)
-    svn_ra_serf__xml_push_state(parser, 0);
-
-  /* ### get a real scratch_pool  */
-  scratch_pool = parser->state->pool;
-
-  svn_ra_serf__define_ns(&parser->state->ns_list, attrs, parser->state->pool);
-
-  svn_ra_serf__expand_ns(&name, parser->state->ns_list, raw_name);
-
-  err = parser->start(parser, name, attrs, scratch_pool);
-  if (err && !SERF_BUCKET_READ_ERROR(err->apr_err))
-    err = svn_error_create(SVN_ERR_RA_SERF_WRAPPED_ERROR, err, NULL);
-
-  parser->error = err;
-}
-
-
-/* Conforms to Expat's XML_EndElementHandler  */
-static void
-end_xml(void *userData, const char *raw_name)
-{
-  svn_ra_serf__xml_parser_t *parser = userData;
-  svn_ra_serf__dav_props_t name;
-  svn_error_t *err;
-  apr_pool_t *scratch_pool;
-
-  if (parser->error)
-    return;
-
-  /* ### get a real scratch_pool  */
-  scratch_pool = parser->state->pool;
-
-  svn_ra_serf__expand_ns(&name, parser->state->ns_list, raw_name);
-
-  err = parser->end(parser, name, scratch_pool);
-  if (err && !SERF_BUCKET_READ_ERROR(err->apr_err))
-    err = svn_error_create(SVN_ERR_RA_SERF_WRAPPED_ERROR, err, NULL);
-
-  parser->error = err;
-}
-
-
-/* Conforms to Expat's XML_CharacterDataHandler  */
-static void
-cdata_xml(void *userData, const char *data, int len)
-{
-  svn_ra_serf__xml_parser_t *parser = userData;
-  svn_error_t *err;
-  apr_pool_t *scratch_pool;
-
-  if (parser->error)
-    return;
-
-  if (!parser->state)
-    svn_ra_serf__xml_push_state(parser, 0);
-
-  /* ### get a real scratch_pool  */
-  scratch_pool = parser->state->pool;
-
-  err = parser->cdata(parser, data, len, scratch_pool);
-  if (err && !SERF_BUCKET_READ_ERROR(err->apr_err))
-    err = svn_error_create(SVN_ERR_RA_SERF_WRAPPED_ERROR, err, NULL);
-
-  parser->error = err;
-}
-
-/* Flip the requisite bits in CTX to indicate that processing of the
-   response is complete, adding the current "done item" to the list of
-   completed items. */
-static void
-add_done_item(svn_ra_serf__xml_parser_t *ctx)
-{
-  /* Make sure we don't add to DONE_LIST twice.  */
-  if (!*ctx->done)
-    {
-      *ctx->done = TRUE;
-      if (ctx->done_list)
-        {
-          ctx->done_item->data = ctx->user_data;
-          ctx->done_item->next = *ctx->done_list;
-          *ctx->done_list = ctx->done_item;
-        }
-    }
-}
-
-
-/* svn_error_t * wrapper around XML_Parse */
-static APR_INLINE svn_error_t *
-parse_xml(XML_Parser parser, const char *data, apr_size_t len, svn_boolean_t is_final)
-{
-  int xml_status = XML_Parse(parser, data, (int)len, is_final);
-  const char *msg;
-
-  if (xml_status == XML_STATUS_OK)
-    return SVN_NO_ERROR;
-
-  msg = XML_ErrorString(XML_GetErrorCode(parser));
-
-  return svn_error_create(SVN_ERR_RA_DAV_MALFORMED_DATA,
-                          svn_error_createf(SVN_ERR_XML_MALFORMED, NULL,
-                                            _("Malformed XML: %s"),
-                                            msg),
-                          _("The XML response contains invalid XML"));
-}
-
-/* Apr pool cleanup handler to release an XML_Parser in success and error
-   conditions */
-static apr_status_t
-xml_parser_cleanup(void *baton)
-{
-  XML_Parser *xmlp = baton;
-
-  if (*xmlp)
-    {
-      (void) XML_ParserFree(*xmlp);
-      *xmlp = NULL;
-    }
-
-  return APR_SUCCESS;
-}
-
-/* Implements svn_ra_serf__response_handler_t */
-svn_error_t *
-svn_ra_serf__handle_xml_parser(serf_request_t *request,
-                               serf_bucket_t *response,
-                               void *baton,
-                               apr_pool_t *pool)
-{
-  apr_status_t status;
-  svn_ra_serf__xml_parser_t *ctx = baton;
-  svn_error_t *err;
-
-  if (!ctx->xmlp)
-    {
-      ctx->xmlp = XML_ParserCreate(NULL);
-      apr_pool_cleanup_register(ctx->pool, &ctx->xmlp, xml_parser_cleanup,
-                                apr_pool_cleanup_null);
-      XML_SetUserData(ctx->xmlp, ctx);
-      XML_SetElementHandler(ctx->xmlp, start_xml, end_xml);
-      if (ctx->cdata)
-        {
-          XML_SetCharacterDataHandler(ctx->xmlp, cdata_xml);
-        }
-    }
-
-  while (1)
-    {
-      const char *data;
-      apr_size_t len;
-
-      status = serf_bucket_read(response, PARSE_CHUNK_SIZE, &data, &len);
-      if (SERF_BUCKET_READ_ERROR(status))
-        {
-          return svn_ra_serf__wrap_err(status, NULL);
-        }
-
-      err = parse_xml(ctx->xmlp, data, len, FALSE);
-
-      err = svn_error_compose_create(ctx->error, err);
-
-      if (err)
-        {
-          SVN_ERR_ASSERT(ctx->xmlp != NULL);
-
-          apr_pool_cleanup_run(ctx->pool, &ctx->xmlp, xml_parser_cleanup);
-          add_done_item(ctx);
-          return svn_error_trace(err);
-        }
-
-      if (APR_STATUS_IS_EAGAIN(status))
-        {
-          return svn_ra_serf__wrap_err(status, NULL);
-        }
-
-      if (APR_STATUS_IS_EOF(status))
-        {
-          SVN_ERR_ASSERT(ctx->xmlp != NULL);
-
-          err = parse_xml(ctx->xmlp, NULL, 0, TRUE);
-
-          err = svn_error_compose_create(ctx->error, err);
-
-          apr_pool_cleanup_run(ctx->pool, &ctx->xmlp, xml_parser_cleanup);
-
-          SVN_ERR(err);
-
-          add_done_item(ctx);
-
-          return svn_ra_serf__wrap_err(status, NULL);
-        }
-
-      /* feed me! */
-    }
-  /* not reached */
-}
-
 
 apr_status_t
 svn_ra_serf__credentials_callback(char **username, char **password,
@@ -1452,6 +1183,8 @@ handle_response(serf_request_t *request,
   if (!response)
     {
       /* Uh-oh. Our connection died.  */
+      handler->scheduled = FALSE;
+
       if (handler->response_error)
         {
           /* Give a handler chance to prevent request requeue. */
@@ -1673,10 +1406,14 @@ handle_response_cb(serf_request_t *reque
   /* Make sure the DONE flag is set properly and requests are cleaned up. */
   if (APR_STATUS_IS_EOF(outer_status) || APR_STATUS_IS_EOF(inner_status))
     {
+      svn_ra_serf__session_t *sess = handler->session;
       handler->done = TRUE;
+      handler->scheduled = FALSE;
       outer_status = APR_EOF;
 
-      save_error(handler->session,
+      /* We use a cached handler->session here to allow handler to free the
+         memory containing the handler */
+      save_error(sess,
                  handler->done_delegate(request, handler->done_delegate_baton,
                                         scratch_pool));
     }
@@ -1685,7 +1422,8 @@ handle_response_cb(serf_request_t *reque
     {
       handler->discard_body = TRUE; /* Discard further data */
       handler->done = TRUE; /* Mark as done */
-      return APR_EAGAIN; /* Exit context loop */
+      handler->scheduled = FALSE;
+      outer_status = APR_EAGAIN; /* Exit context loop */
     }
 
   return outer_status;
@@ -1787,24 +1525,29 @@ setup_request_cb(serf_request_t *request
 void
 svn_ra_serf__request_create(svn_ra_serf__handler_t *handler)
 {
-  SVN_ERR_ASSERT_NO_RETURN(handler->handler_pool != NULL);
-
-  /* In case HANDLER is re-queued, reset the various transient fields.
+  SVN_ERR_ASSERT_NO_RETURN(handler->handler_pool != NULL
+                           && !handler->scheduled);
 
-     ### prior to recent changes, HANDLER was constant. maybe we should
-     ### break out these processing fields, apart from the request
-     ### definition.  */
+  /* In case HANDLER is re-queued, reset the various transient fields. */
   handler->done = FALSE;
   handler->server_error = NULL;
   handler->sline.version = 0;
   handler->location = NULL;
   handler->reading_body = FALSE;
   handler->discard_body = FALSE;
+  handler->scheduled = TRUE;
+
+  /* Keeping track of the returned request object would be nice, but doesn't
+     work the way we would expect in ra_serf..
+
+     Serf sometimes creates a new request for us (and destroys the old one)
+     without telling, like when authentication failed (401/407 response.
 
-  /* ### do we ever alter the >response_handler?  */
+     We 'just' trust serf to do the right thing and expect it to tell us
+     when the state of the request changes.
 
-  /* ### do we need to hold onto the returned request object, or just
-     ### not worry about it (the serf ctx will manage it).  */
+     ### I fixed a request leak in serf in r2258 on auth failures.
+   */
   (void) serf_connection_request_create(handler->conn->conn,
                                         setup_request_cb, handler);
 }
@@ -2072,181 +1815,6 @@ svn_ra_serf__register_editor_shim_callba
   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_boolean_t got_expected_status;
-
-  if (ectx->expected_status)
-    {
-      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);
-
-  if (!ectx->handler->server_error
-      && ((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;
-      svn_error_t *err;
-      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  */
-      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?  */
-
-      err = parse_xml(ectx->parser, data, len, at_eof /* isFinal */);
-
-      err = svn_error_compose_create(ectx->inner_error, err);
-
-      if (at_eof || err)
-        {
-          /* 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
-         current Expat parsers, we stop the parser when an error occurs,
-         so we want to ignore EXPAT_STATUS (which reports the stoppage).
-
-         If an error is not present, THEN we go ahead and look for parsing
-         errors.  */
-      SVN_ERR(err);
-
-      /* The parsing went fine. What has the bucket told us?  */
-
-      if (at_eof)
-        {
-          /* 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))
-        {
-          return svn_ra_serf__wrap_err(status, NULL);
-        }
-    }
-
-  /* NOTREACHED */
-}
-
 /* Shandard done_delegate handler */
 static svn_error_t *
 response_done(serf_request_t *request,
@@ -2273,6 +1841,27 @@ response_done(serf_request_t *request,
   return SVN_NO_ERROR;
 }
 
+/* Pool cleanup handler for request handlers.
+
+   If a serf context run stops for some outside error, like when the user
+   cancels a request via ^C in the context loop, the handler is still
+   registered in the serf context. With the pool cleanup there would be
+   handlers registered in no freed memory.
+
+   This fallback kills the connection for this case, which will make serf
+   unregister any*/
+static apr_status_t
+handler_cleanup(void *baton)
+{
+  svn_ra_serf__handler_t *handler = baton;
+  if (handler->scheduled && handler->conn)
+    {
+      serf_connection_reset(handler->conn->conn);
+    }
+
+  return APR_SUCCESS;
+}
+
 svn_ra_serf__handler_t *
 svn_ra_serf__create_handler(apr_pool_t *result_pool)
 {
@@ -2281,6 +1870,9 @@ svn_ra_serf__create_handler(apr_pool_t *
   handler = apr_pcalloc(result_pool, sizeof(*handler));
   handler->handler_pool = result_pool;
 
+  apr_pool_cleanup_register(result_pool, handler, handler_cleanup,
+                            apr_pool_cleanup_null);
+
   /* Setup the default done handler, to handle server errors */
   handler->done_delegate_baton = handler;
   handler->done_delegate = response_done;
@@ -2288,27 +1880,3 @@ svn_ra_serf__create_handler(apr_pool_t *
   return handler;
 }
 
-
-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;
-  struct expat_ctx_t *ectx;
-
-  ectx = apr_pcalloc(result_pool, sizeof(*ectx));
-  ectx->xmlctx = xmlctx;
-  ectx->parser = NULL;
-  ectx->expected_status = expected_status;
-  ectx->cleanup_pool = result_pool;
-
-
-  handler = svn_ra_serf__create_handler(result_pool);
-  handler->response_handler = expat_response_handler;
-  handler->response_baton = ectx;
-
-  ectx->handler = handler;
-
-  return handler;
-}

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/xml.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/xml.c?rev=1558485&r1=1558484&r2=1558485&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/xml.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/xml.c Wed Jan 15 17:47:23 2014
@@ -24,6 +24,7 @@
 
 
 #include <apr_uri.h>
+#include <expat.h>
 #include <serf.h>
 
 #include "svn_private_config.h"
@@ -42,6 +43,30 @@
 #include "ra_serf.h"
 
 
+/* Fix for older expat 1.95.x's that do not define
+ * XML_STATUS_OK/XML_STATUS_ERROR
+ */
+#ifndef XML_STATUS_OK
+#define XML_STATUS_OK    1
+#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
+
+
 struct svn_ra_serf__xml_context_t {
   /* Current state information.  */
   svn_ra_serf__xml_estate_t *current;
@@ -85,6 +110,16 @@ struct svn_ra_serf__xml_context_t {
 
 };
 
+/* Structure which represents an XML namespace. */
+typedef struct svn_ra_serf__ns_t {
+  /* The assigned name. */
+  const char *xmlns;
+  /* The full URL for this namespace. */
+  const char *url;
+  /* The next namespace in our list. */
+  struct svn_ra_serf__ns_t *next;
+} svn_ra_serf__ns_t;
+
 struct svn_ra_serf__xml_estate_t {
   /* The current state value.  */
   int state;
@@ -116,6 +151,19 @@ struct svn_ra_serf__xml_estate_t {
 
 };
 
+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;
+
+  /* Do not use this pool for allocation. It is merely recorded for running
+     the cleanup handler.  */
+  apr_pool_t *cleanup_pool;
+};
+
 
 static void
 define_namespaces(svn_ra_serf__ns_t **ns_list,
@@ -172,22 +220,15 @@ define_namespaces(svn_ra_serf__ns_t **ns
     }
 }
 
-
-void
-svn_ra_serf__define_ns(svn_ra_serf__ns_t **ns_list,
-                       const char *const *attrs,
-                       apr_pool_t *result_pool)
-{
-  define_namespaces(ns_list, attrs, NULL /* get_pool */, result_pool);
-}
-
-
 /*
- * Look up NAME in the NS_LIST list for previously declared namespace
- * definitions and return a DAV_PROPS_T-tuple that has values.
+ * Look up @a name in the @a ns_list list for previously declared namespace
+ * definitions.
+ *
+ * Return (in @a *returned_prop_name) a #svn_ra_serf__dav_props_t tuple
+ * representing the expanded name.
  */
-void
-svn_ra_serf__expand_ns(svn_ra_serf__dav_props_t *returned_prop_name,
+static void
+expand_ns(svn_ra_serf__dav_props_t *returned_prop_name,
                        const svn_ra_serf__ns_t *ns_list,
                        const char *name)
 {
@@ -381,54 +422,6 @@ void svn_ra_serf__add_tag_buckets(serf_b
   svn_ra_serf__add_close_tag_buckets(agg_bucket, bkt_alloc, tag);
 }
 
-void
-svn_ra_serf__xml_push_state(svn_ra_serf__xml_parser_t *parser,
-                            int state)
-{
-  svn_ra_serf__xml_state_t *new_state;
-
-  if (!parser->free_state)
-    {
-      new_state = apr_palloc(parser->pool, sizeof(*new_state));
-      new_state->pool = svn_pool_create(parser->pool);
-    }
-  else
-    {
-      new_state = parser->free_state;
-      parser->free_state = parser->free_state->prev;
-
-      svn_pool_clear(new_state->pool);
-    }
-
-  if (parser->state)
-    {
-      new_state->private = parser->state->private;
-      new_state->ns_list = parser->state->ns_list;
-    }
-  else
-    {
-      new_state->private = NULL;
-      new_state->ns_list = NULL;
-    }
-
-  new_state->current_state = state;
-
-  /* Add it to the state chain. */
-  new_state->prev = parser->state;
-  parser->state = new_state;
-}
-
-void svn_ra_serf__xml_pop_state(svn_ra_serf__xml_parser_t *parser)
-{
-  svn_ra_serf__xml_state_t *cur_state;
-
-  cur_state = parser->state;
-  parser->state = cur_state->prev;
-  cur_state->prev = parser->free_state;
-  parser->free_state = cur_state;
-}
-
-
 /* Return a pool for XES to use for self-alloc (and other specifics).  */
 static apr_pool_t *
 xes_pool(const svn_ra_serf__xml_estate_t *xes)
@@ -618,10 +611,10 @@ svn_ra_serf__xml_state_pool(svn_ra_serf_
 }
 
 
-svn_error_t *
-svn_ra_serf__xml_cb_start(svn_ra_serf__xml_context_t *xmlctx,
-                          const char *raw_name,
-                          const char *const *attrs)
+static svn_error_t *
+xml_cb_start(svn_ra_serf__xml_context_t *xmlctx,
+             const char *raw_name,
+             const char *const *attrs)
 {
   svn_ra_serf__xml_estate_t *current = xmlctx->current;
   svn_ra_serf__dav_props_t elemname;
@@ -641,7 +634,7 @@ svn_ra_serf__xml_cb_start(svn_ra_serf__x
      were found.  */
   define_namespaces(&current->ns_list, attrs, lazy_create_pool, current);
 
-  svn_ra_serf__expand_ns(&elemname, current->ns_list, raw_name);
+  expand_ns(&elemname, current->ns_list, raw_name);
 
   for (scan = xmlctx->ttable; scan->ns != NULL; ++scan)
     {
@@ -767,14 +760,11 @@ svn_ra_serf__xml_cb_start(svn_ra_serf__x
 }
 
 
-svn_error_t *
-svn_ra_serf__xml_cb_end(svn_ra_serf__xml_context_t *xmlctx,
-                        const char *raw_name)
+static svn_error_t *
+xml_cb_end(svn_ra_serf__xml_context_t *xmlctx,
+           const char *raw_name)
 {
   svn_ra_serf__xml_estate_t *xes = xmlctx->current;
-  svn_ra_serf__dav_props_t elemname;
-
-  svn_ra_serf__expand_ns(&elemname, xes->ns_list, raw_name);
 
   if (xmlctx->waiting > 0)
     {
@@ -825,10 +815,10 @@ svn_ra_serf__xml_cb_end(svn_ra_serf__xml
 }
 
 
-svn_error_t *
-svn_ra_serf__xml_cb_cdata(svn_ra_serf__xml_context_t *xmlctx,
-                          const char *data,
-                          apr_size_t len)
+static svn_error_t *
+xml_cb_cdata(svn_ra_serf__xml_context_t *xmlctx,
+             const char *data,
+             apr_size_t len)
 {
   /* If we are waiting for a closing tag, then we are uninterested in
      the cdata. Just return.  */
@@ -857,3 +847,216 @@ svn_ra_serf__xml_cb_cdata(svn_ra_serf__x
   return SVN_NO_ERROR;
 }
 
+/* svn_error_t * wrapper around XML_Parse */
+static APR_INLINE svn_error_t *
+parse_xml(XML_Parser parser, const char *data, apr_size_t len, svn_boolean_t is_final)
+{
+  int xml_status = XML_Parse(parser, data, (int)len, is_final);
+  const char *msg;
+
+  /* ### Perhaps we should filter some specific error codes on systems
+         that use STOPPARSER to hide addtional errors */
+  if (xml_status == XML_STATUS_OK)
+    return SVN_NO_ERROR;
+
+  msg = XML_ErrorString(XML_GetErrorCode(parser));
+
+  return svn_error_create(SVN_ERR_RA_DAV_MALFORMED_DATA,
+                          svn_error_createf(SVN_ERR_XML_MALFORMED, NULL,
+                                            _("Malformed XML: %s"),
+                                            msg),
+                          _("The XML response contains invalid XML"));
+}
+
+/* Apr pool cleanup handler to release an XML_Parser in success and error
+   conditions */
+static apr_status_t
+xml_parser_cleanup(void *baton)
+{
+  XML_Parser *xmlp = baton;
+
+  if (*xmlp)
+    {
+      (void) XML_ParserFree(*xmlp);
+      *xmlp = NULL;
+    }
+
+  return APR_SUCCESS;
+}
+
+/* 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(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(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(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_boolean_t got_expected_status;
+
+  if (ectx->expected_status)
+    {
+      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);
+
+  if (!ectx->handler->server_error
+      && ((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;
+      svn_error_t *err;
+      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;
+
+      err = parse_xml(ectx->parser, data, len, at_eof /* isFinal */);
+
+      err = svn_error_compose_create(ectx->inner_error, err);
+
+      if (at_eof || err)
+        {
+          /* Release xml parser state/tables. */
+          apr_pool_cleanup_run(ectx->cleanup_pool, &ectx->parser,
+                               xml_parser_cleanup);
+        }
+
+      SVN_ERR(err);
+
+      /* The parsing went fine. What has the bucket told us?  */
+      if (at_eof)
+        {
+          /* 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))
+        {
+          return svn_ra_serf__wrap_err(status, NULL);
+        }
+    }
+
+  /* NOTREACHED */
+}
+
+
+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;
+  struct expat_ctx_t *ectx;
+
+  ectx = apr_pcalloc(result_pool, sizeof(*ectx));
+  ectx->xmlctx = xmlctx;
+  ectx->parser = NULL;
+  ectx->expected_status = expected_status;
+  ectx->cleanup_pool = result_pool;
+
+  handler = svn_ra_serf__create_handler(result_pool);
+  handler->response_handler = expat_response_handler;
+  handler->response_baton = ectx;
+
+  ectx->handler = handler;
+
+  return handler;
+}

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_repos/log.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_repos/log.c?rev=1558485&r1=1558484&r2=1558485&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_repos/log.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_repos/log.c Wed Jan 15 17:47:23 2014
@@ -242,8 +242,7 @@ turn_unique_copies_into_moves(apr_hash_t
     if (   (i == 0 || strcmp(sources[i-1], sources[i]))
         && (i == copy_sources->nelts-1 || strcmp(sources[i+1], sources[i])))
       {
-        apr_hash_set(unique_copy_sources, sources[i],
-                     APR_HASH_KEY_STRING, sources[i]);
+        svn_hash_sets(unique_copy_sources, sources[i], sources[i]);
       }
 
   /* no unique copy-from paths -> no moves */
@@ -264,12 +263,10 @@ turn_unique_copies_into_moves(apr_hash_t
       apr_hash_this(hi, (const void **)&key, &klen, (void**)&change);
       if (   change->copyfrom_rev != revision-1
           || !change->copyfrom_path
-          || !apr_hash_get(unique_copy_sources, change->copyfrom_path,
-                           APR_HASH_KEY_STRING))
+          || !svn_hash_gets(unique_copy_sources, change->copyfrom_path))
         continue;
 
-      copy_from_change = apr_hash_get(changes, change->copyfrom_path,
-                                      APR_HASH_KEY_STRING);
+      copy_from_change = svn_hash_gets(changes, change->copyfrom_path);
       if (!copy_from_change || !is_deletion(copy_from_change))
         continue;
 

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_subr/sqlite.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_subr/sqlite.c?rev=1558485&r1=1558484&r2=1558485&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_subr/sqlite.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_subr/sqlite.c Wed Jan 15 17:47:23 2014
@@ -109,6 +109,23 @@ sqlite_profiler(void *data, const char *
 }
 #endif
 
+#if defined(SVN_DEBUG) && defined(SQLITE_CONFIG_LOG)
+static void
+sqlite_error_log(void* baton, int err, const char* msg)
+{
+  fprintf(stderr, "DBG: sqlite[S%d]: %s\n", err, msg);
+}
+#endif
+
+void
+svn_sqlite__dbg_enable_errorlog(void)
+{
+#if defined(SVN_DEBUG) && defined(SQLITE_CONFIG_LOG)
+  sqlite3_config(SQLITE_CONFIG_LOG, sqlite_error_log, (void*)NULL /* baton */);
+#endif
+}
+
+
 struct svn_sqlite__db_t
 {
   sqlite3 *db3;

Modified: subversion/branches/fsfs-ucsnorm/subversion/mod_dav_svn/reports/update.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/mod_dav_svn/reports/update.c?rev=1558485&r1=1558484&r2=1558485&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/mod_dav_svn/reports/update.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/mod_dav_svn/reports/update.c Wed Jan 15 17:47:23 2014
@@ -127,10 +127,6 @@ typedef struct item_baton_t {
   /* File/dir copied? */
   svn_boolean_t copyfrom;
 
-  /* Does the client need to fetch additional properties for this
-     item? */
-  svn_boolean_t fetch_props;
-
   /* Array of const char * names of removed properties.  (Used only
      for copied files/dirs in skelta mode.)  */
   apr_array_header_t *removed_props;
@@ -466,12 +462,6 @@ close_helper(svn_boolean_t is_dir, item_
         }
     }
 
-  /* If our client need to fetch properties, let it know. */
-  if (baton->fetch_props)
-    SVN_ERR(dav_svn__brigade_printf(baton->uc->bb, baton->uc->output,
-                                    "<S:fetch-props/>" DEBUG_CR));
-
-
   /* Let's tie it off, nurse. */
   if (baton->added)
     SVN_ERR(dav_svn__brigade_printf(baton->uc->bb, baton->uc->output,
@@ -694,8 +684,8 @@ upd_change_xxx_prop(void *baton,
 
           /* That said, beginning in Subversion 1.8, clients might
              request even in skelta mode that we transmit properties
-             on newly added files explicitly. */
-          if ((! b->copyfrom) && value && b->uc->include_props)
+             on added files and directories explicitly. */
+          if (value && b->uc->include_props)
             {
               SVN_ERR(send_propchange(b, name, value, pool));
             }
@@ -1147,6 +1137,11 @@ dav_svn__update_report(const dav_resourc
         }
       if (child->ns == ns && strcmp(child->name, "resource-walk") == 0)
         {
+          /* This flag is not used since Subversion 1.1.x
+             There are some remains in libsvn_ra_neon, where it can
+             be enabled via a static function flag.
+             Disabled since  r852220 (aka r12146)
+             "Prefer correctness over efficiency." */
           cdata = dav_xml_get_cdata(child, resource->pool, 1);
           if (! *cdata)
             return malformed_element_error(child->name, resource->pool);

Modified: subversion/branches/fsfs-ucsnorm/subversion/mod_dav_svn/repos.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/mod_dav_svn/repos.c?rev=1558485&r1=1558484&r2=1558485&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/mod_dav_svn/repos.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/mod_dav_svn/repos.c Wed Jan 15 17:47:23 2014
@@ -1795,7 +1795,11 @@ do_out_of_date_check(dav_resource_combin
   if (comb->priv.version_name < created_rev)
     {
       serr = svn_error_createf(SVN_ERR_RA_OUT_OF_DATE, NULL,
-                               "Item '%s' is out of date",
+                               comb->res.collection
+                                ? "Directory '%s' is out of date"
+                                : (comb->res.exists
+                                    ? "File '%s' is out of date"
+                                    : "'%s' is out of date"),
                                comb->priv.repos_path);
       return dav_svn__convert_err(serr, HTTP_CONFLICT,
                                   "Attempting to modify out-of-date resource.",
@@ -1973,6 +1977,25 @@ get_resource(request_rec *r,
      of private resource, iff the SVNListParentPath directive is 'on'. */
   if (dav_svn__is_parentpath_list(r))
     {
+      /* Only allow GET and HEAD on the parentpath resource
+       * httpd uses the same method_number for HEAD as GET */
+      if (r->method_number != M_GET)
+        {
+          int status;
+
+          /* Marshall the error back to the client by generating by
+           * way of the dav_svn__error_response_tag trick. */
+          err = dav_svn__new_error(r->pool, HTTP_METHOD_NOT_ALLOWED,
+                                   SVN_ERR_APMOD_MALFORMED_URI,
+                                   "The URI does not contain the name "
+                                   "of a repository.");
+          /* can't use r->allowed since the default handler isn't called */
+          apr_table_setn(r->headers_out, "Allow", "GET,HEAD");
+          status = dav_svn__error_response_tag(r, err);
+
+          return dav_push_error(r->pool, status, err->error_id, NULL, err);
+        }
+
       err = get_parentpath_resource(r, resource);
       if (err)
         return err;
@@ -3927,7 +3950,11 @@ remove_resource(dav_resource *resource, 
       if (resource->info->version_name < created_rev)
         {
           serr = svn_error_createf(SVN_ERR_RA_OUT_OF_DATE, NULL,
-                                   "Item '%s' is out of date",
+                                   resource->collection
+                                    ? "Directory '%s' is out of date"
+                                    : (resource->exists
+                                        ? "File '%s' is out of date"
+                                        : "'%s' is out of date"),
                                    resource->info->repos_path);
           return dav_svn__convert_err(serr, HTTP_CONFLICT,
                                       "Can't DELETE out-of-date resource",

Modified: subversion/branches/fsfs-ucsnorm/subversion/mod_dav_svn/version.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/mod_dav_svn/version.c?rev=1558485&r1=1558484&r2=1558485&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/mod_dav_svn/version.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/mod_dav_svn/version.c Wed Jan 15 17:47:23 2014
@@ -182,23 +182,29 @@ get_option(const dav_resource *resource,
                        SVN_IGNORED_REVNUM, "", 0, resource->pool);
 
   /* ### DAV:version-history-collection-set */
-  if (elem->ns == APR_XML_NS_DAV_ID)
+  if (elem->ns != APR_XML_NS_DAV_ID
+      || strcmp(elem->name, "activity-collection-set") != 0)
     {
-      if (strcmp(elem->name, "activity-collection-set") == 0)
-        {
-          apr_text_append(resource->pool, option,
-                          "<D:activity-collection-set>");
-          apr_text_append(resource->pool, option,
-                          dav_svn__build_uri(resource->info->repos,
-                                             DAV_SVN__BUILD_URI_ACT_COLLECTION,
-                                             SVN_INVALID_REVNUM, NULL,
-                                             1 /* add_href */,
-                                             resource->pool));
-          apr_text_append(resource->pool, option,
-                          "</D:activity-collection-set>");
-        }
+       /* We don't know about other options (yet).
+
+          If we ever add multiple option request keys we should
+          just write the requested option value and make sure
+          we set the headers *once*. */
+      return NULL;
     }
 
+  apr_text_append(resource->pool, option,
+                  "<D:activity-collection-set>");
+
+  apr_text_append(resource->pool, option,
+                  dav_svn__build_uri(resource->info->repos,
+                                     DAV_SVN__BUILD_URI_ACT_COLLECTION,
+                                     SVN_INVALID_REVNUM, NULL,
+                                     1 /* add_href */,
+                                     resource->pool));
+  apr_text_append(resource->pool, option,
+                  "</D:activity-collection-set>");
+
   /* If we're allowed (by configuration) to do so, advertise support
      for ephemeral transaction properties. */
   if (dav_svn__check_ephemeral_txnprops_support(r))

Modified: subversion/branches/fsfs-ucsnorm/subversion/svnrdump/dump_editor.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/svnrdump/dump_editor.c?rev=1558485&r1=1558484&r2=1558485&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/svnrdump/dump_editor.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/svnrdump/dump_editor.c Wed Jan 15 17:47:23 2014
@@ -121,13 +121,6 @@ struct file_baton
   svn_boolean_t dump_props;
 };
 
-/* A handler baton to be used in window_handler().  */
-struct handler_baton
-{
-  svn_txdelta_window_handler_t apply_handler;
-  void *apply_baton;
-};
-
 /* The baton used by the dump editor. */
 struct dump_edit_baton {
   /* The output stream we write the dumpfile to */
@@ -187,31 +180,38 @@ make_dir_baton(const char *path,
   struct dump_edit_baton *eb = edit_baton;
   struct dir_baton *new_db = apr_pcalloc(pool, sizeof(*new_db));
   const char *repos_relpath;
+  apr_pool_t *dir_pool;
 
   /* Construct the full path of this node. */
   if (pb)
-    repos_relpath = svn_relpath_canonicalize(path, pool);
+    {
+      dir_pool = svn_pool_create(pb->pool);
+      repos_relpath = svn_relpath_canonicalize(path, dir_pool);
+    }
   else
-    repos_relpath = "";
+    {
+      dir_pool = svn_pool_create(eb->pool);
+      repos_relpath = "";
+    }
 
   /* Strip leading slash from copyfrom_path so that the path is
      canonical and svn_relpath_join can be used */
   if (copyfrom_path)
-    copyfrom_path = svn_relpath_canonicalize(copyfrom_path, pool);
+    copyfrom_path = svn_relpath_canonicalize(copyfrom_path, dir_pool);
 
   new_db->eb = eb;
   new_db->parent_dir_baton = pb;
-  new_db->pool = pool;
+  new_db->pool = dir_pool;
   new_db->repos_relpath = repos_relpath;
   new_db->copyfrom_path = copyfrom_path
-                            ? svn_relpath_canonicalize(copyfrom_path, pool)
+                            ? svn_relpath_canonicalize(copyfrom_path, dir_pool)
                             : NULL;
   new_db->copyfrom_rev = copyfrom_rev;
   new_db->added = added;
   new_db->written_out = FALSE;
-  new_db->props = apr_hash_make(pool);
-  new_db->deleted_props = apr_hash_make(pool);
-  new_db->deleted_entries = apr_hash_make(pool);
+  new_db->props = apr_hash_make(dir_pool);
+  new_db->deleted_props = apr_hash_make(dir_pool);
+  new_db->deleted_entries = apr_hash_make(dir_pool);
 
   return new_db;
 }
@@ -225,14 +225,15 @@ make_file_baton(const char *path,
                 struct dir_baton *pb,
                 apr_pool_t *pool)
 {
-  struct file_baton *new_fb = apr_pcalloc(pool, sizeof(*new_fb));
+  apr_pool_t *file_pool = svn_pool_create(pb->pool);
+  struct file_baton *new_fb = apr_pcalloc(file_pool, sizeof(*new_fb));
 
   new_fb->eb = pb->eb;
   new_fb->parent_dir_baton = pb;
-  new_fb->pool = pool;
-  new_fb->repos_relpath = svn_relpath_canonicalize(path, pool);
-  new_fb->props = apr_hash_make(pool);
-  new_fb->deleted_props = apr_hash_make(pool);
+  new_fb->pool = file_pool;
+  new_fb->repos_relpath = svn_relpath_canonicalize(path, file_pool);
+  new_fb->props = apr_hash_make(file_pool);
+  new_fb->deleted_props = apr_hash_make(file_pool);
   new_fb->is_copy = FALSE;
   new_fb->copyfrom_path = NULL;
   new_fb->copyfrom_rev = SVN_INVALID_REVNUM;
@@ -670,7 +671,7 @@ delete_entry(const char *path,
      to the deleted_entries of the parent directory baton.  That way,
      we can tell (later) an addition from a replacement.  All the real
      deletions get handled in close_directory().  */
-  svn_hash_sets(pb->deleted_entries, apr_pstrdup(pb->eb->pool, path), pb);
+  svn_hash_sets(pb->deleted_entries, apr_pstrdup(pb->pool, path), pb);
 
   return SVN_NO_ERROR;
 }
@@ -693,7 +694,7 @@ add_directory(const char *path,
   SVN_ERR(dump_pending(pb->eb, pool));
 
   new_db = make_dir_baton(path, copyfrom_path, copyfrom_rev, pb->eb,
-                          pb, TRUE, pb->eb->pool);
+                          pb, TRUE, pb->pool);
 
   /* This might be a replacement -- is the path already deleted? */
   val = svn_hash_gets(pb->deleted_entries, path);
@@ -745,12 +746,12 @@ open_directory(const char *path,
     {
       copyfrom_path = svn_relpath_join(pb->copyfrom_path,
                                        svn_relpath_basename(path, NULL),
-                                       pb->eb->pool);
+                                       pb->pool);
       copyfrom_rev = pb->copyfrom_rev;
     }
 
   new_db = make_dir_baton(path, copyfrom_path, copyfrom_rev, pb->eb, pb,
-                          FALSE, pb->eb->pool);
+                          FALSE, pb->pool);
 
   *child_baton = new_db;
   return SVN_NO_ERROR;
@@ -801,7 +802,7 @@ close_directory(void *dir_baton,
     }
 
   /* ### should be unnecessary */
-  apr_hash_clear(db->deleted_entries);
+  svn_pool_destroy(db->pool);
 
   return SVN_NO_ERROR;
 }
@@ -868,7 +869,7 @@ open_file(const char *path,
     {
       fb->copyfrom_path = svn_relpath_join(pb->copyfrom_path,
                                            svn_relpath_basename(path, NULL),
-                                           pb->eb->pool);
+                                           pb->pool);
       fb->copyfrom_rev = pb->copyfrom_rev;
     }
 
@@ -940,22 +941,6 @@ change_file_prop(void *file_baton,
 }
 
 static svn_error_t *
-window_handler(svn_txdelta_window_t *window, void *baton)
-{
-  struct handler_baton *hb = baton;
-  static svn_error_t *err;
-
-  err = hb->apply_handler(window, hb->apply_baton);
-  if (window != NULL && !err)
-    return SVN_NO_ERROR;
-
-  if (err)
-    SVN_ERR(err);
-
-  return SVN_NO_ERROR;
-}
-
-static svn_error_t *
 apply_textdelta(void *file_baton, const char *base_checksum,
                 apr_pool_t *pool,
                 svn_txdelta_window_handler_t *handler,
@@ -963,31 +948,21 @@ apply_textdelta(void *file_baton, const 
 {
   struct file_baton *fb = file_baton;
   struct dump_edit_baton *eb = fb->eb;
-  struct handler_baton *hb;
   svn_stream_t *delta_filestream;
 
   LDR_DBG(("apply_textdelta %p\n", file_baton));
 
-  /* This is custom handler_baton, allocated from a separate pool.  */
-  hb = apr_pcalloc(eb->pool, sizeof(*hb));
-
   /* Use a temporary file to measure the Text-content-length */
   delta_filestream = svn_stream_from_aprfile2(eb->delta_file, TRUE, pool);
 
   /* Prepare to write the delta to the delta_filestream */
-  svn_txdelta_to_svndiff3(&(hb->apply_handler), &(hb->apply_baton),
+  svn_txdelta_to_svndiff3(handler, handler_baton,
                           delta_filestream, 0,
                           SVN_DELTA_COMPRESSION_LEVEL_DEFAULT, pool);
 
   /* Record that there's text to be dumped, and its base checksum. */
   fb->dump_text = TRUE;
-  fb->base_checksum = apr_pstrdup(eb->pool, base_checksum);
-
-  /* The actual writing takes place when this function has
-     finished. Set handler and handler_baton now so for
-     window_handler() */
-  *handler = window_handler;
-  *handler_baton = hb;
+  fb->base_checksum = apr_pstrdup(fb->pool, base_checksum);
 
   return SVN_NO_ERROR;
 }
@@ -1100,6 +1075,8 @@ close_file(void *file_baton,
      dump` */
   SVN_ERR(svn_stream_puts(eb->stream, "\n\n"));
 
+  svn_pool_clear(fb->pool);
+
   return SVN_NO_ERROR;
 }
 

Modified: subversion/branches/fsfs-ucsnorm/subversion/svnserve/logger.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/svnserve/logger.c?rev=1558485&r1=1558484&r2=1558485&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/svnserve/logger.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/svnserve/logger.c Wed Jan 15 17:47:23 2014
@@ -52,28 +52,16 @@ struct logger_t
   apr_pool_t *pool;
 };
 
-/* Pool cleanup handler.  Make sure we destroy our private pool as well. */
-static apr_status_t cleanup_logger(void *data)
-{
-  logger_t *logger = data;
-  svn_pool_destroy(logger->pool);
-
-  return APR_SUCCESS;
-}
-
 svn_error_t *
 logger__create_for_stderr(logger_t **logger,
                           apr_pool_t *pool)
 {
   logger_t *result = apr_pcalloc(pool, sizeof(*result));
-  result->pool = svn_pool_create(NULL);
+  result->pool = svn_pool_create(pool);
   
   SVN_ERR(svn_stream_for_stderr(&result->stream, pool));
   SVN_ERR(svn_mutex__init(&result->mutex, TRUE, pool));
 
-  apr_pool_cleanup_register(pool, result, cleanup_logger,
-                            apr_pool_cleanup_null);
-  
   *logger = result;
 
   return SVN_NO_ERROR;
@@ -93,11 +81,8 @@ logger__create(logger_t **logger,
   SVN_ERR(svn_mutex__init(&result->mutex, TRUE, pool));
 
   result->stream = svn_stream_from_aprfile2(file, FALSE,  pool);
-  result->pool = svn_pool_create(NULL);
-  
-  apr_pool_cleanup_register(pool, result, cleanup_logger,
-                            apr_pool_cleanup_null);
-  
+  result->pool = svn_pool_create(pool);
+
   *logger = result;
 
   return SVN_NO_ERROR;

Modified: subversion/branches/fsfs-ucsnorm/subversion/svnserve/serve.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/svnserve/serve.c?rev=1558485&r1=1558484&r2=1558485&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/svnserve/serve.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/svnserve/serve.c Wed Jan 15 17:47:23 2014
@@ -97,7 +97,6 @@ typedef struct file_revs_baton_t {
 typedef struct fs_warning_baton_t {
   server_baton_t *server;
   svn_ra_svn_conn_t *conn;
-  apr_pool_t *pool;
 } fs_warning_baton_t;
 
 typedef struct authz_baton_t {
@@ -3438,8 +3437,6 @@ fs_warning_func(void *baton, svn_error_t
 {
   fs_warning_baton_t *b = baton;
   log_error(err, b->server);
-  /* TODO: Keep log_pool in the server baton, cleared after every log? */
-  svn_pool_clear(b->pool);
 }
 
 /* Return the normalized repository-relative path for the given PATH
@@ -3779,7 +3776,6 @@ construct_server_baton(server_baton_t **
   warn_baton = apr_pcalloc(scratch_pool, sizeof(*warn_baton));
   warn_baton->server = b;
   warn_baton->conn = conn;
-  warn_baton->pool = svn_pool_create(scratch_pool);
   svn_fs_set_warning_func(b->repository->fs, fs_warning_func, warn_baton);
 
   /* Set up editor shims. */
@@ -3833,7 +3829,6 @@ reopen_repos(connection_t *connection,
   
   warn_baton->server = connection->baton;
   warn_baton->conn = connection->conn;
-  warn_baton->pool = svn_pool_create(pool);
   svn_fs_set_warning_func(connection->baton->repository->fs,
                           fs_warning_func, &warn_baton);
 

Modified: subversion/branches/fsfs-ucsnorm/subversion/tests/cmdline/prop_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/tests/cmdline/prop_tests.py?rev=1558485&r1=1558484&r2=1558485&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/tests/cmdline/prop_tests.py (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/tests/cmdline/prop_tests.py Wed Jan 15 17:47:23 2014
@@ -2654,6 +2654,55 @@ def xml_unsafe_author(sbox):
                                      'proplist', '--revprop', '-r', '1',
                                      wc_dir)
 
+def dir_prop_conflict_details(sbox):
+  "verify dir property conflict details"
+
+  sbox.build()
+  wc_dir = sbox.wc_dir
+
+  # Apply some changes
+  sbox.simple_propset('svn:mergeinfo', '/B:1', 'A')
+  sbox.simple_propset('my-prop', 'my-val', 'A')
+  sbox.simple_commit()
+
+  # Revert to r1
+  sbox.simple_update('', revision=1)
+
+  # Apply some incompatible changes
+  sbox.simple_propset('svn:mergeinfo', '/C:1', 'A')
+  sbox.simple_propset('my-prop', 'other-val', 'A')
+
+  # This should report out of date because there are incompatible property
+  # changes that can't be merged on the server
+  svntest.actions.run_and_verify_commit(wc_dir,
+                                        None,
+                                        None,
+                                        '.*[Oo]ut of date.*',
+                                        wc_dir)
+
+  expected_output = svntest.wc.State(wc_dir, {
+    'A'                 : Item(status=' C'),
+  })
+  expected_status = svntest.actions.get_virginal_state(wc_dir, 2)
+  expected_status.tweak('A', status=' C')
+
+  svntest.actions.run_and_verify_update(wc_dir,
+                                        expected_output,
+                                        None,
+                                        expected_status,
+                                        None, None, None, None, None, 1,
+                                        wc_dir)
+
+  # The conflict properties file line was shown for previous versions, but the
+  # conflict source urls are new since 1.8.
+  expected_info = {
+    'Conflict Properties File' : re.escape(os.path.abspath(
+                                           sbox.ospath('A/dir_conflicts.prej'))
+                                           + ' Source  left: (dir) ^/A@1'
+                                           + ' Source right: (dir) ^/A@2')
+  }
+  svntest.actions.run_and_verify_info([expected_info], sbox.path('A'))
+
 
 ########################################################################
 # Run the tests
@@ -2701,6 +2750,7 @@ test_list = [ None,
               almost_known_prop_names,
               peg_rev_base_working,
               xml_unsafe_author,
+              dir_prop_conflict_details,
              ]
 
 if __name__ == '__main__':

Modified: subversion/branches/fsfs-ucsnorm/subversion/tests/libsvn_fs/fs-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/tests/libsvn_fs/fs-test.c?rev=1558485&r1=1558484&r2=1558485&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/tests/libsvn_fs/fs-test.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/tests/libsvn_fs/fs-test.c Wed Jan 15 17:47:23 2014
@@ -4582,6 +4582,7 @@ unordered_txn_dirprops(const svn_test_op
   svn_fs_root_t *txn_root, *txn_root2;
   svn_string_t pval;
   svn_revnum_t new_rev, not_rev;
+  svn_boolean_t is_bdb = strcmp(opts->fs_type, "bdb") == 0;
 
   /* This is a regression test for issue #2751. */
 
@@ -4638,10 +4639,21 @@ unordered_txn_dirprops(const svn_test_op
   /* Commit the first one first. */
   SVN_ERR(test_commit_txn(&new_rev, txn, NULL, pool));
 
-  /* Then commit the second -- but expect an conflict because the
-     directory wasn't up-to-date, which is required for propchanges. */
-  SVN_ERR(test_commit_txn(&not_rev, txn2, "/A/B", pool));
-  SVN_ERR(svn_fs_abort_txn(txn2, pool));
+  /* Some backends are clever then others. */
+  if (is_bdb)
+    {
+      /* Then commit the second -- but expect an conflict because the
+         directory wasn't up-to-date, which is required for propchanges. */
+      SVN_ERR(test_commit_txn(&not_rev, txn2, "/A/B", pool));
+      SVN_ERR(svn_fs_abort_txn(txn2, pool));
+    }
+  else
+    {
+      /* Then commit the second -- there will be no conflict despite the
+         directory being out-of-data because the properties as well as the
+         directory structure (list of nodes) was up-to-date. */
+      SVN_ERR(test_commit_txn(&not_rev, txn2, NULL, pool));
+    }
 
   return SVN_NO_ERROR;
 }
@@ -5222,6 +5234,80 @@ test_compat_version(const svn_test_opts_
   return SVN_NO_ERROR;
 }
 
+static svn_error_t *
+dir_prop_merge(const svn_test_opts_t *opts,
+               apr_pool_t *pool)
+{
+  svn_fs_t *fs;
+  svn_revnum_t head_rev;
+  svn_fs_root_t *root;
+  svn_fs_txn_t *txn, *mid_txn, *top_txn, *sub_txn, *c_txn;
+  svn_boolean_t is_bdb = strcmp(opts->fs_type, "bdb") == 0;
+
+  /* Create test repository. */
+  SVN_ERR(svn_test__create_fs(&fs, "test-dir_prop-merge", opts, pool));
+
+  SVN_ERR(svn_fs_begin_txn(&txn, fs, 0, pool));
+  SVN_ERR(svn_fs_txn_root(&root, txn, pool));
+
+  /* Create and verify the greek tree. */
+  SVN_ERR(svn_test__create_greek_tree(root, pool));
+  SVN_ERR(test_commit_txn(&head_rev, txn, NULL, pool));
+
+  /* Start concurrent transactions */
+
+  /* 1st: modify a mid-level directory */
+  SVN_ERR(svn_fs_begin_txn2(&mid_txn, fs, head_rev, 0, pool));
+  SVN_ERR(svn_fs_txn_root(&root, mid_txn, pool));
+  SVN_ERR(svn_fs_change_node_prop(root, "A/D", "test-prop",
+                                  svn_string_create("val1", pool), pool));
+  svn_fs_close_root(root);
+
+  /* 2st: modify a top-level directory */
+  SVN_ERR(svn_fs_begin_txn2(&top_txn, fs, head_rev, 0, pool));
+  SVN_ERR(svn_fs_txn_root(&root, top_txn, pool));
+  SVN_ERR(svn_fs_change_node_prop(root, "A", "test-prop",
+                                  svn_string_create("val2", pool), pool));
+  svn_fs_close_root(root);
+
+  SVN_ERR(svn_fs_begin_txn2(&sub_txn, fs, head_rev, 0, pool));
+  SVN_ERR(svn_fs_txn_root(&root, sub_txn, pool));
+  SVN_ERR(svn_fs_change_node_prop(root, "A/D/G", "test-prop",
+                                  svn_string_create("val3", pool), pool));
+  svn_fs_close_root(root);
+
+  /* 3rd: modify a conflicting change to the mid-level directory */
+  SVN_ERR(svn_fs_begin_txn2(&c_txn, fs, head_rev, 0, pool));
+  SVN_ERR(svn_fs_txn_root(&root, c_txn, pool));
+  SVN_ERR(svn_fs_change_node_prop(root, "A/D", "test-prop",
+                                  svn_string_create("valX", pool), pool));
+  svn_fs_close_root(root);
+
+  /* Prop changes to the same node should conflict */
+  SVN_ERR(test_commit_txn(&head_rev, mid_txn, NULL, pool));
+  SVN_ERR(test_commit_txn(&head_rev, c_txn, "/A/D", pool));
+  SVN_ERR(svn_fs_abort_txn(c_txn, pool));
+
+  /* Changes in a sub-tree should not conflict with prop changes to some
+     parent directory but some backends are clever then others. */
+  if (is_bdb)
+    {
+      SVN_ERR(test_commit_txn(&head_rev, top_txn, "/A", pool));
+      SVN_ERR(svn_fs_abort_txn(top_txn, pool));
+    }
+  else
+    {
+      SVN_ERR(test_commit_txn(&head_rev, top_txn, NULL, pool));
+    }
+
+  /* The inverted case is not that trivial to handle.  Hence, conflict.
+     Depending on the checking order, the reported conflict path differs. */
+  SVN_ERR(test_commit_txn(&head_rev, sub_txn, is_bdb ? "/A/D" : "/A", pool));
+  SVN_ERR(svn_fs_abort_txn(sub_txn, pool));
+
+  return SVN_NO_ERROR;
+}
+
 
 /* ------------------------------------------------------------------------ */
 
@@ -5315,5 +5401,7 @@ struct svn_test_descriptor_t test_funcs[
                        "commit timestamp"),
     SVN_TEST_OPTS_PASS(test_compat_version,
                        "test svn_fs__compatible_version"),
+    SVN_TEST_OPTS_PASS(dir_prop_merge,
+                       "test merge directory properties"),
     SVN_TEST_NULL
   };

Modified: subversion/branches/fsfs-ucsnorm/subversion/tests/svn_test_main.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/tests/svn_test_main.c?rev=1558485&r1=1558484&r2=1558485&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/tests/svn_test_main.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/tests/svn_test_main.c Wed Jan 15 17:47:23 2014
@@ -49,6 +49,7 @@
 #include "private/svn_cmdline_private.h"
 #include "private/svn_atomic.h"
 #include "private/svn_mutex.h"
+#include "private/svn_sqlite.h"
 
 #include "svn_private_config.h"
 
@@ -715,6 +716,11 @@ main(int argc, const char *argv[])
 #endif /* _MSC_VER >= 1400 */
 #endif
 
+  /* Temporary code: Enable Sqlite error log to diagnose buildbot issue.
+     ### Perhaps we should later attach this to an environment variable? */
+  svn_sqlite__dbg_enable_errorlog();
+  /* /Temporary code */
+
   if (err)
     return svn_cmdline_handle_exit_error(err, pool, prog_name);
   while (1)