正如您在描述中看到的传输编码 https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Transfer-Encoding,分块传输将具有以下形状:
chunk1_length\r\n
chunk1 (binary data)
\r\n
chunk2_length\r\n
chunk2 (binary data)
\r\n
0\r\n
\r\n
您只需读取一行,获取下一个块的大小,然后消耗两个二进制块and后续换行符。
这个例子将能够处理请求Content-Length
or Transfer-Encoding: chunked
标头。
from http.server import HTTPServer, SimpleHTTPRequestHandler
PORT = 8080
class TestHTTPRequestHandler(SimpleHTTPRequestHandler):
def do_PUT(self):
self.send_response(200)
self.end_headers()
path = self.translate_path(self.path)
if "Content-Length" in self.headers:
content_length = int(self.headers["Content-Length"])
body = self.rfile.read(content_length)
with open(path, "wb") as out_file:
out_file.write(body)
elif "chunked" in self.headers.get("Transfer-Encoding", ""):
with open(path, "wb") as out_file:
while True:
line = self.rfile.readline().strip()
chunk_length = int(line, 16)
if chunk_length != 0:
chunk = self.rfile.read(chunk_length)
out_file.write(chunk)
# Each chunk is followed by an additional empty newline
# that we have to consume.
self.rfile.readline()
# Finally, a chunk size of 0 is an end indication
if chunk_length == 0:
break
httpd = HTTPServer(("", PORT), TestHTTPRequestHandler)
print("Serving at port:", httpd.server_port)
httpd.serve_forever()
注意我选择继承自简单HTTP请求处理程序代替基本HTTP请求处理程序,因为那么该方法SimpleHTTPRequestHandler.translate_path()
可用于允许客户端选择目标路径(这可能有用也可能没用,具体取决于用例;我的示例已经编写为使用它)。
您可以使用以下命令测试两种操作模式curl命令,正如您提到的:
# PUT with "Content-Length":
curl --upload-file "file.txt" \
"http://127.0.0.1:8080/uploaded.txt"
# PUT with "Transfer-Encoding: chunked":
curl --upload-file "file.txt" -H "Transfer-Encoding: chunked" \
"http://127.0.0.1:8080/uploaded.txt"