Author: rhuijben
Date: Mon Aug  8 23:59:41 2011
New Revision: 1155160

URL: http://svn.apache.org/viewvc?rev=1155160&view=rev
Log:
Make serf capable of checking out from Subversion 1.3 repositories with the/a
"lost response" with lingering close bug. (See also r858579)

This code is not pretty but it is a safe and local fix to this problem.
Fixing this problem in a clean way probably requires some design changes to
the request creation in ra_serf.

Before fixing the calculation bug in r1154733 checking out neon from its
repository was completely impossible. But after that fix checkout still failed
in about 30-50% of the cases. This patch fixes those remaining failures by
applying the same fix to the xml requests.

* subversion/libsvn_ra_serf/ra_serf.h
  (svn_ra_serf__xml_parser_t): Add 3 variables to allow tracking restarted
    connections.

* subversion/libsvn_ra_serf/util.c
  (svn_ra_serf__handle_xml_parser): Detect restarted requests by checking if
    the response headers changed since the last invocation. If so apply the same
    skip trick as used in ra_serf/update.c to avoid reading the same xml twice,
    which makes the xml invalid as <?xml is only valid at the start of the xml.

Modified:
    subversion/trunk/subversion/libsvn_ra_serf/ra_serf.h
    subversion/trunk/subversion/libsvn_ra_serf/util.c

Modified: subversion/trunk/subversion/libsvn_ra_serf/ra_serf.h
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_ra_serf/ra_serf.h?rev=1155160&r1=1155159&r2=1155160&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_ra_serf/ra_serf.h (original)
+++ subversion/trunk/subversion/libsvn_ra_serf/ra_serf.h Mon Aug  8 23:59:41 
2011
@@ -629,6 +629,11 @@ struct svn_ra_serf__xml_parser_t {
 
      See libsvn_ra_serf/util.c  */
   struct svn_ra_serf__pending_t *pending;
+
+  /* Response restart support */
+  const void *headers_baton; /* Last pointer to headers */
+  apr_off_t skip_size; /* Number of bytes to skip */
+  apr_off_t read_size; /* Number of bytes read from response */
 };
 
 /*

Modified: subversion/trunk/subversion/libsvn_ra_serf/util.c
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_ra_serf/util.c?rev=1155160&r1=1155159&r2=1155160&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_ra_serf/util.c (original)
+++ subversion/trunk/subversion/libsvn_ra_serf/util.c Mon Aug  8 23:59:41 2011
@@ -1705,6 +1705,22 @@ svn_ra_serf__handle_xml_parser(serf_requ
       return SVN_NO_ERROR;
     }
 
+  if (ctx->headers_baton == NULL)
+    ctx->headers_baton = serf_bucket_response_get_headers(response);
+  else if (ctx->headers_baton != serf_bucket_response_get_headers(response))
+    {
+      /* We got a new response to an existing parser...
+         This tells us the connection has restarted and we should continue
+         where we stopped last time.
+       */
+
+      /* Is this a second attempt?? */
+      if (!ctx->skip_size)
+        ctx->skip_size = ctx->read_size;
+
+      ctx->read_size = 0; /* New request, nothing read */
+    }
+
   if (!ctx->xmlp)
     {
       ctx->xmlp = XML_ParserCreate(NULL);
@@ -1749,6 +1765,35 @@ svn_ra_serf__handle_xml_parser(serf_requ
           return svn_error_wrap_apr(status, NULL);
         }
 
+      ctx->read_size += len;
+
+      if (ctx->skip_size)
+        {
+          /* Handle restarted requests correctly: Skip what we already read */
+          apr_size_t skip;
+
+          if (ctx->skip_size >= ctx->read_size)
+            {
+            /* Eek.  What did the file shrink or something? */
+              if (APR_STATUS_IS_EOF(status))
+                {
+                  SVN_ERR_MALFUNCTION();
+                }
+
+              /* Skip on to the next iteration of this loop. */
+              if (APR_STATUS_IS_EAGAIN(status))
+                {
+                  return svn_error_wrap_apr(status, NULL);
+                }
+              continue;
+            }
+
+          skip = (apr_size_t)(len - (ctx->read_size - ctx->skip_size));
+          data += skip;
+          len -= skip;
+          ctx->skip_size = 0;
+        }
+
       /* Ensure that the parser's PAUSED state is correct before we test
          the flag.  */
       PBTEST_SET_PAUSED(ctx);


Reply via email to