python / python/cpython

asyncio SSL loses received data when `get_buffer()` returns a `bytearray`

未关闭
#156,275 3 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

还没有人认领这个 Issue。

stdlib topic-asyncio type-bug
主要语言
Python
星标
77.2k
派生
36k
PR 合并指标
PR 指标待抓取

描述

Bug report

Bug description:

Over TLS, a BufferedProtocol returning a bytearray from get_buffer() gets NULs instead of data - with the byte count still reported as correct.

Repro (run from a CPython directory root):

import asyncio 
import ssl

D = "Lib/test/certdata/"

class Buffered(asyncio.BufferedProtocol):
    buf = bytearray(100)
    def get_buffer(self, hint): return self.buf
    def buffer_updated(self, n): print("BufferedProtocol:", bytes(self.buf[:n]))

class Plain(asyncio.Protocol):
    def data_received(self, data): print("Protocol        :", data)

async def h(r, w):
    w.write(b"A"*30); await w.drain(); w.write(b"B"*30)

async def main():
    srv_ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER); srv_ctx.load_cert_chain(D + "keycert3.pem")
    cli_ctx = ssl.create_default_context(cafile=D + "pycacert.pem")
    srv = await asyncio.start_server(h, "localhost", 0, ssl=srv_ctx)
    port = srv.sockets[0].getsockname()[1]
    loop = asyncio.get_running_loop()
    for proto in (Buffered, Plain):
        await loop.create_connection(proto, "localhost", port, ssl=cli_ctx)
        await asyncio.sleep(0.3)

asyncio.run(main())

The output would be, Protocol is here to have an example of proper behavior

BufferedProtocol: b'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
Protocol        : b'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBBBBBBB'

Doc says (asyncio-protocol.rst - 620)

get_buffer() must return an object implementing the buffer protocol.

Proposed fix is to take memoryview(buf) once before the loop and read into view[offset:]

I have a fix ready for that

CPython versions tested on:

CPython main branch

Operating systems tested on:

macOS

Linked PRs
  • gh-156276

贡献指南

打开贡献指南

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

调研方向

首先查看 asyncio 协议文档中 asyncio-protocol.rst 约第 620 行的内容,并复现 issue 中的 TLS BufferedProtocol 示例。然后检查链接的 PR gh-156276 以及相关的 asyncio SSL 传输测试;当 bytearray 缓冲区能够保留接收到的 TLS 数据,并且该回归问题有测试覆盖时,即视为完成。

由索引模型根据 Issue 内容生成。

评估

技术栈
python
领域
networking
Issue 类型
缺陷
难度
3/5
预计耗时
1-2 天
活跃度
停滞
描述清晰度
描述清楚
新手友好度
35/100

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。