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/09 10:31:15 UTC

svn commit: r1556765 [8/12] - in /subversion/branches/fsfs-ucsnorm: ./ contrib/server-side/fsfsfixer/fixer/ subversion/bindings/javahl/native/ subversion/bindings/javahl/native/jniwrapper/ subversion/bindings/javahl/src/org/apache/subversion/javahl/ su...

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=1556765&r1=1556764&r2=1556765&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/util.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/util.c Thu Jan  9 09:31:10 2014
@@ -76,25 +76,6 @@
 /* Read/write chunks of this size into the spillbuf.  */
 #define PARSE_CHUNK_SIZE 8000
 
-/* We will store one megabyte in memory, before switching to store content
-   into a temporary file.  */
-#define SPILL_SIZE 1000000
-
-
-/* This structure records pending data for the parser in memory blocks,
-   and possibly into a temporary file if "too much" content arrives.  */
-struct svn_ra_serf__pending_t {
-  /* The spillbuf where we record the pending data.  */
-  svn_spillbuf_t *buf;
-
-  /* This flag is set when the network has reached EOF. The PENDING
-     processing can then properly detect when parsing has completed.  */
-  svn_boolean_t network_eof;
-};
-
-#define HAS_PENDING_DATA(p) ((p) != NULL && (p)->buf != NULL \
-                             && svn_spillbuf__get_size((p)->buf) != 0)
-
 
 struct expat_ctx_t {
   svn_ra_serf__xml_context_t *xmlctx;
@@ -884,6 +865,72 @@ setup_serf_req(serf_request_t *request,
 }
 
 svn_error_t *
+svn_ra_serf__context_run(svn_ra_serf__session_t *sess,
+                         apr_interval_time_t *waittime_left,
+                         apr_pool_t *scratch_pool)
+{
+  apr_status_t status;
+  svn_error_t *err;
+  assert(sess->pending_error == SVN_NO_ERROR);
+
+  if (sess->cancel_func)
+    SVN_ERR(sess->cancel_func(sess->cancel_baton));
+
+  status = serf_context_run(sess->context,
+                            SVN_RA_SERF__CONTEXT_RUN_DURATION,
+                            scratch_pool);
+
+  err = sess->pending_error;
+  sess->pending_error = SVN_NO_ERROR;
+
+   /* If the context duration timeout is up, we'll subtract that
+      duration from the total time alloted for such things.  If
+      there's no time left, we fail with a message indicating that
+      the connection timed out.  */
+  if (APR_STATUS_IS_TIMEUP(status))
+    {
+      status = 0;
+
+      if (sess->timeout)
+        {
+          if (*waittime_left > SVN_RA_SERF__CONTEXT_RUN_DURATION)
+            {
+              *waittime_left -= SVN_RA_SERF__CONTEXT_RUN_DURATION;
+            }
+          else
+            {
+              return
+                  svn_error_compose_create(
+                        err,
+                        svn_error_create(SVN_ERR_RA_DAV_CONN_TIMEOUT, NULL,
+                                         _("Connection timed out")));
+            }
+        }
+    }
+  else
+    {
+      *waittime_left = sess->timeout;
+    }
+
+  SVN_ERR(err);
+  if (status)
+    {
+      /* ### This omits SVN_WARNING, and possibly relies on the fact that
+         ### MAX(SERF_ERROR_*) < SVN_ERR_BAD_CATEGORY_START? */
+      if (status >= SVN_ERR_BAD_CATEGORY_START && status < SVN_ERR_LAST)
+        {
+          /* apr can't translate subversion errors to text */
+          SVN_ERR_W(svn_error_create(status, NULL, NULL),
+                    _("Error running context"));
+        }
+
+      return svn_ra_serf__wrap_err(status, _("Error running context"));
+    }
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
 svn_ra_serf__context_run_wait(svn_boolean_t *done,
                               svn_ra_serf__session_t *sess,
                               apr_pool_t *scratch_pool)
@@ -896,65 +943,11 @@ svn_ra_serf__context_run_wait(svn_boolea
   iterpool = svn_pool_create(scratch_pool);
   while (!*done)
     {
-      apr_status_t status;
-      svn_error_t *err;
       int i;
 
       svn_pool_clear(iterpool);
 
-      if (sess->cancel_func)
-        SVN_ERR((*sess->cancel_func)(sess->cancel_baton));
-
-      status = serf_context_run(sess->context,
-                                SVN_RA_SERF__CONTEXT_RUN_DURATION,
-                                iterpool);
-
-      err = sess->pending_error;
-      sess->pending_error = SVN_NO_ERROR;
-
-      /* If the context duration timeout is up, we'll subtract that
-         duration from the total time alloted for such things.  If
-         there's no time left, we fail with a message indicating that
-         the connection timed out.  */
-      if (APR_STATUS_IS_TIMEUP(status))
-        {
-          status = 0;
-
-          if (sess->timeout)
-            {
-              if (waittime_left > SVN_RA_SERF__CONTEXT_RUN_DURATION)
-                {
-                  waittime_left -= SVN_RA_SERF__CONTEXT_RUN_DURATION;
-                }
-              else
-                {
-                  return
-                      svn_error_compose_create(
-                            err,
-                            svn_error_create(SVN_ERR_RA_DAV_CONN_TIMEOUT, NULL,
-                                             _("Connection timed out")));
-                }
-            }
-        }
-      else
-        {
-          waittime_left = sess->timeout;
-        }
-
-      SVN_ERR(err);
-      if (status)
-        {
-          /* ### This omits SVN_WARNING, and possibly relies on the fact that
-             ### MAX(SERF_ERROR_*) < SVN_ERR_BAD_CATEGORY_START? */
-          if (status >= SVN_ERR_BAD_CATEGORY_START && status < SVN_ERR_LAST)
-            {
-              /* apr can't translate subversion errors to text */
-              SVN_ERR_W(svn_error_create(status, NULL, NULL),
-                        _("Error running context"));
-            }
-
-          return svn_ra_serf__wrap_err(status, _("Error running context"));
-        }
+      SVN_ERR(svn_ra_serf__context_run(sess, &waittime_left, iterpool));
 
       /* Debugging purposes only! */
       for (i = 0; i < sess->num_conns; i++)
@@ -997,114 +990,10 @@ svn_ra_serf__context_run_one(svn_ra_serf
                                        svn_ra_serf__wrap_err(status, NULL));
     }
 
-  if (handler->server_error)
-    {
-      err = svn_error_compose_create(err, handler->server_error->error);
-      handler->server_error = NULL;
-    }
-
   return svn_error_trace(err);
 }
 
 
-/*
- * Expat callback invoked on a start element tag for an error response.
- */
-static svn_error_t *
-start_error(svn_ra_serf__xml_parser_t *parser,
-            svn_ra_serf__dav_props_t name,
-            const char **attrs,
-            apr_pool_t *scratch_pool)
-{
-  svn_ra_serf__server_error_t *ctx = parser->user_data;
-
-  if (!ctx->in_error &&
-      strcmp(name.namespace, "DAV:") == 0 &&
-      strcmp(name.name, "error") == 0)
-    {
-      ctx->in_error = TRUE;
-    }
-  else if (ctx->in_error && strcmp(name.name, "human-readable") == 0)
-    {
-      const char *err_code;
-
-      err_code = svn_xml_get_attr_value("errcode", attrs);
-      if (err_code)
-        {
-          apr_int64_t val;
-
-          SVN_ERR(svn_cstring_atoi64(&val, err_code));
-          ctx->error->apr_err = (apr_status_t)val;
-        }
-
-      /* If there's no error code provided, or if the provided code is
-         0 (which can happen sometimes depending on how the error is
-         constructed on the server-side), just pick a generic error
-         code to run with. */
-      if (! ctx->error->apr_err)
-        {
-          ctx->error->apr_err = SVN_ERR_RA_DAV_REQUEST_FAILED;
-        }
-
-      /* Start collecting cdata. */
-      svn_stringbuf_setempty(ctx->cdata);
-      ctx->collect_cdata = TRUE;
-    }
-
-  return SVN_NO_ERROR;
-}
-
-/*
- * Expat callback invoked on an end element tag for a PROPFIND response.
- */
-static svn_error_t *
-end_error(svn_ra_serf__xml_parser_t *parser,
-          svn_ra_serf__dav_props_t name,
-          apr_pool_t *scratch_pool)
-{
-  svn_ra_serf__server_error_t *ctx = parser->user_data;
-
-  if (ctx->in_error &&
-      strcmp(name.namespace, "DAV:") == 0 &&
-      strcmp(name.name, "error") == 0)
-    {
-      ctx->in_error = FALSE;
-    }
-  if (ctx->in_error && strcmp(name.name, "human-readable") == 0)
-    {
-      /* On the server dav_error_response_tag() will add a leading
-         and trailing newline if DEBUG_CR is defined in mod_dav.h,
-         so remove any such characters here. */
-      svn_stringbuf_strip_whitespace(ctx->cdata);
-
-      ctx->error->message = apr_pstrmemdup(ctx->error->pool, ctx->cdata->data,
-                                           ctx->cdata->len);
-      ctx->collect_cdata = FALSE;
-    }
-
-  return SVN_NO_ERROR;
-}
-
-/*
- * Expat callback invoked on CDATA elements in an error response.
- *
- * This callback can be called multiple times.
- */
-static svn_error_t *
-cdata_error(svn_ra_serf__xml_parser_t *parser,
-            const char *data,
-            apr_size_t len,
-            apr_pool_t *scratch_pool)
-{
-  svn_ra_serf__server_error_t *ctx = parser->user_data;
-
-  if (ctx->collect_cdata)
-    {
-      svn_stringbuf_appendbytes(ctx->cdata, data, len);
-    }
-
-  return SVN_NO_ERROR;
-}
 
 
 static apr_status_t
@@ -1124,28 +1013,7 @@ drain_bucket(serf_bucket_t *bucket)
 }
 
 
-static svn_ra_serf__server_error_t *
-begin_error_parsing(svn_ra_serf__xml_start_element_t start,
-                    svn_ra_serf__xml_end_element_t end,
-                    svn_ra_serf__xml_cdata_chunk_handler_t cdata,
-                    apr_pool_t *result_pool)
-{
-  svn_ra_serf__server_error_t *server_err;
-
-  server_err = apr_pcalloc(result_pool, sizeof(*server_err));
-  server_err->error = svn_error_create(APR_SUCCESS, NULL, NULL);
-  server_err->contains_precondition_error = FALSE;
-  server_err->cdata = svn_stringbuf_create_empty(server_err->error->pool);
-  server_err->collect_cdata = FALSE;
-  server_err->parser.pool = server_err->error->pool;
-  server_err->parser.user_data = server_err;
-  server_err->parser.start = start;
-  server_err->parser.end = end;
-  server_err->parser.cdata = cdata;
-  server_err->parser.ignore_errors = TRUE;
 
-  return server_err;
-}
 
 /* Implements svn_ra_serf__response_handler_t */
 svn_error_t *
@@ -1234,7 +1102,7 @@ svn_ra_serf__expect_empty_body(serf_requ
   const char *val;
 
   /* This function is just like handle_multistatus_only() except for the
-     XML parsing callbacks. We want to look for the human-readable element.  */
+     XML parsing callbacks. We want to look for the -readable element.  */
 
   /* We should see this just once, in order to initialize SERVER_ERROR.
      At that point, the core error processing will take over. If we choose
@@ -1248,11 +1116,10 @@ svn_ra_serf__expect_empty_body(serf_requ
     {
       svn_ra_serf__server_error_t *server_err;
 
-      server_err = begin_error_parsing(start_error, end_error, cdata_error,
-                                       handler->handler_pool);
-
-      /* Get the parser to set our DONE flag.  */
-      server_err->parser.done = &handler->done;
+      SVN_ERR(svn_ra_serf__setup_error_parsing(&server_err, handler,
+                                               FALSE,
+                                               handler->handler_pool,
+                                               handler->handler_pool));
 
       handler->server_error = server_err;
     }
@@ -1269,188 +1136,6 @@ svn_ra_serf__expect_empty_body(serf_requ
   return SVN_NO_ERROR;
 }
 
-
-/* Given a string like "HTTP/1.1 500 (status)" in BUF, parse out the numeric
-   status code into *STATUS_CODE_OUT.  Ignores leading whitespace. */
-static svn_error_t *
-parse_dav_status(int *status_code_out, svn_stringbuf_t *buf,
-                 apr_pool_t *scratch_pool)
-{
-  svn_error_t *err;
-  const char *token;
-  char *tok_status;
-  svn_stringbuf_t *temp_buf = svn_stringbuf_dup(buf, scratch_pool);
-
-  svn_stringbuf_strip_whitespace(temp_buf);
-  token = apr_strtok(temp_buf->data, " \t\r\n", &tok_status);
-  if (token)
-    token = apr_strtok(NULL, " \t\r\n", &tok_status);
-  if (!token)
-    return svn_error_createf(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL,
-                             _("Malformed DAV:status CDATA '%s'"),
-                             buf->data);
-  err = svn_cstring_atoi(status_code_out, token);
-  if (err)
-    return svn_error_createf(SVN_ERR_RA_DAV_MALFORMED_DATA, err,
-                             _("Malformed DAV:status CDATA '%s'"),
-                             buf->data);
-
-  return SVN_NO_ERROR;
-}
-
-/*
- * Expat callback invoked on a start element tag for a 207 response.
- */
-static svn_error_t *
-start_207(svn_ra_serf__xml_parser_t *parser,
-          svn_ra_serf__dav_props_t name,
-          const char **attrs,
-          apr_pool_t *scratch_pool)
-{
-  svn_ra_serf__server_error_t *ctx = parser->user_data;
-
-  if (!ctx->in_error &&
-      strcmp(name.namespace, "DAV:") == 0 &&
-      strcmp(name.name, "multistatus") == 0)
-    {
-      ctx->in_error = TRUE;
-    }
-  else if (ctx->in_error && strcmp(name.name, "responsedescription") == 0)
-    {
-      /* Start collecting cdata. */
-      svn_stringbuf_setempty(ctx->cdata);
-      ctx->collect_cdata = TRUE;
-    }
-  else if (ctx->in_error &&
-           strcmp(name.namespace, "DAV:") == 0 &&
-           strcmp(name.name, "status") == 0)
-    {
-      /* Start collecting cdata. */
-      svn_stringbuf_setempty(ctx->cdata);
-      ctx->collect_cdata = TRUE;
-    }
-
-  return SVN_NO_ERROR;
-}
-
-/*
- * Expat callback invoked on an end element tag for a 207 response.
- */
-static svn_error_t *
-end_207(svn_ra_serf__xml_parser_t *parser,
-        svn_ra_serf__dav_props_t name,
-        apr_pool_t *scratch_pool)
-{
-  svn_ra_serf__server_error_t *ctx = parser->user_data;
-
-  if (ctx->in_error &&
-      strcmp(name.namespace, "DAV:") == 0 &&
-      strcmp(name.name, "multistatus") == 0)
-    {
-      ctx->in_error = FALSE;
-    }
-  if (ctx->in_error && strcmp(name.name, "responsedescription") == 0)
-    {
-      /* Remove leading newline added by DEBUG_CR on server */
-      svn_stringbuf_strip_whitespace(ctx->cdata);
-
-      ctx->collect_cdata = FALSE;
-      ctx->error->message = apr_pstrmemdup(ctx->error->pool, ctx->cdata->data,
-                                           ctx->cdata->len);
-      if (ctx->contains_precondition_error)
-        ctx->error->apr_err = SVN_ERR_FS_PROP_BASEVALUE_MISMATCH;
-      else
-        ctx->error->apr_err = SVN_ERR_RA_DAV_REQUEST_FAILED;
-    }
-  else if (ctx->in_error &&
-           strcmp(name.namespace, "DAV:") == 0 &&
-           strcmp(name.name, "status") == 0)
-    {
-      int status_code;
-
-      ctx->collect_cdata = FALSE;
-
-      SVN_ERR(parse_dav_status(&status_code, ctx->cdata, parser->pool));
-      if (status_code == 412)
-        ctx->contains_precondition_error = TRUE;
-    }
-
-  return SVN_NO_ERROR;
-}
-
-/*
- * Expat callback invoked on CDATA elements in a 207 response.
- *
- * This callback can be called multiple times.
- */
-static svn_error_t *
-cdata_207(svn_ra_serf__xml_parser_t *parser,
-          const char *data,
-          apr_size_t len,
-          apr_pool_t *scratch_pool)
-{
-  svn_ra_serf__server_error_t *ctx = parser->user_data;
-
-  if (ctx->collect_cdata)
-    {
-      svn_stringbuf_appendbytes(ctx->cdata, data, len);
-    }
-
-  return SVN_NO_ERROR;
-}
-
-/* Implements svn_ra_serf__response_handler_t */
-svn_error_t *
-svn_ra_serf__handle_multistatus_only(serf_request_t *request,
-                                     serf_bucket_t *response,
-                                     void *baton,
-                                     apr_pool_t *scratch_pool)
-{
-  svn_ra_serf__handler_t *handler = baton;
-
-  /* This function is just like expect_empty_body() except for the
-     XML parsing callbacks. We are looking for very limited pieces of
-     the multistatus response.  */
-
-  /* We should see this just once, in order to initialize SERVER_ERROR.
-     At that point, the core error processing will take over. If we choose
-     not to parse an error, then we'll never return here (because we
-     change the response handler).  */
-  SVN_ERR_ASSERT(handler->server_error == NULL);
-
-    {
-      serf_bucket_t *hdrs;
-      const char *val;
-
-      hdrs = serf_bucket_response_get_headers(response);
-      val = serf_bucket_headers_get(hdrs, "Content-Type");
-      if (val && strncasecmp(val, "text/xml", sizeof("text/xml") - 1) == 0)
-        {
-          svn_ra_serf__server_error_t *server_err;
-
-          server_err = begin_error_parsing(start_207, end_207, cdata_207,
-                                           handler->handler_pool);
-
-          /* Get the parser to set our DONE flag.  */
-          server_err->parser.done = &handler->done;
-
-          handler->server_error = server_err;
-        }
-      else
-        {
-          /* The body was not text/xml, so we don't know what to do with it.
-             Toss anything that arrives.  */
-          handler->discard_body = TRUE;
-        }
-    }
-
-  /* Returning SVN_NO_ERROR will return APR_SUCCESS to serf, which tells it
-     to call the response handler again. That will start up the XML parsing,
-     or it will be dropped on the floor (per the decision above).  */
-  return SVN_NO_ERROR;
-}
-
-
 /* Conforms to Expat's XML_StartElementHandler  */
 static void
 start_xml(void *userData, const char *raw_name, const char **attrs)
@@ -1550,54 +1235,23 @@ add_done_item(svn_ra_serf__xml_parser_t 
 }
 
 
-static svn_error_t *
-write_to_pending(svn_ra_serf__xml_parser_t *ctx,
-                 const char *data,
-                 apr_size_t len,
-                 apr_pool_t *scratch_pool)
-{
-  if (ctx->pending == NULL)
-    {
-      ctx->pending = apr_pcalloc(ctx->pool, sizeof(*ctx->pending));
-      ctx->pending->buf = svn_spillbuf__create(PARSE_CHUNK_SIZE,
-                                               SPILL_SIZE,
-                                               ctx->pool);
-    }
-
-  /* Copy the data into one or more chunks in the spill buffer.  */
-  return svn_error_trace(svn_spillbuf__write(ctx->pending->buf,
-                                             data, len,
-                                             scratch_pool));
-}
-
-
-static svn_error_t *
-inject_to_parser(svn_ra_serf__xml_parser_t *ctx,
-                 const char *data,
-                 apr_size_t len,
-                 const serf_status_line *sl)
+/* 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_status = XML_Parse(ctx->xmlp, data, (int) len, 0);
-
-  if (! ctx->ignore_errors)
-    {
-      SVN_ERR(ctx->error);
+  int xml_status = XML_Parse(parser, data, (int)len, is_final);
+  const char *msg;
 
-      if (xml_status != XML_STATUS_OK)
-        {
-          if (sl == NULL)
-            return svn_error_createf(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL,
-                                     _("XML parsing failed"));
+  if (xml_status == XML_STATUS_OK)
+    return SVN_NO_ERROR;
 
-          return svn_error_createf(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL,
-                                   _("XML parsing failed: (%d %s)"),
-                                   sl->code, sl->reason);
-        }
-     }
+  msg = XML_ErrorString(XML_GetErrorCode(parser));
 
-  return SVN_NO_ERROR;
+  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
@@ -1616,155 +1270,6 @@ xml_parser_cleanup(void *baton)
   return APR_SUCCESS;
 }
 
-/* Limit the amount of pending content to parse at once to < 100KB per
-   iteration. This number is chosen somewhat arbitrarely. Making it lower
-   will have a drastical negative impact on performance, whereas increasing it
-   increases the risk for connection timeouts.
- */
-#define PENDING_TO_PARSE PARSE_CHUNK_SIZE * 5
-
-svn_error_t *
-svn_ra_serf__process_pending(svn_ra_serf__xml_parser_t *parser,
-                             svn_boolean_t *network_eof,
-                             apr_pool_t *scratch_pool)
-{
-  svn_boolean_t pending_empty = FALSE;
-  apr_size_t cur_read = 0;
-
-  /* Fast path exit: already paused, nothing to do, or already done.  */
-  if (parser->paused || parser->pending == NULL || *parser->done)
-    {
-      *network_eof = parser->pending ? parser->pending->network_eof : FALSE;
-      return SVN_NO_ERROR;
-    }
-
-  /* Parsing the pending conten in the spillbuf will result in many disc i/o
-     operations. This can be so slow that we don't run the network event
-     processing loop often enough, resulting in timed out connections.
-
-     So we limit the amounts of bytes parsed per iteration.
-   */
-  while (cur_read < PENDING_TO_PARSE)
-    {
-      const char *data;
-      apr_size_t len;
-
-      /* Get a block of content, stopping the loop when we run out.  */
-      SVN_ERR(svn_spillbuf__read(&data, &len, parser->pending->buf,
-                             scratch_pool));
-      if (data)
-        {
-          /* Inject the content into the XML parser.  */
-          SVN_ERR(inject_to_parser(parser, data, len, NULL));
-
-          /* If the XML parsing callbacks paused us, then we're done for now.  */
-          if (parser->paused)
-            break;
-
-          cur_read += len;
-        }
-      else
-        {
-          /* The buffer is empty. */
-          pending_empty = TRUE;
-          break;
-        }
-    }
-
-  /* If the PENDING structures are empty *and* we consumed all content from
-     the network, then we're completely done with the parsing.  */
-  if (pending_empty &&
-      parser->pending->network_eof)
-    {
-      int xml_status;
-      SVN_ERR_ASSERT(parser->xmlp != NULL);
-
-      /* Tell the parser that no more content will be parsed. */
-      xml_status = XML_Parse(parser->xmlp, NULL, 0, 1);
-
-      apr_pool_cleanup_run(parser->pool, &parser->xmlp, xml_parser_cleanup);
-      parser->xmlp = NULL;
-
-      if (! parser->ignore_errors)
-        {
-          SVN_ERR(parser->error);
-
-          if (xml_status != XML_STATUS_OK)
-            {
-              return svn_error_createf(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL,
-                                       _("XML parsing failed"));
-            }
-        }
-
-      add_done_item(parser);
-    }
-
-  *network_eof = parser->pending ? parser->pending->network_eof : FALSE;
-
-  return SVN_NO_ERROR;
-}
-#undef PENDING_TO_PARSE
-
-
-/* ### this is still broken conceptually. just shifting incrementally... */
-static svn_error_t *
-handle_server_error(serf_request_t *request,
-                    serf_bucket_t *response,
-                    apr_pool_t *scratch_pool)
-{
-  svn_ra_serf__server_error_t server_err = { 0 };
-  serf_bucket_t *hdrs;
-  const char *val;
-  apr_status_t err;
-
-  hdrs = serf_bucket_response_get_headers(response);
-  val = serf_bucket_headers_get(hdrs, "Content-Type");
-  if (val && strncasecmp(val, "text/xml", sizeof("text/xml") - 1) == 0)
-    {
-      /* ### we should figure out how to reuse begin_error_parsing  */
-
-      server_err.error = svn_error_create(APR_SUCCESS, NULL, NULL);
-      server_err.contains_precondition_error = FALSE;
-      server_err.cdata = svn_stringbuf_create_empty(scratch_pool);
-      server_err.collect_cdata = FALSE;
-      server_err.parser.pool = server_err.error->pool;
-      server_err.parser.user_data = &server_err;
-      server_err.parser.start = start_error;
-      server_err.parser.end = end_error;
-      server_err.parser.cdata = cdata_error;
-      server_err.parser.done = &server_err.done;
-      server_err.parser.ignore_errors = TRUE;
-
-      /* We don't care about any errors except for SERVER_ERR.ERROR  */
-      svn_error_clear(svn_ra_serf__handle_xml_parser(request,
-                                                     response,
-                                                     &server_err.parser,
-                                                     scratch_pool));
-
-      /* ### checking DONE is silly. the above only parses whatever has
-         ### been received at the network interface. totally wrong. but
-         ### it is what we have for now (maintaining historical code),
-         ### until we fully migrate.  */
-      if (server_err.done && server_err.error->apr_err == APR_SUCCESS)
-        {
-          svn_error_clear(server_err.error);
-          server_err.error = SVN_NO_ERROR;
-        }
-
-      return svn_error_trace(server_err.error);
-    }
-
-  /* The only error that we will return is from the XML response body.
-     Otherwise, ignore the entire body but allow SUCCESS/EOF/EAGAIN to
-     surface. */
-  err = drain_bucket(response);
-  if (err && !SERF_BUCKET_READ_ERROR(err))
-    return svn_ra_serf__wrap_err(err, NULL);
-
-  return SVN_NO_ERROR;
-}
-
-
 /* Implements svn_ra_serf__response_handler_t */
 svn_error_t *
 svn_ra_serf__handle_xml_parser(serf_request_t *request,
@@ -1772,29 +1277,10 @@ svn_ra_serf__handle_xml_parser(serf_requ
                                void *baton,
                                apr_pool_t *pool)
 {
-  serf_status_line sl;
   apr_status_t status;
   svn_ra_serf__xml_parser_t *ctx = baton;
   svn_error_t *err;
 
-  /* ### get the HANDLER rather than fetching this.  */
-  status = serf_bucket_response_status(response, &sl);
-  if (SERF_BUCKET_READ_ERROR(status))
-    {
-      return svn_ra_serf__wrap_err(status, NULL);
-    }
-
-  /* Woo-hoo.  Nothing here to see.  */
-  if (sl.code == 404 && !ctx->ignore_errors)
-    {
-      err = handle_server_error(request, response, pool);
-
-      if (err && APR_STATUS_IS_EOF(err->apr_err))
-        add_done_item(ctx);
-
-      return svn_error_trace(err);
-    }
-
   if (!ctx->xmlp)
     {
       ctx->xmlp = XML_ParserCreate(NULL);
@@ -1819,28 +1305,10 @@ svn_ra_serf__handle_xml_parser(serf_requ
           return svn_ra_serf__wrap_err(status, NULL);
         }
 
-      /* Note: once the callbacks invoked by inject_to_parser() sets the
-         PAUSED flag, then it will not be cleared. write_to_pending() will
-         only save the content. Logic outside of serf_context_run() will
-         clear that flag, as appropriate, along with processing the
-         content that we have placed into the PENDING buffer.
-
-         We want to save arriving content into the PENDING structures if
-         the parser has been paused, or we already have data in there (so
-         the arriving data is appended, rather than injected out of order)  */
-      if (ctx->paused || HAS_PENDING_DATA(ctx->pending))
-        {
-          err = write_to_pending(ctx, data, len, pool);
-        }
-      else
-        {
-          err = inject_to_parser(ctx, data, len, &sl);
-          if (err)
-            {
-              /* Should have no errors if IGNORE_ERRORS is set.  */
-              SVN_ERR_ASSERT(!ctx->ignore_errors);
-            }
-        }
+      err = parse_xml(ctx->xmlp, data, len, FALSE);
+
+      err = svn_error_compose_create(ctx->error, err);
+
       if (err)
         {
           SVN_ERR_ASSERT(ctx->xmlp != NULL);
@@ -1857,34 +1325,17 @@ svn_ra_serf__handle_xml_parser(serf_requ
 
       if (APR_STATUS_IS_EOF(status))
         {
-          if (ctx->pending != NULL)
-            ctx->pending->network_eof = TRUE;
+          SVN_ERR_ASSERT(ctx->xmlp != NULL);
 
-          /* We just hit the end of the network content. If we have nothing
-             in the PENDING structures, then we're completely done.  */
-          if (!HAS_PENDING_DATA(ctx->pending))
-            {
-              int xml_status;
-              SVN_ERR_ASSERT(ctx->xmlp != NULL);
+          err = parse_xml(ctx->xmlp, NULL, 0, TRUE);
 
-              xml_status = XML_Parse(ctx->xmlp, NULL, 0, 1);
+          err = svn_error_compose_create(ctx->error, err);
 
-              apr_pool_cleanup_run(ctx->pool, &ctx->xmlp, xml_parser_cleanup);
+          apr_pool_cleanup_run(ctx->pool, &ctx->xmlp, xml_parser_cleanup);
 
-              if (! ctx->ignore_errors)
-                {
-                  SVN_ERR(ctx->error);
-
-                  if (xml_status != XML_STATUS_OK)
-                    {
-                      return svn_error_create(
-                                    SVN_ERR_XML_MALFORMED, NULL,
-                                    _("The XML response contains invalid XML"));
-                    }
-                }
+          SVN_ERR(err);
 
-              add_done_item(ctx);
-            }
+          add_done_item(ctx);
 
           return svn_ra_serf__wrap_err(status, NULL);
         }
@@ -2119,10 +1570,7 @@ handle_response(serf_request_t *request,
     }
   handler->conn->last_status_code = handler->sline.code;
 
-  if (handler->sline.code == 405
-      || handler->sline.code == 408
-      || handler->sline.code == 409
-      || handler->sline.code >= 500)
+  if (handler->sline.code >= 400)
     {
       /* 405 Method Not allowed.
          408 Request Timeout
@@ -2137,35 +1585,22 @@ handle_response(serf_request_t *request,
         {
           svn_ra_serf__server_error_t *server_err;
 
-          server_err = begin_error_parsing(start_error, end_error, cdata_error,
-                                           handler->handler_pool);
-          /* Get the parser to set our DONE flag.  */
-          server_err->parser.done = &handler->done;
+          SVN_ERR(svn_ra_serf__setup_error_parsing(&server_err, handler,
+                                                   FALSE,
+                                                   handler->handler_pool,
+                                                   handler->handler_pool));
 
           handler->server_error = server_err;
         }
       else
         {
           handler->discard_body = TRUE;
-
-          if (!handler->session->pending_error)
-            {
-              apr_status_t apr_err = SVN_ERR_RA_DAV_REQUEST_FAILED;
-
-              /* 405 == Method Not Allowed (Occurs when trying to lock a working
-                copy path which no longer exists at HEAD in the repository. */
-              if (handler->sline.code == 405
-                  && strcmp(handler->method, "LOCK") == 0)
-                apr_err = SVN_ERR_FS_OUT_OF_DATE;
-
-              handler->session->pending_error =
-                  svn_error_createf(apr_err, NULL,
-                                    _("%s request on '%s' failed: %d %s"),
-                                   handler->method, handler->path,
-                                   handler->sline.code, handler->sline.reason);
-            }
         }
     }
+  else if (handler->sline.code <= 199)
+    {
+      handler->discard_body = TRUE;
+    }
 
   /* Stop processing the above, on every packet arrival.  */
   handler->reading_body = TRUE;
@@ -2177,13 +1612,6 @@ handle_response(serf_request_t *request,
     {
       *serf_status = drain_bucket(response);
 
-      /* If the handler hasn't set done (which it shouldn't have) and
-         we now have the EOF, go ahead and set it so that we can stop
-         our context loops.
-       */
-      if (!handler->done && APR_STATUS_IS_EOF(*serf_status))
-          handler->done = TRUE;
-
       return SVN_NO_ERROR;
     }
 
@@ -2191,50 +1619,12 @@ handle_response(serf_request_t *request,
      that now.  */
   if (handler->server_error != NULL)
     {
-      err = svn_ra_serf__handle_xml_parser(request, response,
-                                           &handler->server_error->parser,
-                                           scratch_pool);
-
-      /* If we do not receive an error or it is a non-transient error, return
-         immediately.
-
-         APR_EOF will be returned when parsing is complete.
-
-         APR_EAGAIN & WAIT_CONN may be intermittently returned as we proceed through
-         parsing and the network has no more data right now.  If we receive that,
-         clear the error and return - allowing serf to wait for more data.
-         */
-      if (!err || SERF_BUCKET_READ_ERROR(err->apr_err))
-        return svn_error_trace(err);
-
-      if (!APR_STATUS_IS_EOF(err->apr_err))
-        {
-          *serf_status = err->apr_err;
-          svn_error_clear(err);
-          return SVN_NO_ERROR;
-        }
-
-      /* Clear the EOF. We don't need it.  */
-      svn_error_clear(err);
-
-      /* If the parsing is done, and we did not extract an error, then
-         simply toss everything, and anything else that might arrive.
-         The higher-level code will need to investigate HANDLER->SLINE,
-         as we have no further information for them.  */
-      if (handler->done
-          && handler->server_error->error->apr_err == APR_SUCCESS)
-        {
-          svn_error_clear(handler->server_error->error);
-
-          /* Stop parsing for a server error.  */
-          handler->server_error = NULL;
-
-          /* If anything arrives after this, then just discard it.  */
-          handler->discard_body = TRUE;
-        }
-
-      *serf_status = APR_EOF;
-      return SVN_NO_ERROR;
+      return svn_error_trace(
+                svn_ra_serf__handle_server_error(handler->server_error,
+                                                 handler,
+                                                 request, response, 
+                                                 serf_status,
+                                                 scratch_pool));
     }
 
   /* Pass the body along to the registered response handler.  */
@@ -2280,9 +1670,23 @@ handle_response_cb(serf_request_t *reque
   if (!outer_status)
     outer_status = inner_status;
 
-  /* Make sure the DONE flag is set properly.  */
+  /* 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))
-    handler->done = TRUE;
+    {
+      handler->done = TRUE;
+      outer_status = APR_EOF;
+
+      save_error(handler->session,
+                 handler->done_delegate(request, handler->done_delegate_baton,
+                                        scratch_pool));
+    }
+  else if (SERF_BUCKET_READ_ERROR(outer_status)
+           && handler->session->pending_error)
+    {
+      handler->discard_body = TRUE; /* Discard further data */
+      handler->done = TRUE; /* Mark as done */
+      return APR_EAGAIN; /* Exit context loop */
+    }
 
   return outer_status;
 }
@@ -2469,11 +1873,6 @@ svn_ra_serf__discover_vcc(const char **v
 
               /* Okay, strip off a component from PATH. */
               path = svn_urlpath__dirname(path, pool);
-
-              /* An error occurred on conns. serf 0.4.0 remembers that
-                 the connection had a problem. We need to reset it, in
-                 order to use it again.  */
-              serf_connection_reset(conn->conn);
             }
         }
     }
@@ -2582,7 +1981,9 @@ svn_ra_serf__error_on_status(serf_status
     {
       case 301:
       case 302:
+      case 303:
       case 307:
+      case 308:
         return svn_error_createf(SVN_ERR_RA_DAV_RELOCATED, NULL,
                                  (sline.code == 301)
                                  ? _("Repository moved permanently to '%s';"
@@ -2596,6 +1997,15 @@ svn_ra_serf__error_on_status(serf_status
       case 404:
         return svn_error_createf(SVN_ERR_FS_NOT_FOUND, NULL,
                                  _("'%s' path not found"), path);
+      case 405:
+        return svn_error_createf(SVN_ERR_FS_OUT_OF_DATE, NULL,
+                                 _("'%s' is out of date"), path);
+      case 409:
+        return svn_error_createf(SVN_ERR_FS_CONFLICT, NULL,
+                                 _("'%s' conflicts"), path);
+      case 412:
+        return svn_error_createf(SVN_ERR_RA_DAV_PRECONDITION_FAILED, NULL,
+                                 _("Precondition on '%s' failed"), path);
       case 423:
         return svn_error_createf(SVN_ERR_FS_NO_LOCK_TOKEN, NULL,
                                  _("'%s': no lock token available"), path);
@@ -2606,21 +2016,53 @@ svn_ra_serf__error_on_status(serf_status
                       "server or an intermediate proxy does not accept "
                       "chunked encoding. Try setting 'http-chunked-requests' "
                       "to 'auto' or 'no' in your client configuration."));
+      case 500:
+        return svn_error_createf(SVN_ERR_RA_DAV_REQUEST_FAILED, NULL,
+                                 _("Unexpected server error %d '%s' on '%s'"),
+                                 sline.code, sline.reason, path);
       case 501:
         return svn_error_createf(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
                                  _("The requested feature is not supported by "
                                    "'%s'"), path);
     }
 
-  if (sline.code >= 300)
+  if (sline.code >= 300 || sline.code <= 199)
     return svn_error_createf(SVN_ERR_RA_DAV_REQUEST_FAILED, NULL,
-                             _("Unexpected HTTP status %d '%s' on '%s'\n"),
+                             _("Unexpected HTTP status %d '%s' on '%s'"),
                              sline.code, sline.reason, path);
 
   return SVN_NO_ERROR;
 }
 
 svn_error_t *
+svn_ra_serf__unexpected_status(svn_ra_serf__handler_t *handler)
+{
+  /* Is it a standard error status? */
+  SVN_ERR(svn_ra_serf__error_on_status(handler->sline,
+                                       handler->path,
+                                       handler->location));
+
+  switch (handler->sline.code)
+    {
+      case 201:
+        return svn_error_createf(SVN_ERR_RA_DAV_REQUEST_FAILED, NULL,
+                                 _("Path '%s' unexpectedly created"),
+                                 handler->path);
+      case 204:
+        return svn_error_createf(SVN_ERR_FS_ALREADY_EXISTS, NULL,
+                                 _("Path '%s' already exists"),
+                                 handler->path);
+
+      default:
+        return svn_error_createf(SVN_ERR_RA_DAV_REQUEST_FAILED, NULL,
+                                 _("Unexpected HTTP status %d '%s' on '%s' "
+                                   "request to '%s'"),
+                                 handler->sline.code, handler->sline.reason,
+                                 handler->method, handler->path);
+    }
+}
+
+svn_error_t *
 svn_ra_serf__register_editor_shim_callbacks(svn_ra_session_t *ra_session,
                                     svn_delta_shim_callbacks_t *callbacks)
 {
@@ -2712,8 +2154,9 @@ expat_response_handler(serf_request_t *r
   else
     got_expected_status = (ectx->handler->sline.code == 200);
 
-  if ((ectx->handler->sline.code < 200) || (ectx->handler->sline.code >= 300)
-      || ! got_expected_status)
+  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
@@ -2748,7 +2191,7 @@ expat_response_handler(serf_request_t *r
       apr_status_t status;
       const char *data;
       apr_size_t len;
-      int expat_status;
+      svn_error_t *err;
       svn_boolean_t at_eof = FALSE;
 
       status = serf_bucket_read(response, PARSE_CHUNK_SIZE, &data, &len);
@@ -2767,12 +2210,11 @@ 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,
-                               at_eof /* isFinal */);
+      err = parse_xml(ectx->parser, data, len, at_eof /* isFinal */);
+
+      err = svn_error_compose_create(ectx->inner_error, err);
 
-      if (at_eof 
-          || ectx->inner_error
-          || expat_status != XML_STATUS_OK)
+      if (at_eof || err)
         {
           /* Release xml parser state/tables. */
           apr_pool_cleanup_run(ectx->cleanup_pool, &ectx->parser,
@@ -2786,14 +2228,7 @@ expat_response_handler(serf_request_t *r
 
          If an error is not present, THEN we go ahead and look for parsing
          errors.  */
-      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,
-                                 ectx->handler->sline.code,
-                                 ectx->handler->sline.reason);
+      SVN_ERR(err);
 
       /* The parsing went fine. What has the bucket told us?  */
 
@@ -2812,6 +2247,47 @@ expat_response_handler(serf_request_t *r
   /* NOTREACHED */
 }
 
+/* Shandard done_delegate handler */
+static svn_error_t *
+response_done(serf_request_t *request,
+              void *handler_baton,
+              apr_pool_t *scratch_pool)
+{
+  svn_ra_serf__handler_t *handler = handler_baton;
+
+  assert(handler->done);
+
+  if (handler->no_fail_on_http_failure_status)
+    return SVN_NO_ERROR;
+
+  if (handler->server_error)
+    return svn_ra_serf__server_error_create(handler, scratch_pool);
+
+  if ((handler->sline.code >= 400 || handler->sline.code <= 199)
+      && !handler->session->pending_error
+      && !handler->no_fail_on_http_failure_status)
+    {
+      return svn_error_trace(svn_ra_serf__unexpected_status(handler));
+    }
+
+  return SVN_NO_ERROR;
+}
+
+svn_ra_serf__handler_t *
+svn_ra_serf__create_handler(apr_pool_t *result_pool)
+{
+  svn_ra_serf__handler_t *handler;
+
+  handler = apr_pcalloc(result_pool, sizeof(*handler));
+  handler->handler_pool = result_pool;
+
+  /* Setup the default done handler, to handle server errors */
+  handler->done_delegate_baton = handler;
+  handler->done_delegate = response_done;
+
+  return handler;
+}
+
 
 svn_ra_serf__handler_t *
 svn_ra_serf__create_expat_handler(svn_ra_serf__xml_context_t *xmlctx,
@@ -2828,8 +2304,7 @@ svn_ra_serf__create_expat_handler(svn_ra
   ectx->cleanup_pool = result_pool;
 
 
-  handler = apr_pcalloc(result_pool, sizeof(*handler));
-  handler->handler_pool = result_pool;
+  handler = svn_ra_serf__create_handler(result_pool);
   handler->response_handler = expat_response_handler;
   handler->response_baton = ectx;
 

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=1556765&r1=1556764&r2=1556765&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/xml.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_serf/xml.c Thu Jan  9 09:31:10 2014
@@ -46,9 +46,11 @@ struct svn_ra_serf__xml_context_t {
   /* Current state information.  */
   svn_ra_serf__xml_estate_t *current;
 
-  /* If WAITING.NAMESPACE != NULL, wait for NAMESPACE:NAME element to be
-     closed before looking for transitions from CURRENT->STATE.  */
-  svn_ra_serf__dav_props_t waiting;
+  /* If WAITING >= then we are waiting for an element to close before
+     resuming events. The number stored here is the amount of nested
+     elements open. The Xml parser will make sure the document is well
+     formed. */
+  int waiting;
 
   /* The transition table.  */
   const svn_ra_serf__xml_transition_t *ttable;
@@ -57,7 +59,6 @@ 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.  */
@@ -141,7 +142,7 @@ define_namespaces(svn_ra_serf__ns_t **ns
           /* Have we already defined this ns previously? */
           for (cur_ns = *ns_list; cur_ns; cur_ns = cur_ns->next)
             {
-              if (strcmp(cur_ns->namespace, prefix) == 0)
+              if (strcmp(cur_ns->xmlns, prefix) == 0)
                 {
                   found = TRUE;
                   break;
@@ -158,7 +159,7 @@ define_namespaces(svn_ra_serf__ns_t **ns
               else
                 pool = baton;
               new_ns = apr_palloc(pool, sizeof(*new_ns));
-              new_ns->namespace = apr_pstrdup(pool, prefix);
+              new_ns->xmlns = apr_pstrdup(pool, prefix);
               new_ns->url = apr_pstrdup(pool, tmp_attrs[1]);
 
               /* Push into the front of NS_LIST. Parent states will point
@@ -199,9 +200,9 @@ svn_ra_serf__expand_ns(svn_ra_serf__dav_
 
       for (ns = ns_list; ns; ns = ns->next)
         {
-          if (strncmp(ns->namespace, name, colon - name) == 0)
+          if (strncmp(ns->xmlns, name, colon - name) == 0)
             {
-              returned_prop_name->namespace = ns->url;
+              returned_prop_name->xmlns = ns->url;
               returned_prop_name->name = colon + 1;
               return;
             }
@@ -213,9 +214,9 @@ svn_ra_serf__expand_ns(svn_ra_serf__dav_
 
       for (ns = ns_list; ns; ns = ns->next)
         {
-          if (! ns->namespace[0])
+          if (! ns->xmlns[0])
             {
-              returned_prop_name->namespace = ns->url;
+              returned_prop_name->xmlns = ns->url;
               returned_prop_name->name = name;
               return;
             }
@@ -224,7 +225,7 @@ svn_ra_serf__expand_ns(svn_ra_serf__dav_
 
   /* If the prefix is not found, then the name is NOT within a
      namespace.  */
-  returned_prop_name->namespace = "";
+  returned_prop_name->xmlns = "";
   returned_prop_name->name = name;
 }
 
@@ -501,14 +502,6 @@ svn_ra_serf__xml_context_done(svn_ra_ser
                                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;
 }
@@ -519,7 +512,6 @@ 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)
 {
@@ -531,7 +523,6 @@ 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);
 
@@ -640,8 +631,11 @@ svn_ra_serf__xml_cb_start(svn_ra_serf__x
 
   /* If we're waiting for an element to close, then just ignore all
      other element-opens.  */
-  if (xmlctx->waiting.namespace != NULL)
-    return SVN_NO_ERROR;
+  if (xmlctx->waiting > 0)
+    {
+      xmlctx->waiting++;
+      return SVN_NO_ERROR;
+    }
 
   /* Look for xmlns: attributes. Lazily create the state pool if any
      were found.  */
@@ -660,7 +654,7 @@ svn_ra_serf__xml_cb_start(svn_ra_serf__x
 
       /* Found a specific transition.  */
       if (strcmp(elemname.name, scan->name) == 0
-          && strcmp(elemname.namespace, scan->ns) == 0)
+          && strcmp(elemname.xmlns, scan->ns) == 0)
         break;
     }
   if (scan->ns == NULL)
@@ -673,8 +667,7 @@ svn_ra_serf__xml_cb_start(svn_ra_serf__x
                         elemname.name);
         }
 
-      xmlctx->waiting = elemname;
-      /* ### return?  */
+      xmlctx->waiting++; /* Start waiting for the close tag */
       return SVN_NO_ERROR;
     }
 
@@ -750,7 +743,7 @@ svn_ra_serf__xml_cb_start(svn_ra_serf__x
   /* Some basic copies to set up the new estate.  */
   new_xes->state = scan->to_state;
   new_xes->tag.name = apr_pstrdup(new_pool, elemname.name);
-  new_xes->tag.namespace = apr_pstrdup(new_pool, elemname.namespace);
+  new_xes->tag.xmlns = apr_pstrdup(new_pool, elemname.xmlns);
   new_xes->custom_close = scan->custom_close;
 
   /* Start with the parent's namespace set.  */
@@ -783,30 +776,12 @@ svn_ra_serf__xml_cb_end(svn_ra_serf__xml
 
   svn_ra_serf__expand_ns(&elemname, xes->ns_list, raw_name);
 
-  if (xmlctx->waiting.namespace != NULL)
+  if (xmlctx->waiting > 0)
     {
-      /* If this element is not the closer, then keep waiting... */
-      if (strcmp(elemname.name, xmlctx->waiting.name) != 0
-          || strcmp(elemname.namespace, xmlctx->waiting.namespace) != 0)
-        return SVN_NO_ERROR;
-
-      /* Found it. Stop waiting, and go back for more.  */
-      xmlctx->waiting.namespace = NULL;
+      xmlctx->waiting--;
       return SVN_NO_ERROR;
     }
 
-  /* We should be looking at the same tag that opened the current state.
-
-     Unknown elements are simply skipped, so we wouldn't reach this check.
-
-     Known elements push a new state for a given tag. Some other elemname
-     would imply closing an ancestor tag (where did ours go?) or a spurious
-     tag closure.  */
-  if (strcmp(elemname.name, xes->tag.name) != 0
-      || strcmp(elemname.namespace, xes->tag.namespace) != 0)
-    return svn_error_create(SVN_ERR_XML_MALFORMED, NULL,
-                            _("The response contains invalid XML"));
-
   if (xes->custom_close)
     {
       const svn_string_t *cdata;
@@ -857,7 +832,7 @@ svn_ra_serf__xml_cb_cdata(svn_ra_serf__x
 {
   /* If we are waiting for a closing tag, then we are uninterested in
      the cdata. Just return.  */
-  if (xmlctx->waiting.namespace != NULL)
+  if (xmlctx->waiting > 0)
     return SVN_NO_ERROR;
 
   /* If the current state is collecting cdata, then copy the cdata.  */

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_svn/client.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_svn/client.c?rev=1556765&r1=1556764&r2=1556765&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_svn/client.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_svn/client.c Thu Jan  9 09:31:10 2014
@@ -598,6 +598,7 @@ static svn_error_t *open_session(svn_ra_
                                  const apr_uri_t *uri,
                                  const char *tunnel_name,
                                  const char **tunnel_argv,
+                                 apr_hash_t *config,
                                  const svn_ra_callbacks2_t *callbacks,
                                  void *callbacks_baton,
                                  apr_pool_t *pool)
@@ -623,6 +624,11 @@ static svn_error_t *open_session(svn_ra_
   sess->callbacks_baton = callbacks_baton;
   sess->bytes_read = sess->bytes_written = 0;
 
+  if (config)
+    SVN_ERR(svn_config_copy_config(&sess->config, config, pool));
+  else
+    sess->config = NULL;
+
   if (tunnel_name)
     {
       if (tunnel_argv)
@@ -823,13 +829,65 @@ static svn_error_t *ra_svn_open(svn_ra_s
 
   /* We open the session in a subpool so we can get rid of it if we
      reparent with a server that doesn't support reparenting. */
-  SVN_ERR(open_session(&sess, url, &uri, tunnel, tunnel_argv,
+  SVN_ERR(open_session(&sess, url, &uri, tunnel, tunnel_argv, config,
                        callbacks, callback_baton, sess_pool));
   session->priv = sess;
 
   return SVN_NO_ERROR;
 }
 
+static svn_error_t *ra_svn_dup_session(svn_ra_session_t *new_session,
+                                       svn_ra_session_t *old_session,
+                                       const char *new_session_url,
+                                       apr_pool_t *result_pool,
+                                       apr_pool_t *scratch_pool)
+{
+  apr_pool_t *sess_pool = svn_pool_create(result_pool);
+  svn_ra_svn__session_baton_t *old_sess = old_session->priv;
+  svn_ra_svn__session_baton_t *new_sess;
+  const char *tunnel, **tunnel_argv;
+  apr_uri_t uri;
+  svn_config_t *cfg, *cfg_client;
+  apr_hash_t *config = old_sess->config;
+  const svn_ra_callbacks2_t *callbacks = old_sess->callbacks;
+  void *callback_baton = old_sess->callbacks_baton;
+
+  SVN_ERR(parse_url(new_session_url, &uri, sess_pool));
+
+  parse_tunnel(new_session_url, &tunnel, result_pool);
+
+  /* Use the default tunnel implementation if we got a tunnel name,
+     but either do not have tunnel handler callbacks installed, or
+     the handlers don't like the tunnel name. */
+  if (tunnel
+      && (!callbacks->open_tunnel_func
+          || (callbacks->check_tunnel_func && callbacks->open_tunnel_func
+              && !callbacks->check_tunnel_func(callbacks->tunnel_baton,
+                                               tunnel))))
+    SVN_ERR(find_tunnel_agent(tunnel, uri.hostinfo, &tunnel_argv,
+                              config,
+                              result_pool));
+  else
+    tunnel_argv = NULL;
+
+  cfg_client = config
+               ? svn_hash_gets(config, SVN_CONFIG_CATEGORY_CONFIG)
+               : NULL;
+  cfg = config ? svn_hash_gets(config, SVN_CONFIG_CATEGORY_SERVERS) : NULL;
+  svn_auth_set_parameter(callbacks->auth_baton,
+                         SVN_AUTH_PARAM_CONFIG_CATEGORY_CONFIG, cfg_client);
+  svn_auth_set_parameter(callbacks->auth_baton,
+                         SVN_AUTH_PARAM_CONFIG_CATEGORY_SERVERS, cfg);
+
+  /* We open the session in a subpool so we can get rid of it if we
+     reparent with a server that doesn't support reparenting. */
+  SVN_ERR(open_session(&new_sess, new_session_url, &uri, tunnel, tunnel_argv,
+                       config, callbacks, callback_baton, sess_pool));
+  new_session->priv = new_sess;
+
+  return SVN_NO_ERROR;
+}
+
 static svn_error_t *ra_svn_reparent(svn_ra_session_t *ra_session,
                                     const char *url,
                                     apr_pool_t *pool)
@@ -860,7 +918,8 @@ static svn_error_t *ra_svn_reparent(svn_
   err = parse_url(url, &uri, sess_pool);
   if (! err)
     err = open_session(&new_sess, url, &uri, sess->tunnel_name, sess->tunnel_argv,
-                       sess->callbacks, sess->callbacks_baton, sess_pool);
+                       sess->config, sess->callbacks, sess->callbacks_baton,
+                       sess_pool);
   /* We destroy the new session pool on error, since it is allocated in
      the main session pool. */
   if (err)
@@ -2792,6 +2851,16 @@ ra_svn_get_inherited_props(svn_ra_sessio
   svn_ra_svn__session_baton_t *sess_baton = session->priv;
   svn_ra_svn_conn_t *conn = sess_baton->conn;
   apr_array_header_t *iproplist;
+  svn_boolean_t iprop_capable;
+
+  SVN_ERR(ra_svn_has_capability(session, &iprop_capable,
+                                SVN_RA_CAPABILITY_INHERITED_PROPS,
+                                scratch_pool));
+
+  /* If we don't support native iprop handling, use the implementation
+     in libsvn_ra */
+  if (!iprop_capable)
+    return svn_error_create(SVN_ERR_RA_NOT_IMPLEMENTED, NULL, NULL);
 
   SVN_ERR(svn_ra_svn__write_cmd_get_iprops(conn, scratch_pool,
                                            path, revision));
@@ -2808,6 +2877,7 @@ static const svn_ra__vtable_t ra_svn_vta
   ra_svn_get_description,
   ra_svn_get_schemes,
   ra_svn_open,
+  ra_svn_dup_session,
   ra_svn_reparent,
   ra_svn_get_session_url,
   ra_svn_get_latest_rev,

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_svn/ra_svn.h
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_svn/ra_svn.h?rev=1556765&r1=1556764&r2=1556765&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_svn/ra_svn.h (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_ra_svn/ra_svn.h Thu Jan  9 09:31:10 2014
@@ -131,6 +131,7 @@ struct svn_ra_svn__session_baton_t {
   const char **tunnel_argv;
   const svn_ra_callbacks2_t *callbacks;
   void *callbacks_baton;
+  apr_hash_t *config;
   apr_off_t bytes_read, bytes_written; /* apr_off_t's because that's what
                                           the callback interface uses */
   const char *useragent;

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_repos/authz_pool.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_repos/authz_pool.c?rev=1556765&r1=1556764&r2=1556765&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_repos/authz_pool.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_repos/authz_pool.c Thu Jan  9 09:31:10 2014
@@ -38,7 +38,6 @@
 #include "../libsvn_subr/config_impl.h"
 
 #include "repos.h"
-#include <apr_poll.h>
 
 /* Currently this structure is just a wrapper around a svn_config_t.
  */

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_repos/commit.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_repos/commit.c?rev=1556765&r1=1556764&r2=1556765&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_repos/commit.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_repos/commit.c Thu Jan  9 09:31:10 2014
@@ -761,6 +761,13 @@ close_edit(void *edit_baton,
 
   if (SVN_IS_VALID_REVNUM(new_revision))
     {
+      /* The actual commit succeeded, i.e. the transaction does no longer
+         exist and we can't use txn_root for conflict resolution etc.
+
+         Since close_edit is supposed to release resources, do it now. */
+      if (eb->txn_root)
+        svn_fs_close_root(eb->txn_root);
+
       if (err)
         {
           /* If the error was in post-commit, then the commit itself
@@ -821,6 +828,10 @@ abort_edit(void *edit_baton,
 
   eb->txn_aborted = TRUE;
 
+  /* Since abort_edit is supposed to release resources, do it now. */
+  if (eb->txn_root)
+    svn_fs_close_root(eb->txn_root);
+
   return svn_error_trace(svn_fs_abort_txn(eb->txn, pool));
 }
 

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_repos/delta.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_repos/delta.c?rev=1556765&r1=1556764&r2=1556765&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_repos/delta.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_repos/delta.c Thu Jan  9 09:31:10 2014
@@ -216,10 +216,9 @@ svn_repos_dir_delta2(svn_fs_root_t *src_
   void *root_baton = NULL;
   struct context c;
   const char *src_fullpath;
-  const svn_fs_id_t *src_id, *tgt_id;
   svn_node_kind_t src_kind, tgt_kind;
   svn_revnum_t rootrev;
-  int distance;
+  svn_fs_node_relation_t relation;
   const char *authz_root_path;
 
   /* SRC_PARENT_DIR must be valid. */
@@ -319,11 +318,10 @@ svn_repos_dir_delta2(svn_fs_root_t *src_
     }
 
   /* Get and compare the node IDs for the source and target. */
-  SVN_ERR(svn_fs_node_id(&tgt_id, tgt_root, tgt_fullpath, pool));
-  SVN_ERR(svn_fs_node_id(&src_id, src_root, src_fullpath, pool));
-  distance = svn_fs_compare_ids(src_id, tgt_id);
+  SVN_ERR(svn_fs_node_relation(&relation, tgt_root, tgt_fullpath,
+                               src_root, src_fullpath, pool));
 
-  if (distance == 0)
+  if (relation == svn_fs_node_same)
     {
       /* They are the same node!  No-op (you gotta love those). */
       goto cleanup;
@@ -334,7 +332,7 @@ svn_repos_dir_delta2(svn_fs_root_t *src_
          add the other.  Also, if they are completely unrelated and
          our caller is interested in relatedness, we do the same thing. */
       if ((src_kind != tgt_kind)
-          || ((distance == -1) && (! ignore_ancestry)))
+          || ((relation == svn_fs_node_unrelated) && (! ignore_ancestry)))
         {
           SVN_ERR(authz_root_check(tgt_root, authz_root_path,
                                    authz_read_func, authz_read_baton, pool));

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_repos/dump.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_repos/dump.c?rev=1556765&r1=1556764&r2=1556765&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_repos/dump.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_repos/dump.c Thu Jan  9 09:31:10 2014
@@ -38,6 +38,7 @@
 
 #include "private/svn_mergeinfo_private.h"
 #include "private/svn_fs_private.h"
+#include "private/svn_sorts_private.h"
 #include "private/svn_utf_private.h"
 #include "private/svn_cache.h"
 
@@ -399,13 +400,6 @@ struct edit_baton
   char buffer[SVN__STREAM_CHUNK_SIZE];
   apr_size_t bufsize;
 
-  /* map nodeID -> node kind.  May be NULL.
-     The key is the string representation of the node ID given in
-     directory entries.  If we find an entry in this cache, the
-     respective node has already been verified as readable and being
-     of the type stored as value in the cache. */
-  svn_cache__t *verified_dirents_cache;
-
   /* Structure allows us to verify the paths currently being dumped.
      If NULL, validity checks are being skipped. */
   path_tracker_t *path_tracker;
@@ -592,42 +586,11 @@ node_must_not_exist(struct edit_baton *e
   return SVN_NO_ERROR;
 }
 
-
+/* Unique string pointers used by verify_mergeinfo_normalization()
+   and check_name_collision() */
 static const char normalized_unique[] = "normalized_unique";
 static const char normalized_collision[] = "normalized_collision";
 
-static svn_error_t *
-check_path_normalization(const char *path,
-                         svn_node_kind_t kind,
-                         svn_repos_notify_func_t notify_func,
-                         void *notify_baton,
-                         apr_pool_t *scratch_pool)
-{
-  const char *const name = svn_relpath_basename(path, scratch_pool);
-  if (!svn_utf__is_normalized(name, scratch_pool))
-    {
-      svn_repos_notify_t *const notify =
-        svn_repos_notify_create(svn_repos_notify_warning, scratch_pool);
-      notify->warning = svn_repos_notify_warning_denormalized_name;
-      switch (kind)
-        {
-        case svn_node_dir:
-          notify->warning_str = apr_psprintf(
-              scratch_pool, _("Denormalized directory name '%s'"), path);
-          break;
-        case svn_node_file:
-          notify->warning_str = apr_psprintf(
-              scratch_pool, _("Denormalized file name '%s'"), path);
-          break;
-        default:
-          notify->warning_str = apr_psprintf(
-              scratch_pool, _("Denormalized entry name '%s'"), path);
-        }
-      notify_func(notify_baton, notify, scratch_pool);
-    }
-  return SVN_NO_ERROR;
-}
-
 
 /* Baton for extract_mergeinfo_paths */
 struct extract_mergeinfo_paths_baton
@@ -703,18 +666,6 @@ verify_mergeinfo_normalization(void *bat
   const char *found;
 
   SVN_ERR(svn_utf__normalize(&normpath, path, klen, &vb->buffer));
-  if (0 != strcmp(path, normpath))
-    {
-      /* Report denormlized mergeinfo path */
-      svn_repos_notify_t *const notify =
-        svn_repos_notify_create(svn_repos_notify_warning, iterpool);
-      notify->warning = svn_repos_notify_warning_denormalized_mergeinfo;
-      notify->warning_str = apr_psprintf(
-          iterpool, _("Denormalized path '%s' in %s property of '%s'"),
-          path, SVN_PROP_MERGEINFO, vb->path);
-      vb->notify_func(vb->notify_baton, notify, iterpool);
-    }
-
   found = svn_hash_gets(vb->normalized_paths, normpath);
   if (!found)
       svn_hash_sets(vb->normalized_paths,
@@ -1370,14 +1321,11 @@ add_directory(const char *path,
     /* Delete the path, it's now been dumped. */
     svn_hash_sets(pb->deleted_entries, path, NULL);
 
-  /* Check for UCS normalization and name clashes, but only if this is
-     actually a new name in the parent, not a replacement. */
+  /* Check for normalized name clashes, but only if this is actually a
+     new name in the parent, not a replacement. */
   if (!val && eb->verify && eb->check_normalization && eb->notify_func)
     {
       pb->check_name_collision = TRUE;
-      SVN_ERR(check_path_normalization(
-                  path, svn_node_dir,
-                  eb->notify_func, eb->notify_baton, pool));
     }
 
   new_db->written_out = TRUE;
@@ -1479,20 +1427,17 @@ add_file(const char *path,
                     is_copy ? copyfrom_rev : SVN_INVALID_REVNUM,
                     pool));
 
-  /* Check for UCS normalization and name clashes, but only if this is
-     actually a new name in the parent, not a replacement. */
+  if (val)
+    /* delete the path, it's now been dumped. */
+    svn_hash_sets(pb->deleted_entries, path, NULL);
+
+  /* Check for normalized name clashes, but only if this is actually a
+     new name in the parent, not a replacement. */
   if (!val && eb->verify && eb->check_normalization && eb->notify_func)
     {
       pb->check_name_collision = TRUE;
-      SVN_ERR(check_path_normalization(
-                  path, svn_node_file,
-                  eb->notify_func, eb->notify_baton, pool));
     }
 
-  if (val)
-    /* delete the path, it's now been dumped. */
-    svn_hash_sets(pb->deleted_entries, path, NULL);
-
   *file_baton = NULL;  /* muhahahaha */
   return SVN_NO_ERROR;
 }
@@ -1657,7 +1602,6 @@ get_dump_editor(const svn_delta_editor_t
                 svn_boolean_t use_deltas,
                 svn_boolean_t verify,
                 svn_boolean_t check_normalization,
-                svn_cache__t *verified_dirents_cache,
                 apr_pool_t *pool)
 {
   /* Allocate an edit baton to be stored in every directory baton.
@@ -1683,7 +1627,6 @@ get_dump_editor(const svn_delta_editor_t
   eb->check_normalization = check_normalization;
   eb->found_old_reference = found_old_reference;
   eb->found_old_mergeinfo = found_old_mergeinfo;
-  eb->verified_dirents_cache = verified_dirents_cache;
 
   /* In non-verification mode, we will allow anything to be dumped because
      it might be an incremental dump with possible manual intervention.
@@ -1889,7 +1832,7 @@ svn_repos_dump_fs3(svn_repos_t *repos,
                               &found_old_mergeinfo, NULL,
                               notify_func, notify_baton,
                               start_rev, use_deltas_for_rev, FALSE, FALSE,
-                              NULL, subpool));
+                              subpool));
 
       /* Drive the editor in one way or another. */
       SVN_ERR(svn_fs_revision_root(&to_root, fs, rev, subpool));
@@ -2002,55 +1945,31 @@ verify_directory_entry(void *baton, cons
   struct dir_baton *db = baton;
   svn_fs_dirent_t *dirent = (svn_fs_dirent_t *)val;
   char *path;
-  apr_hash_t *dirents;
-  svn_filesize_t len;
-  svn_string_t *unparsed_id;
-
-  /* most directory entries will be unchanged from previous revs.
-     We should find those in the cache and they must match the
-     type defined in the DIRENT. */
-  if (db->edit_baton->verified_dirents_cache)
-    {
-      svn_node_kind_t *kind;
-      svn_boolean_t found;
-      unparsed_id = svn_fs_unparse_id(dirent->id, pool);
-
-      SVN_ERR(svn_cache__get((void **)&kind, &found,
-                             db->edit_baton->verified_dirents_cache,
-                             unparsed_id->data, pool));
-
-      if (found)
-        {
-          if (*kind == dirent->kind)
-            return SVN_NO_ERROR;
-          else
-            {
-              path = svn_relpath_join(db->path, (const char *)key, pool);
-
-              return
-                  svn_error_createf(SVN_ERR_NODE_UNEXPECTED_KIND, NULL,
-                                    _("Unexpected node kind %d for '%s'. "
-                                      "Expected kind was %d."),
-                                    dirent->kind, path, *kind);
-            }
-        }
-    }
+  svn_boolean_t right_kind;
 
   path = svn_relpath_join(db->path, (const char *)key, pool);
 
   /* since we can't access the directory entries directly by their ID,
      we need to navigate from the FS_ROOT to them (relatively expensive
-     because we may start at a never rev than the last change to node). */
+     because we may start at a never rev than the last change to node).
+     We check that the node kind stored in the noderev matches the dir
+     entry.  This also ensures that all entries point to valid noderevs.
+   */
   switch (dirent->kind) {
   case svn_node_dir:
-    /* Getting this directory's contents is enough to ensure that our
-       link to it is correct. */
-    SVN_ERR(svn_fs_dir_entries(&dirents, db->edit_baton->fs_root, path, pool));
+    SVN_ERR(svn_fs_is_dir(&right_kind, db->edit_baton->fs_root, path, pool));
+    if (!right_kind)
+      return svn_error_createf(SVN_ERR_NODE_UNEXPECTED_KIND, NULL,
+                               _("Node '%s' is not a directory."),
+                               path);
+
     break;
   case svn_node_file:
-    /* Getting this file's size is enough to ensure that our link to it
-       is correct. */
-    SVN_ERR(svn_fs_file_length(&len, db->edit_baton->fs_root, path, pool));
+    SVN_ERR(svn_fs_is_file(&right_kind, db->edit_baton->fs_root, path, pool));
+    if (!right_kind)
+      return svn_error_createf(SVN_ERR_NODE_UNEXPECTED_KIND, NULL,
+                               _("Node '%s' is not a file."),
+                               path);
     break;
   default:
     return svn_error_createf(SVN_ERR_NODE_UNEXPECTED_KIND, NULL,
@@ -2058,11 +1977,6 @@ verify_directory_entry(void *baton, cons
                              dirent->kind, path);
   }
 
-  /* remember ID, kind pair */
-  if (db->edit_baton->verified_dirents_cache)
-    SVN_ERR(svn_cache__set(db->edit_baton->verified_dirents_cache,
-                           unparsed_id->data, &dirent->kind, pool));
-
   return SVN_NO_ERROR;
 }
 
@@ -2166,7 +2080,6 @@ verify_one_revision(svn_fs_t *fs,
                     svn_boolean_t check_normalization,
                     svn_cancel_func_t cancel_func,
                     void *cancel_baton,
-                    svn_cache__t *verified_dirents_cache,
                     apr_pool_t *scratch_pool)
 {
   const svn_delta_editor_t *dump_editor;
@@ -2186,7 +2099,6 @@ verify_one_revision(svn_fs_t *fs,
                           start_rev,
                           FALSE, TRUE, /* use_deltas, verify */
                           check_normalization,
-                          verified_dirents_cache,
                           scratch_pool));
   SVN_ERR(svn_delta_get_cancellation_editor(cancel_func, cancel_baton,
                                             dump_editor, dump_edit_baton,
@@ -2234,30 +2146,6 @@ verify_fs2_notify_func(svn_revnum_t revi
                             notify_baton->notify, pool);
 }
 
-/* cache entry (de-)serialization support for svn_node_kind_t. */
-static svn_error_t *
-serialize_node_kind(void **data,
-                    apr_size_t *data_len,
-                    void *in,
-                    apr_pool_t *pool)
-{
-  *data_len = sizeof(svn_node_kind_t);
-  *data = in;
-
-  return SVN_NO_ERROR;
-}
-
-static svn_error_t *
-deserialize_node_kind(void **out,
-                      void *data,
-                      apr_size_t data_len,
-                      apr_pool_t *pool)
-{
-  *out = data;
-
-  return SVN_NO_ERROR;
-}
-
 svn_error_t *
 svn_repos_verify_fs3(svn_repos_t *repos,
                      svn_revnum_t start_rev,
@@ -2279,7 +2167,6 @@ svn_repos_verify_fs3(svn_repos_t *repos,
   struct verify_fs2_notify_func_baton_t *verify_notify_baton = NULL;
   svn_error_t *err;
   svn_boolean_t found_corruption = FALSE;
-  svn_cache__t *verified_dirents_cache = NULL;
 
   /* Determine the current youngest revision of the filesystem. */
   SVN_ERR(svn_fs_youngest_rev(&youngest, fs, pool));
@@ -2341,18 +2228,6 @@ svn_repos_verify_fs3(svn_repos_t *repos,
       svn_error_clear(err);
     }
 
-  if (svn_cache__get_global_membuffer_cache())
-    SVN_ERR(svn_cache__create_membuffer_cache
-                                 (&verified_dirents_cache,
-                                  svn_cache__get_global_membuffer_cache(),
-                                  serialize_node_kind,
-                                  deserialize_node_kind,
-                                  APR_HASH_KEY_STRING,
-                                  svn_uuid_generate(pool),
-                                  SVN_CACHE__MEMBUFFER_DEFAULT_PRIORITY,
-                                  FALSE,
-                                  pool));
-
   for (rev = start_rev; rev <= end_rev; rev++)
     {
       svn_pool_clear(iterpool);
@@ -2361,7 +2236,7 @@ svn_repos_verify_fs3(svn_repos_t *repos,
       err = verify_one_revision(fs, rev, notify_func, notify_baton,
                                 start_rev, check_normalization,
                                 cancel_func, cancel_baton,
-                                verified_dirents_cache, iterpool);
+                                iterpool);
 
       if (err)
         {

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_repos/fs-wrap.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_repos/fs-wrap.c?rev=1556765&r1=1556764&r2=1556765&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_repos/fs-wrap.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_repos/fs-wrap.c Thu Jan  9 09:31:10 2014
@@ -37,6 +37,7 @@
 #include "repos.h"
 
 #include "private/svn_repos_private.h"
+#include "private/svn_sorts_private.h"
 #include "private/svn_utf_private.h"
 #include "private/svn_fspath.h"
 
@@ -88,7 +89,7 @@ svn_repos_fs_commit_txn(const char **con
   svn_pool_destroy(iterpool);
 
   /* Commit. */
-  err = svn_fs_commit_txn2(conflict_p, new_rev, txn, TRUE, pool);
+  err = svn_fs_commit_txn(conflict_p, new_rev, txn, pool);
   if (! SVN_IS_VALID_REVNUM(*new_rev))
     {
       /* The commit failed, try to restore the ephemeral properties. */
@@ -851,7 +852,7 @@ svn_repos_fs_get_inherited_props(apr_arr
                 apr_pstrdup(result_pool, parent_path + 1);
               i_props->prop_hash = parent_properties;
               /* Build the output array in depth-first order. */
-              svn_sort__array_insert(&i_props, inherited_props, 0);
+              svn_sort__array_insert(inherited_props, &i_props, 0);
             }
         }
     }

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_repos/load-fs-vtable.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_repos/load-fs-vtable.c?rev=1556765&r1=1556764&r2=1556765&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_repos/load-fs-vtable.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_repos/load-fs-vtable.c Thu Jan  9 09:31:10 2014
@@ -501,7 +501,8 @@ new_revision_record(void **revision_bato
   if ((rb->rev > 0) && (! rb->skipped))
     {
       /* Create a new fs txn. */
-      SVN_ERR(svn_fs_begin_txn2(&(rb->txn), pb->fs, head_rev, 0, pool));
+      SVN_ERR(svn_fs_begin_txn2(&(rb->txn), pb->fs, head_rev,
+                                SVN_FS_TXN_CLIENT_DATE, pool));
       SVN_ERR(svn_fs_txn_root(&(rb->txn_root), rb->txn, pool));
 
       if (pb->notify_func)
@@ -968,8 +969,7 @@ close_revision(void *baton)
     }
 
   /* Commit. */
-  err = svn_fs_commit_txn2(&conflict_msg, &committed_rev, rb->txn, FALSE,
-                           rb->pool);
+  err = svn_fs_commit_txn(&conflict_msg, &committed_rev, rb->txn, rb->pool);
   if (SVN_IS_VALID_REVNUM(committed_rev))
     {
       if (err)

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_repos/rev_hunt.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_repos/rev_hunt.c?rev=1556765&r1=1556764&r2=1556765&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_repos/rev_hunt.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_repos/rev_hunt.c Thu Jan  9 09:31:10 2014
@@ -309,11 +309,11 @@ svn_repos_deleted_rev(svn_fs_t *fs,
                       apr_pool_t *pool)
 {
   apr_pool_t *subpool;
-  svn_fs_root_t *root, *copy_root;
+  svn_fs_root_t *start_root, *root, *copy_root;
   const char *copy_path;
   svn_revnum_t mid_rev;
-  const svn_fs_id_t *start_node_id, *curr_node_id;
-  svn_error_t *err;
+  svn_node_kind_t kind;
+  svn_fs_node_relation_t node_relation;
 
   /* Validate the revision range. */
   if (! SVN_IS_VALID_REVNUM(start))
@@ -334,32 +334,19 @@ svn_repos_deleted_rev(svn_fs_t *fs,
     }
 
   /* Ensure path exists in fs at start revision. */
-  SVN_ERR(svn_fs_revision_root(&root, fs, start, pool));
-  err = svn_fs_node_id(&start_node_id, root, path, pool);
-  if (err)
+  SVN_ERR(svn_fs_revision_root(&start_root, fs, start, pool));
+  SVN_ERR(svn_fs_check_path(&kind, start_root, path, pool));
+  if (kind == svn_node_none)
     {
-      if (err->apr_err == SVN_ERR_FS_NOT_FOUND)
-        {
-          /* Path must exist in fs at start rev. */
-          *deleted = SVN_INVALID_REVNUM;
-          svn_error_clear(err);
-          return SVN_NO_ERROR;
-        }
-      return svn_error_trace(err);
+      /* Path must exist in fs at start rev. */
+      *deleted = SVN_INVALID_REVNUM;
+      return SVN_NO_ERROR;
     }
 
   /* Ensure path was deleted at or before end revision. */
   SVN_ERR(svn_fs_revision_root(&root, fs, end, pool));
-  err = svn_fs_node_id(&curr_node_id, root, path, pool);
-  if (err && err->apr_err == SVN_ERR_FS_NOT_FOUND)
-    {
-      svn_error_clear(err);
-    }
-  else if (err)
-    {
-      return svn_error_trace(err);
-    }
-  else
+  SVN_ERR(svn_fs_check_path(&kind, root, path, pool));
+  if (kind != svn_node_none)
     {
       /* path exists in the end node and the end node is equivalent
          or otherwise equivalent to the start node.  This can mean
@@ -386,8 +373,9 @@ svn_repos_deleted_rev(svn_fs_t *fs,
            5) The start node was deleted and replaced by a node which
               it does not share any history with.
       */
-      SVN_ERR(svn_fs_node_id(&curr_node_id, root, path, pool));
-      if (svn_fs_compare_ids(start_node_id, curr_node_id) != -1)
+      SVN_ERR(svn_fs_node_relation(&node_relation, start_root, path,
+                                   root, path, pool));
+      if (node_relation != svn_fs_node_unrelated)
         {
           SVN_ERR(svn_fs_closest_copy(&copy_root, &copy_path, root,
                                       path, pool));
@@ -450,28 +438,23 @@ svn_repos_deleted_rev(svn_fs_t *fs,
 
       /* Get revision root and node id for mid_rev at that revision. */
       SVN_ERR(svn_fs_revision_root(&root, fs, mid_rev, subpool));
-      err = svn_fs_node_id(&curr_node_id, root, path, subpool);
-
-      if (err)
+      SVN_ERR(svn_fs_check_path(&kind, root, path, pool));
+      if (kind == svn_node_none)
         {
-          if (err->apr_err == SVN_ERR_FS_NOT_FOUND)
-            {
-              /* Case D: Look lower in the range. */
-              svn_error_clear(err);
-              end = mid_rev;
-              mid_rev = (start + mid_rev) / 2;
-            }
-          else
-            return svn_error_trace(err);
+          /* Case D: Look lower in the range. */
+          end = mid_rev;
+          mid_rev = (start + mid_rev) / 2;
         }
       else
         {
           /* Determine the relationship between the start node
              and the current node. */
-          int cmp = svn_fs_compare_ids(start_node_id, curr_node_id);
+          SVN_ERR(svn_fs_node_relation(&node_relation, start_root, path,
+                                       root, path, pool));
+          if (node_relation != svn_fs_node_unrelated)
           SVN_ERR(svn_fs_closest_copy(&copy_root, &copy_path, root,
                                       path, subpool));
-          if (cmp == -1 ||
+          if (node_relation == svn_fs_node_unrelated ||
               (copy_root &&
                (svn_fs_revision_root_revision(copy_root) > start)))
             {
@@ -654,7 +637,6 @@ svn_repos_trace_node_locations(svn_fs_t 
   svn_revnum_t revision;
   svn_boolean_t is_ancestor;
   apr_pool_t *lastpool, *currpool;
-  const svn_fs_id_t *id;
 
   SVN_ERR_ASSERT(location_revisions_orig->elt_size == sizeof(svn_revnum_t));
 
@@ -774,20 +756,22 @@ svn_repos_trace_node_locations(svn_fs_t 
      the node existing at the same path.  We will look up path@lrev
      for each remaining location-revision and make sure it is related
      to path@revision. */
-  SVN_ERR(svn_fs_revision_root(&root, fs, revision, currpool));
-  SVN_ERR(svn_fs_node_id(&id, root, path, pool));
+  SVN_ERR(svn_fs_revision_root(&root, fs, revision, lastpool));
   while (revision_ptr < revision_ptr_end)
     {
       svn_node_kind_t kind;
-      const svn_fs_id_t *lrev_id;
+      svn_fs_node_relation_t node_relation;
+      svn_fs_root_t *cur_rev_root;
 
       svn_pool_clear(currpool);
-      SVN_ERR(svn_fs_revision_root(&root, fs, *revision_ptr, currpool));
-      SVN_ERR(svn_fs_check_path(&kind, root, path, currpool));
+      SVN_ERR(svn_fs_revision_root(&cur_rev_root, fs, *revision_ptr,
+                                   currpool));
+      SVN_ERR(svn_fs_check_path(&kind, cur_rev_root, path, currpool));
       if (kind == svn_node_none)
         break;
-      SVN_ERR(svn_fs_node_id(&lrev_id, root, path, currpool));
-      if (! svn_fs_check_related(id, lrev_id))
+      SVN_ERR(svn_fs_node_relation(&node_relation, root, path,
+                                   cur_rev_root, path, currpool));
+      if (node_relation == svn_fs_node_unrelated)
         break;
 
       /* The node exists at the same path; record that and advance. */

Propchange: subversion/branches/fsfs-ucsnorm/subversion/libsvn_subr/checksum.h
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_subr/cmdline.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_subr/cmdline.c?rev=1556765&r1=1556764&r2=1556765&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_subr/cmdline.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_subr/cmdline.c Thu Jan  9 09:31:10 2014
@@ -64,6 +64,7 @@
 
 #include "private/svn_cmdline_private.h"
 #include "private/svn_utf_private.h"
+#include "private/svn_sorts_private.h"
 #include "private/svn_string_private.h"
 
 #include "win32_crashrpt.h"

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_subr/config_auth.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_subr/config_auth.c?rev=1556765&r1=1556764&r2=1556765&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_subr/config_auth.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_subr/config_auth.c Thu Jan  9 09:31:10 2014
@@ -89,6 +89,7 @@ svn_config_read_auth_data(apr_hash_t **h
   if (kind == svn_node_file)
     {
       svn_stream_t *stream;
+      svn_string_t *stored_realm;
 
       SVN_ERR_W(svn_stream_open_readonly(&stream, auth_path, pool, pool),
                 _("Unable to open auth file for reading"));
@@ -100,6 +101,11 @@ svn_config_read_auth_data(apr_hash_t **h
                              svn_dirent_local_style(auth_path, pool)));
 
       SVN_ERR(svn_stream_close(stream));
+
+      stored_realm = svn_hash_gets(*hash, SVN_CONFIG_REALMSTRING_KEY);
+
+      if (!stored_realm || strcmp(stored_realm->data, realmstring) != 0)
+        *hash = NULL; /* Hash collision, or somebody tampering with storage */
     }
 
   return SVN_NO_ERROR;

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_subr/error.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_subr/error.c?rev=1556765&r1=1556764&r2=1556765&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_subr/error.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_subr/error.c Thu Jan  9 09:31:10 2014
@@ -261,8 +261,7 @@ svn_error_compose_create(svn_error_t *er
   if (err1 && err2)
     {
       svn_error_compose(err1,
-                        svn_error_quick_wrap(err2,
-                                             _("Additional errors:")));
+                        svn_error_create(SVN_ERR_COMPOSED_ERROR, err2, NULL));
       return err1;
     }
   return err1 ? err1 : err2;
@@ -314,7 +313,10 @@ svn_error_root_cause(svn_error_t *err)
 {
   while (err)
     {
-      if (err->child)
+      /* I don't think we can change the behavior here, but the additional
+         error chain doesn't define the root cause. Perhaps we should rev
+         this function. */
+      if (err->child /*&& err->child->apr_err != SVN_ERR_COMPOSED_ERROR*/)
         err = err->child;
       else
         break;

Propchange: subversion/branches/fsfs-ucsnorm/subversion/libsvn_subr/fnv1a.c
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: subversion/branches/fsfs-ucsnorm/subversion/libsvn_subr/fnv1a.h
------------------------------------------------------------------------------
    svn:eol-style = native