Author: kotkov
Date: Wed Mar 14 18:48:37 2018
New Revision: 1826747

URL: http://svn.apache.org/viewvc?rev=1826747&view=rev
Log:
Fix an issue in the svn_txdelta_to_svndiff_stream() API that could cause
unexpected short reads (EOFs) on the stream.

This API is used when performing PUT requests to the server.  Consequently,
the bug could result in truncated payload being sent to the server and
failing commits over http://.

* subversion/libsvn_delta/svndiff.c
  (svndiff_stream_read_fn): Handle a case where we have received the final
   window from the txdelta stream, but the remaining part of the buffer
   cannot fully accommodate it during this call to read_fn.  Instead of
   exiting and triggering an unexpected short read, allow the remaining
   part to be read during subsequent calls to read_fn.

* subversion/tests/libsvn_delta
  (): Add 'svndiff-stream-test' to svn:ignore.

* subversion/tests/libsvn_delta/svndiff-stream-test.c: New file with a
  regression test for this issue.

* build.conf
  (svndiff-stream-test): New.
  (__ALL_TESTS__): Run svndiff-stream-test.

Added:
    subversion/trunk/subversion/tests/libsvn_delta/svndiff-stream-test.c   
(with props)
Modified:
    subversion/trunk/build.conf
    subversion/trunk/subversion/libsvn_delta/svndiff.c
    subversion/trunk/subversion/tests/libsvn_delta/   (props changed)

Modified: subversion/trunk/build.conf
URL: 
http://svn.apache.org/viewvc/subversion/trunk/build.conf?rev=1826747&r1=1826746&r2=1826747&view=diff
==============================================================================
--- subversion/trunk/build.conf (original)
+++ subversion/trunk/build.conf Wed Mar 14 18:48:37 2018
@@ -1207,6 +1207,14 @@ sources = window-test.c
 install = test
 libs = libsvn_test libsvn_delta libsvn_subr apriconv apr
 
+[svndiff-stream-test]
+description = Test svndiff streams
+type = exe
+path = subversion/tests/libsvn_delta
+sources = svndiff-stream-test.c
+install = test
+libs = libsvn_test libsvn_delta libsvn_subr apriconv apr
+
 # ----------------------------------------------------------------------------
 # Tests for libsvn_client
 
@@ -1580,6 +1588,7 @@ libs = __ALL__
        op-depth-test dirent_uri-test wc-queries-test wc-test
        auth-test
        parse-diff-test x509-test xml-test afl-x509 compress-test
+       svndiff-stream-test
 
 [__MORE__]
 type = project

Modified: subversion/trunk/subversion/libsvn_delta/svndiff.c
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_delta/svndiff.c?rev=1826747&r1=1826746&r2=1826747&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_delta/svndiff.c (original)
+++ subversion/trunk/subversion/libsvn_delta/svndiff.c Wed Mar 14 18:48:37 2018
@@ -1026,11 +1026,11 @@ svndiff_stream_read_fn(void *baton, char
   apr_size_t left = *len;
   apr_size_t read = 0;
 
-  while (left && !b->hit_eof)
+  while (left)
     {
       apr_size_t chunk_size;
 
-      if (b->read_pos == b->window_buffer->len)
+      if (b->read_pos == b->window_buffer->len && !b->hit_eof)
         {
           svn_txdelta_window_t *window;
 
@@ -1050,6 +1050,9 @@ svndiff_stream_read_fn(void *baton, char
       else
         chunk_size = left;
 
+      if (!chunk_size)
+          break;
+
       memcpy(buffer, b->window_buffer->data + b->read_pos, chunk_size);
       b->read_pos += chunk_size;
       buffer += chunk_size;

Propchange: subversion/trunk/subversion/tests/libsvn_delta/
------------------------------------------------------------------------------
--- svn:ignore (original)
+++ svn:ignore Wed Mar 14 18:48:37 2018
@@ -8,6 +8,7 @@ vdelta-test
 random-test
 xml-output-test
 svndiff-test
+svndiff-stream-test
 window-test
 editor-test
 combined

Added: subversion/trunk/subversion/tests/libsvn_delta/svndiff-stream-test.c
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/libsvn_delta/svndiff-stream-test.c?rev=1826747&view=auto
==============================================================================
--- subversion/trunk/subversion/tests/libsvn_delta/svndiff-stream-test.c (added)
+++ subversion/trunk/subversion/tests/libsvn_delta/svndiff-stream-test.c Wed 
Mar 14 18:48:37 2018
@@ -0,0 +1,79 @@
+/*
+ * svndiff-stream-test.c:  test svndiff streams
+ *
+ * ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you under the Apache License, Version 2.0 (the
+ *    "License"); you may not use this file except in compliance
+ *    with the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing,
+ *    software distributed under the License is distributed on an
+ *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *    KIND, either express or implied.  See the License for the
+ *    specific language governing permissions and limitations
+ *    under the License.
+ * ====================================================================
+ */
+
+#include "svn_delta.h"
+#include "../svn_test.h"
+
+static svn_error_t *
+null_window(svn_txdelta_window_t **window,
+            void *baton, apr_pool_t *pool)
+{
+  *window = NULL;
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+test_txdelta_to_svndiff_stream_small_reads(apr_pool_t *pool)
+{
+  svn_txdelta_stream_t *txstream;
+  svn_stream_t *svndiff_stream;
+  char buf[64];
+  apr_size_t len;
+
+  txstream = svn_txdelta_stream_create(NULL, null_window, NULL, pool);
+  svndiff_stream = svn_txdelta_to_svndiff_stream(txstream, 0, 0, pool);
+
+  len = 3;
+  SVN_ERR(svn_stream_read_full(svndiff_stream, buf, &len));
+  SVN_TEST_INT_ASSERT((int) len, 3);
+  SVN_TEST_ASSERT(memcmp(buf, "SVN", len) == 0);
+
+  len = 1;
+  SVN_ERR(svn_stream_read_full(svndiff_stream, buf, &len));
+  SVN_TEST_INT_ASSERT((int) len, 1);
+  SVN_TEST_ASSERT(memcmp(buf, "\x00", len) == 0);
+
+  /* Test receiving the EOF. */
+  len = sizeof(buf);
+  SVN_ERR(svn_stream_read_full(svndiff_stream, buf, &len));
+  SVN_TEST_INT_ASSERT((int) len, 0);
+
+  /* Test reading after the EOF. */
+  len = sizeof(buf);
+  SVN_ERR(svn_stream_read_full(svndiff_stream, buf, &len));
+  SVN_TEST_INT_ASSERT((int) len, 0);
+
+  return SVN_NO_ERROR;
+}
+
+static int max_threads = -1;
+
+static struct svn_test_descriptor_t test_funcs[] =
+{
+  SVN_TEST_NULL,
+  SVN_TEST_PASS2(test_txdelta_to_svndiff_stream_small_reads,
+                 "test svn_txdelta_to_svndiff_stream() small reads"),
+  SVN_TEST_NULL
+};
+
+SVN_TEST_MAIN

Propchange: subversion/trunk/subversion/tests/libsvn_delta/svndiff-stream-test.c
------------------------------------------------------------------------------
    svn:eol-style = native


Reply via email to