[3.6] bpo-33871: Fix os.sendfile(), os.writev(), os.readv(), etc. (GH… · python/cpython@ada5d99 (original) (raw)
`@@ -2540,12 +2540,14 @@ class Handler(asynchat.async_chat):
`
2540
2540
`def init(self, conn):
`
2541
2541
`asynchat.async_chat.init(self, conn)
`
2542
2542
`self.in_buffer = []
`
``
2543
`+
self.accumulate = True
`
2543
2544
`self.closed = False
`
2544
2545
`self.push(b"220 ready\r\n")
`
2545
2546
``
2546
2547
`def handle_read(self):
`
2547
2548
`data = self.recv(4096)
`
2548
``
`-
self.in_buffer.append(data)
`
``
2549
`+
if self.accumulate:
`
``
2550
`+
self.in_buffer.append(data)
`
2549
2551
``
2550
2552
`def get_data(self):
`
2551
2553
`return b''.join(self.in_buffer)
`
`@@ -2627,6 +2629,8 @@ class TestSendfile(unittest.TestCase):
`
2627
2629
`not sys.platform.startswith("sunos")
`
2628
2630
`requires_headers_trailers = unittest.skipUnless(SUPPORT_HEADERS_TRAILERS,
`
2629
2631
`'requires headers and trailers support')
`
``
2632
`+
requires_32b = unittest.skipUnless(sys.maxsize < 2**32,
`
``
2633
`+
'test is only meaningful on 32-bit builds')
`
2630
2634
``
2631
2635
`@classmethod
`
2632
2636
`def setUpClass(cls):
`
`@@ -2657,17 +2661,13 @@ def tearDown(self):
`
2657
2661
`self.server.stop()
`
2658
2662
`self.server = None
`
2659
2663
``
2660
``
`-
def sendfile_wrapper(self, sock, file, offset, nbytes, headers=[], trailers=[]):
`
``
2664
`+
def sendfile_wrapper(self, *args, **kwargs):
`
2661
2665
`"""A higher level wrapper representing how an application is
`
2662
2666
` supposed to use sendfile().
`
2663
2667
` """
`
2664
``
`-
while 1:
`
``
2668
`+
while True:
`
2665
2669
`try:
`
2666
``
`-
if self.SUPPORT_HEADERS_TRAILERS:
`
2667
``
`-
return os.sendfile(sock, file, offset, nbytes, headers,
`
2668
``
`-
trailers)
`
2669
``
`-
else:
`
2670
``
`-
return os.sendfile(sock, file, offset, nbytes)
`
``
2670
`+
return os.sendfile(*args, **kwargs)
`
2671
2671
`except OSError as err:
`
2672
2672
`if err.errno == errno.ECONNRESET:
`
2673
2673
`# disconnected
`
`@@ -2758,20 +2758,22 @@ def test_keywords(self):
`
2758
2758
`@requires_headers_trailers
`
2759
2759
`def test_headers(self):
`
2760
2760
`total_sent = 0
`
``
2761
`+
expected_data = b"x" * 512 + b"y" * 256 + self.DATA[:-1]
`
2761
2762
`sent = os.sendfile(self.sockno, self.fileno, 0, 4096,
`
2762
``
`-
headers=[b"x" * 512])
`
``
2763
`+
headers=[b"x" * 512, b"y" * 256])
`
``
2764
`+
self.assertLessEqual(sent, 512 + 256 + 4096)
`
2763
2765
`total_sent += sent
`
2764
2766
`offset = 4096
`
2765
``
`-
nbytes = 4096
`
2766
``
`-
while 1:
`
``
2767
`+
while total_sent < len(expected_data):
`
``
2768
`+
nbytes = min(len(expected_data) - total_sent, 4096)
`
2767
2769
`sent = self.sendfile_wrapper(self.sockno, self.fileno,
`
2768
2770
`offset, nbytes)
`
2769
2771
`if sent == 0:
`
2770
2772
`break
`
``
2773
`+
self.assertLessEqual(sent, nbytes)
`
2771
2774
`total_sent += sent
`
2772
2775
`offset += sent
`
2773
2776
``
2774
``
`-
expected_data = b"x" * 512 + self.DATA
`
2775
2777
`self.assertEqual(total_sent, len(expected_data))
`
2776
2778
`self.client.close()
`
2777
2779
`self.server.wait()
`
`@@ -2787,12 +2789,30 @@ def test_trailers(self):
`
2787
2789
`create_file(TESTFN2, file_data)
`
2788
2790
``
2789
2791
`with open(TESTFN2, 'rb') as f:
`
2790
``
`-
os.sendfile(self.sockno, f.fileno(), 0, len(file_data),
`
2791
``
`-
trailers=[b"1234"])
`
``
2792
`+
os.sendfile(self.sockno, f.fileno(), 0, 5,
`
``
2793
`+
trailers=[b"123456", b"789"])
`
2792
2794
`self.client.close()
`
2793
2795
`self.server.wait()
`
2794
2796
`data = self.server.handler_instance.get_data()
`
2795
``
`-
self.assertEqual(data, b"abcdef1234")
`
``
2797
`+
self.assertEqual(data, b"abcde123456789")
`
``
2798
+
``
2799
`+
@requires_headers_trailers
`
``
2800
`+
@requires_32b
`
``
2801
`+
def test_headers_overflow_32bits(self):
`
``
2802
`+
self.server.handler_instance.accumulate = False
`
``
2803
`+
with self.assertRaises(OSError) as cm:
`
``
2804
`+
os.sendfile(self.sockno, self.fileno, 0, 0,
`
``
2805
`+
headers=[b"x" * 216] * 215)
`
``
2806
`+
self.assertEqual(cm.exception.errno, errno.EINVAL)
`
``
2807
+
``
2808
`+
@requires_headers_trailers
`
``
2809
`+
@requires_32b
`
``
2810
`+
def test_trailers_overflow_32bits(self):
`
``
2811
`+
self.server.handler_instance.accumulate = False
`
``
2812
`+
with self.assertRaises(OSError) as cm:
`
``
2813
`+
os.sendfile(self.sockno, self.fileno, 0, 0,
`
``
2814
`+
trailers=[b"x" * 216] * 215)
`
``
2815
`+
self.assertEqual(cm.exception.errno, errno.EINVAL)
`
2796
2816
``
2797
2817
`@requires_headers_trailers
`
2798
2818
`@unittest.skipUnless(hasattr(os, 'SF_NODISKIO'),
`