[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'),

`