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);