简体   繁体   English

Python3 ThreadingHTTPServer 无法发送分块编码的响应

[英]Python3 ThreadingHTTPServer fails to send chunked encoded response

I'm implementing a simple reverse proxy in Python3 and I need to send a response with transfer-encoding chunked mode.我正在 Python3 中实现一个简单的反向代理,我需要使用transfer-encoding chunked模式发送响应。

I've taken my cues from this post but I have some problems when sending the chunks in the format described here我从这篇文章中得到了提示,但是在以此处描述的格式发送块时遇到了一些问题

If I send chunks of length <= 9 bytes the message is received correctly by the client, otherwise when sending chunks of l ength >= 10 bytes , it seems that some of them are not received and the message remains stuck in the client waiting indefinitely如果我发送长度的数据块<= 9个字节是由客户端正确地接收到的消息,发送升ength的块,否则当> = 10个字节,似乎它们中的一些不接收和消息仍然停留在客户端无限期地等待

Here is an example of non working code :是非工作代码的示例:

from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer


class ProxyHTTPRequestHandler(BaseHTTPRequestHandler):
    protocol_version = 'HTTP/1.1'
 
    def do_GET(self, body=True):

        # HTTP 200 + minimal HTTP headers in response
        self.send_response(200)
        self.send_header('transfer-encoding', 'chunked')
        self.send_header('Content-Type', 'text/plain')
        self.end_headers()

        # writing 5 chunks of 10 characters
        for i in range(5):
            text = str(i+1) * 10  # concatenate 10 chars
            chunk = '{0:d}\r\n'.format(len(text)) + text + '\r\n'
            self.wfile.write(chunk.encode(encoding='utf-8'))

        # writing close sequence
        close_chunk = '0\r\n\r\n'
        self.wfile.write(close_chunk.encode(encoding='utf-8'))


def main():
    try:
        server_address = ('127.0.0.1', 8099)

        # I use ThreadingHTTPServer but the problem persists also with HTTPServer
        httpd = ThreadingHTTPServer(server_address, ProxyHTTPRequestHandler)
        print('http server is running')
        httpd.serve_forever()
    except KeyboardInterrupt:
        print(" ^C entered, stopping web server...")
        httpd.socket.close()


if __name__ == '__main__':
    main()

In this case, after several seconds, and only if I manually stop python execution the result in Postman is the following.在这种情况下,几秒钟后,只有当我手动停止 python 执行时,Postman 中的结果如下。 Please note the missing "2222222222" chunk请注意缺少的“2222222222”块

邮差错误

But if I use this length instead:但是如果我改用这个长度:

    # writing the same 5 chunks of 9 characters
    for i in range(5):
        text = str(i+1) * 9  # concatenate 9 chars
        chunk = '{0:d}\r\n'.format(len(text)) + text + '\r\n'
        self.wfile.write(chunk.encode(encoding='utf-8'))

    # writing close sequence
    close_chunk = '0\r\n\r\n'
    self.wfile.write(close_chunk.encode(encoding='utf-8'))

The communication ends correctly (after 6ms all the 5 chunks are interpreted correctly)通信正确结束(6 毫秒后,所有 5 个块都被正确解释) 邮递员好的

Some version informations:部分版本信息:

HTTP Client: Postman 8.10 

(venv) manuel@MBP ReverseProxy % python -V
Python 3.9.2

(venv) manuel@MBP ReverseProxy % pip freeze
certifi==2021.10.8
charset-normalizer==2.0.6
idna==3.2
requests==2.26.0
urllib3==1.26.7

Thanks in advance for any hints!提前感谢您的任何提示!

I post the solution (thanks to Martin Panter from bugs.python.org) in case anyone else will have the same problem in the future.我发布了解决方案(感谢来自 bugs.python.org 的 Martin Panter),以防其他人将来遇到同样的问题。

The behaviour was caused by the chunk size part, that must be in hex format, not decimal .该行为是由块大小部分引起的,它必须是十六进制格式,而不是十进制

Unfortunately from the Mozilla docs the format was not specified and the example used only length < 10. A formal definition is found here不幸的是,Mozilla 文档中没有指定格式,示例中仅使用长度 < 10。这里有一个正式定义

In conclusion, the working version is the following (using {0:x} instead of {0:d} )总之,工作版本如下(使用{0:x}而不是{0:d}

# writing the same 5 chunks of 9 characters
    for i in range(5):
        text = str(i+1) * 9  # concatenate 9 chars
        chunk = '{0:x}\r\n'.format(len(text)) + text + '\r\n'
        self.wfile.write(chunk.encode(encoding='utf-8'))

    # writing close sequence
    close_chunk = '0\r\n\r\n'
    self.wfile.write(close_chunk.encode(encoding='utf-8'))

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM