We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Raise an exception if trying to write into closed response
See https://stackoverflow.com/questions/47175297/handling-premature-client-disconnection-in-aiohttp

The problem is: `await drain()` does nothing because the buffer is not overflown, the buffer is not overflown because sent data are ignored and not accumulated in internal buffer.
`transport.is_closing()` should be used for check.

It should be fixed in payload writer, affects both client and server.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `aiohttp/http_writer.py`
Content:
```
1 """Http related parsers and protocol."""
2 
3 import collections
4 import socket
5 import zlib
6 from contextlib import suppress
7 
8 from .abc import AbstractPayloadWriter
9 from .helpers import noop
10 
11 
12 __all__ = ('PayloadWriter', 'HttpVersion', 'HttpVersion10', 'HttpVersion11',
13            'StreamWriter')
14 
15 HttpVersion = collections.namedtuple('HttpVersion', ['major', 'minor'])
16 HttpVersion10 = HttpVersion(1, 0)
17 HttpVersion11 = HttpVersion(1, 1)
18 
19 
20 if hasattr(socket, 'TCP_CORK'):  # pragma: no cover
21     CORK = socket.TCP_CORK
22 elif hasattr(socket, 'TCP_NOPUSH'):  # pragma: no cover
23     CORK = socket.TCP_NOPUSH
24 else:  # pragma: no cover
25     CORK = None
26 
27 
28 class StreamWriter:
29 
30     def __init__(self, protocol, transport, loop):
31         self._protocol = protocol
32         self._loop = loop
33         self._tcp_nodelay = False
34         self._tcp_cork = False
35         self._socket = transport.get_extra_info('socket')
36         self._waiters = []
37         self.transport = transport
38 
39     @property
40     def tcp_nodelay(self):
41         return self._tcp_nodelay
42 
43     def set_tcp_nodelay(self, value):
44         value = bool(value)
45         if self._tcp_nodelay == value:
46             return
47         if self._socket is None:
48             return
49         if self._socket.family not in (socket.AF_INET, socket.AF_INET6):
50             return
51 
52         # socket may be closed already, on windows OSError get raised
53         with suppress(OSError):
54             if self._tcp_cork:
55                 if CORK is not None:  # pragma: no branch
56                     self._socket.setsockopt(socket.IPPROTO_TCP, CORK, False)
57                     self._tcp_cork = False
58 
59             self._socket.setsockopt(
60                 socket.IPPROTO_TCP, socket.TCP_NODELAY, value)
61             self._tcp_nodelay = value
62 
63     @property
64     def tcp_cork(self):
65         return self._tcp_cork
66 
67     def set_tcp_cork(self, value):
68         value = bool(value)
69         if self._tcp_cork == value:
70             return
71         if self._socket is None:
72             return
73         if self._socket.family not in (socket.AF_INET, socket.AF_INET6):
74             return
75 
76         with suppress(OSError):
77             if self._tcp_nodelay:
78                 self._socket.setsockopt(
79                     socket.IPPROTO_TCP, socket.TCP_NODELAY, False)
80                 self._tcp_nodelay = False
81             if CORK is not None:  # pragma: no branch
82                 self._socket.setsockopt(socket.IPPROTO_TCP, CORK, value)
83                 self._tcp_cork = value
84 
85     async def drain(self):
86         """Flush the write buffer.
87 
88         The intended use is to write
89 
90           await w.write(data)
91           await w.drain()
92         """
93         if self._protocol.transport is not None:
94             await self._protocol._drain_helper()
95 
96 
97 class PayloadWriter(AbstractPayloadWriter):
98 
99     def __init__(self, stream, loop):
100         self._stream = stream
101         self._transport = None
102 
103         self.loop = loop
104         self.length = None
105         self.chunked = False
106         self.buffer_size = 0
107         self.output_size = 0
108 
109         self._eof = False
110         self._compress = None
111         self._drain_waiter = None
112         self._transport = self._stream.transport
113 
114     async def get_transport(self):
115         return self._transport
116 
117     def enable_chunking(self):
118         self.chunked = True
119 
120     def enable_compression(self, encoding='deflate'):
121         zlib_mode = (16 + zlib.MAX_WBITS
122                      if encoding == 'gzip' else -zlib.MAX_WBITS)
123         self._compress = zlib.compressobj(wbits=zlib_mode)
124 
125     def _write(self, chunk):
126         size = len(chunk)
127         self.buffer_size += size
128         self.output_size += size
129         self._transport.write(chunk)
130 
131     def write(self, chunk, *, drain=True, LIMIT=64*1024):
132         """Writes chunk of data to a stream.
133 
134         write_eof() indicates end of stream.
135         writer can't be used after write_eof() method being called.
136         write() return drain future.
137         """
138         if self._compress is not None:
139             chunk = self._compress.compress(chunk)
140             if not chunk:
141                 return noop()
142 
143         if self.length is not None:
144             chunk_len = len(chunk)
145             if self.length >= chunk_len:
146                 self.length = self.length - chunk_len
147             else:
148                 chunk = chunk[:self.length]
149                 self.length = 0
150                 if not chunk:
151                     return noop()
152 
153         if chunk:
154             if self.chunked:
155                 chunk_len = ('%x\r\n' % len(chunk)).encode('ascii')
156                 chunk = chunk_len + chunk + b'\r\n'
157 
158             self._write(chunk)
159 
160             if self.buffer_size > LIMIT and drain:
161                 self.buffer_size = 0
162                 return self.drain()
163 
164         return noop()
165 
166     def write_headers(self, status_line, headers, SEP=': ', END='\r\n'):
167         """Write request/response status and headers."""
168         # status + headers
169         headers = status_line + ''.join(
170             [k + SEP + v + END for k, v in headers.items()])
171         headers = headers.encode('utf-8') + b'\r\n'
172         self._write(headers)
173 
174     async def write_eof(self, chunk=b''):
175         if self._eof:
176             return
177 
178         if self._compress:
179             if chunk:
180                 chunk = self._compress.compress(chunk)
181 
182             chunk = chunk + self._compress.flush()
183             if chunk and self.chunked:
184                 chunk_len = ('%x\r\n' % len(chunk)).encode('ascii')
185                 chunk = chunk_len + chunk + b'\r\n0\r\n\r\n'
186         else:
187             if self.chunked:
188                 if chunk:
189                     chunk_len = ('%x\r\n' % len(chunk)).encode('ascii')
190                     chunk = chunk_len + chunk + b'\r\n0\r\n\r\n'
191                 else:
192                     chunk = b'0\r\n\r\n'
193 
194         if chunk:
195             self._write(chunk)
196 
197         await self.drain()
198 
199         self._eof = True
200         self._transport = None
201 
202     async def drain(self):
203         await self._stream.drain()
204
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/aiohttp/http_writer.py b/aiohttp/http_writer.py
--- a/aiohttp/http_writer.py
+++ b/aiohttp/http_writer.py
@@ -1,5 +1,6 @@
 """Http related parsers and protocol."""
 
+import asyncio
 import collections
 import socket
 import zlib
@@ -126,6 +127,9 @@
         size = len(chunk)
         self.buffer_size += size
         self.output_size += size
+
+        if self._transport.is_closing():
+            raise asyncio.CancelledError('Cannot write to closing transport')
         self._transport.write(chunk)
 
     def write(self, chunk, *, drain=True, LIMIT=64*1024):

{"golden_diff": "diff --git a/aiohttp/http_writer.py b/aiohttp/http_writer.py\n--- a/aiohttp/http_writer.py\n+++ b/aiohttp/http_writer.py\n@@ -1,5 +1,6 @@\n \"\"\"Http related parsers and protocol.\"\"\"\n \n+import asyncio\n import collections\n import socket\n import zlib\n@@ -126,6 +127,9 @@\n         size = len(chunk)\n         self.buffer_size += size\n         self.output_size += size\n+\n+        if self._transport.is_closing():\n+            raise asyncio.CancelledError('Cannot write to closing transport')\n         self._transport.write(chunk)\n \n     def write(self, chunk, *, drain=True, LIMIT=64*1024):\n", "issue": "Raise an exception if trying to write into closed response\nSee https://stackoverflow.com/questions/47175297/handling-premature-client-disconnection-in-aiohttp\r\n\r\nThe problem is: `await drain()` does nothing because the buffer is not overflown, the buffer is not overflown because sent data are ignored and not accumulated in internal buffer.\r\n`transport.is_closing()` should be used for check.\r\n\r\nIt should be fixed in payload writer, affects both client and server.\n", "before_files": [{"content": "\"\"\"Http related parsers and protocol.\"\"\"\n\nimport collections\nimport socket\nimport zlib\nfrom contextlib import suppress\n\nfrom .abc import AbstractPayloadWriter\nfrom .helpers import noop\n\n\n__all__ = ('PayloadWriter', 'HttpVersion', 'HttpVersion10', 'HttpVersion11',\n           'StreamWriter')\n\nHttpVersion = collections.namedtuple('HttpVersion', ['major', 'minor'])\nHttpVersion10 = HttpVersion(1, 0)\nHttpVersion11 = HttpVersion(1, 1)\n\n\nif hasattr(socket, 'TCP_CORK'):  # pragma: no cover\n    CORK = socket.TCP_CORK\nelif hasattr(socket, 'TCP_NOPUSH'):  # pragma: no cover\n    CORK = socket.TCP_NOPUSH\nelse:  # pragma: no cover\n    CORK = None\n\n\nclass StreamWriter:\n\n    def __init__(self, protocol, transport, loop):\n        self._protocol = protocol\n        self._loop = loop\n        self._tcp_nodelay = False\n        self._tcp_cork = False\n        self._socket = transport.get_extra_info('socket')\n        self._waiters = []\n        self.transport = transport\n\n    @property\n    def tcp_nodelay(self):\n        return self._tcp_nodelay\n\n    def set_tcp_nodelay(self, value):\n        value = bool(value)\n        if self._tcp_nodelay == value:\n            return\n        if self._socket is None:\n            return\n        if self._socket.family not in (socket.AF_INET, socket.AF_INET6):\n            return\n\n        # socket may be closed already, on windows OSError get raised\n        with suppress(OSError):\n            if self._tcp_cork:\n                if CORK is not None:  # pragma: no branch\n                    self._socket.setsockopt(socket.IPPROTO_TCP, CORK, False)\n                    self._tcp_cork = False\n\n            self._socket.setsockopt(\n                socket.IPPROTO_TCP, socket.TCP_NODELAY, value)\n            self._tcp_nodelay = value\n\n    @property\n    def tcp_cork(self):\n        return self._tcp_cork\n\n    def set_tcp_cork(self, value):\n        value = bool(value)\n        if self._tcp_cork == value:\n            return\n        if self._socket is None:\n            return\n        if self._socket.family not in (socket.AF_INET, socket.AF_INET6):\n            return\n\n        with suppress(OSError):\n            if self._tcp_nodelay:\n                self._socket.setsockopt(\n                    socket.IPPROTO_TCP, socket.TCP_NODELAY, False)\n                self._tcp_nodelay = False\n            if CORK is not None:  # pragma: no branch\n                self._socket.setsockopt(socket.IPPROTO_TCP, CORK, value)\n                self._tcp_cork = value\n\n    async def drain(self):\n        \"\"\"Flush the write buffer.\n\n        The intended use is to write\n\n          await w.write(data)\n          await w.drain()\n        \"\"\"\n        if self._protocol.transport is not None:\n            await self._protocol._drain_helper()\n\n\nclass PayloadWriter(AbstractPayloadWriter):\n\n    def __init__(self, stream, loop):\n        self._stream = stream\n        self._transport = None\n\n        self.loop = loop\n        self.length = None\n        self.chunked = False\n        self.buffer_size = 0\n        self.output_size = 0\n\n        self._eof = False\n        self._compress = None\n        self._drain_waiter = None\n        self._transport = self._stream.transport\n\n    async def get_transport(self):\n        return self._transport\n\n    def enable_chunking(self):\n        self.chunked = True\n\n    def enable_compression(self, encoding='deflate'):\n        zlib_mode = (16 + zlib.MAX_WBITS\n                     if encoding == 'gzip' else -zlib.MAX_WBITS)\n        self._compress = zlib.compressobj(wbits=zlib_mode)\n\n    def _write(self, chunk):\n        size = len(chunk)\n        self.buffer_size += size\n        self.output_size += size\n        self._transport.write(chunk)\n\n    def write(self, chunk, *, drain=True, LIMIT=64*1024):\n        \"\"\"Writes chunk of data to a stream.\n\n        write_eof() indicates end of stream.\n        writer can't be used after write_eof() method being called.\n        write() return drain future.\n        \"\"\"\n        if self._compress is not None:\n            chunk = self._compress.compress(chunk)\n            if not chunk:\n                return noop()\n\n        if self.length is not None:\n            chunk_len = len(chunk)\n            if self.length >= chunk_len:\n                self.length = self.length - chunk_len\n            else:\n                chunk = chunk[:self.length]\n                self.length = 0\n                if not chunk:\n                    return noop()\n\n        if chunk:\n            if self.chunked:\n                chunk_len = ('%x\\r\\n' % len(chunk)).encode('ascii')\n                chunk = chunk_len + chunk + b'\\r\\n'\n\n            self._write(chunk)\n\n            if self.buffer_size > LIMIT and drain:\n                self.buffer_size = 0\n                return self.drain()\n\n        return noop()\n\n    def write_headers(self, status_line, headers, SEP=': ', END='\\r\\n'):\n        \"\"\"Write request/response status and headers.\"\"\"\n        # status + headers\n        headers = status_line + ''.join(\n            [k + SEP + v + END for k, v in headers.items()])\n        headers = headers.encode('utf-8') + b'\\r\\n'\n        self._write(headers)\n\n    async def write_eof(self, chunk=b''):\n        if self._eof:\n            return\n\n        if self._compress:\n            if chunk:\n                chunk = self._compress.compress(chunk)\n\n            chunk = chunk + self._compress.flush()\n            if chunk and self.chunked:\n                chunk_len = ('%x\\r\\n' % len(chunk)).encode('ascii')\n                chunk = chunk_len + chunk + b'\\r\\n0\\r\\n\\r\\n'\n        else:\n            if self.chunked:\n                if chunk:\n                    chunk_len = ('%x\\r\\n' % len(chunk)).encode('ascii')\n                    chunk = chunk_len + chunk + b'\\r\\n0\\r\\n\\r\\n'\n                else:\n                    chunk = b'0\\r\\n\\r\\n'\n\n        if chunk:\n            self._write(chunk)\n\n        await self.drain()\n\n        self._eof = True\n        self._transport = None\n\n    async def drain(self):\n        await self._stream.drain()\n", "path": "aiohttp/http_writer.py"}], "after_files": [{"content": "\"\"\"Http related parsers and protocol.\"\"\"\n\nimport asyncio\nimport collections\nimport socket\nimport zlib\nfrom contextlib import suppress\n\nfrom .abc import AbstractPayloadWriter\nfrom .helpers import noop\n\n\n__all__ = ('PayloadWriter', 'HttpVersion', 'HttpVersion10', 'HttpVersion11',\n           'StreamWriter')\n\nHttpVersion = collections.namedtuple('HttpVersion', ['major', 'minor'])\nHttpVersion10 = HttpVersion(1, 0)\nHttpVersion11 = HttpVersion(1, 1)\n\n\nif hasattr(socket, 'TCP_CORK'):  # pragma: no cover\n    CORK = socket.TCP_CORK\nelif hasattr(socket, 'TCP_NOPUSH'):  # pragma: no cover\n    CORK = socket.TCP_NOPUSH\nelse:  # pragma: no cover\n    CORK = None\n\n\nclass StreamWriter:\n\n    def __init__(self, protocol, transport, loop):\n        self._protocol = protocol\n        self._loop = loop\n        self._tcp_nodelay = False\n        self._tcp_cork = False\n        self._socket = transport.get_extra_info('socket')\n        self._waiters = []\n        self.transport = transport\n\n    @property\n    def tcp_nodelay(self):\n        return self._tcp_nodelay\n\n    def set_tcp_nodelay(self, value):\n        value = bool(value)\n        if self._tcp_nodelay == value:\n            return\n        if self._socket is None:\n            return\n        if self._socket.family not in (socket.AF_INET, socket.AF_INET6):\n            return\n\n        # socket may be closed already, on windows OSError get raised\n        with suppress(OSError):\n            if self._tcp_cork:\n                if CORK is not None:  # pragma: no branch\n                    self._socket.setsockopt(socket.IPPROTO_TCP, CORK, False)\n                    self._tcp_cork = False\n\n            self._socket.setsockopt(\n                socket.IPPROTO_TCP, socket.TCP_NODELAY, value)\n            self._tcp_nodelay = value\n\n    @property\n    def tcp_cork(self):\n        return self._tcp_cork\n\n    def set_tcp_cork(self, value):\n        value = bool(value)\n        if self._tcp_cork == value:\n            return\n        if self._socket is None:\n            return\n        if self._socket.family not in (socket.AF_INET, socket.AF_INET6):\n            return\n\n        with suppress(OSError):\n            if self._tcp_nodelay:\n                self._socket.setsockopt(\n                    socket.IPPROTO_TCP, socket.TCP_NODELAY, False)\n                self._tcp_nodelay = False\n            if CORK is not None:  # pragma: no branch\n                self._socket.setsockopt(socket.IPPROTO_TCP, CORK, value)\n                self._tcp_cork = value\n\n    async def drain(self):\n        \"\"\"Flush the write buffer.\n\n        The intended use is to write\n\n          await w.write(data)\n          await w.drain()\n        \"\"\"\n        if self._protocol.transport is not None:\n            await self._protocol._drain_helper()\n\n\nclass PayloadWriter(AbstractPayloadWriter):\n\n    def __init__(self, stream, loop):\n        self._stream = stream\n        self._transport = None\n\n        self.loop = loop\n        self.length = None\n        self.chunked = False\n        self.buffer_size = 0\n        self.output_size = 0\n\n        self._eof = False\n        self._compress = None\n        self._drain_waiter = None\n        self._transport = self._stream.transport\n\n    async def get_transport(self):\n        return self._transport\n\n    def enable_chunking(self):\n        self.chunked = True\n\n    def enable_compression(self, encoding='deflate'):\n        zlib_mode = (16 + zlib.MAX_WBITS\n                     if encoding == 'gzip' else -zlib.MAX_WBITS)\n        self._compress = zlib.compressobj(wbits=zlib_mode)\n\n    def _write(self, chunk):\n        size = len(chunk)\n        self.buffer_size += size\n        self.output_size += size\n\n        if self._transport.is_closing():\n            raise asyncio.CancelledError('Cannot write to closing transport')\n        self._transport.write(chunk)\n\n    def write(self, chunk, *, drain=True, LIMIT=64*1024):\n        \"\"\"Writes chunk of data to a stream.\n\n        write_eof() indicates end of stream.\n        writer can't be used after write_eof() method being called.\n        write() return drain future.\n        \"\"\"\n        if self._compress is not None:\n            chunk = self._compress.compress(chunk)\n            if not chunk:\n                return noop()\n\n        if self.length is not None:\n            chunk_len = len(chunk)\n            if self.length >= chunk_len:\n                self.length = self.length - chunk_len\n            else:\n                chunk = chunk[:self.length]\n                self.length = 0\n                if not chunk:\n                    return noop()\n\n        if chunk:\n            if self.chunked:\n                chunk_len = ('%x\\r\\n' % len(chunk)).encode('ascii')\n                chunk = chunk_len + chunk + b'\\r\\n'\n\n            self._write(chunk)\n\n            if self.buffer_size > LIMIT and drain:\n                self.buffer_size = 0\n                return self.drain()\n\n        return noop()\n\n    def write_headers(self, status_line, headers, SEP=': ', END='\\r\\n'):\n        \"\"\"Write request/response status and headers.\"\"\"\n        # status + headers\n        headers = status_line + ''.join(\n            [k + SEP + v + END for k, v in headers.items()])\n        headers = headers.encode('utf-8') + b'\\r\\n'\n        self._write(headers)\n\n    async def write_eof(self, chunk=b''):\n        if self._eof:\n            return\n\n        if self._compress:\n            if chunk:\n                chunk = self._compress.compress(chunk)\n\n            chunk = chunk + self._compress.flush()\n            if chunk and self.chunked:\n                chunk_len = ('%x\\r\\n' % len(chunk)).encode('ascii')\n                chunk = chunk_len + chunk + b'\\r\\n0\\r\\n\\r\\n'\n        else:\n            if self.chunked:\n                if chunk:\n                    chunk_len = ('%x\\r\\n' % len(chunk)).encode('ascii')\n                    chunk = chunk_len + chunk + b'\\r\\n0\\r\\n\\r\\n'\n                else:\n                    chunk = b'0\\r\\n\\r\\n'\n\n        if chunk:\n            self._write(chunk)\n\n        await self.drain()\n\n        self._eof = True\n        self._transport = None\n\n    async def drain(self):\n        await self._stream.drain()\n", "path": "aiohttp/http_writer.py"}]}