【问题标题】:Mock S3 server stalls if using HTTP/1.1如果使用 HTTP/1.1,模拟 S3 服务器会停止
【发布时间】:2018-08-26 17:42:09
【问题描述】:

我正在编写一个测试,其中使用http.server.HTTPServer/http.server.BaseHTTPRequestHandler 在测试环境中加载一个简单的模拟 S3,以测试涉及 Boto 的 S3Transfer 的多部分下载行为。

它工作正常,除非我指定服务器使用HTTP/1.1。在这种情况下,它将下载一个 100mb 文件的 2 个 8mb 部分,然后挂起。我希望模拟服务器使用HTTP/1.1,因为这是真正的 S3 使用的(我相信)。

下面是一个简化版的测试,可以运行...

pip3 install boto3
python3 test.py    

# test.py

import http.server
import re
import threading

import boto3
from botocore import (
    UNSIGNED,
)
from botocore.client import (
    Config,
)

length = 100 * 2**20

class MockS3(http.server.BaseHTTPRequestHandler):
    # If the below line is commented, the download completes
    protocol_version = 'HTTP/1.1'

    def do_GET(self):
        range_header = self.headers['Range']
        match = re.search(r'^bytes=(\d+)-(\d*)', range_header)
        start_inclusive_str, end_inclusive_str = match.group(1), match.group(2)
        start = int(start_inclusive_str)
        end = int(end_inclusive_str) + 1 if end_inclusive_str else length
        bytes_to_send = end - start

        self.send_response(206)
        self.send_header('Content-Length', str(bytes_to_send))
        self.end_headers()
        self.wfile.write(bytearray(bytes_to_send))

    def do_HEAD(self):
        self.send_response(200)
        self.send_header('Content-Length', length)
        self.end_headers()

server_address = ('localhost', 5678)
server = http.server.HTTPServer(server_address, MockS3)
thread = threading.Thread(target=server.serve_forever)
thread.daemon = True
thread.start()

class Writable():
    def write(self, data):
        pass

s3_client = boto3.client('s3',
  endpoint_url='http://localhost:5678',
  config=Config(signature_version=UNSIGNED),
)

s3_client.download_fileobj(
  Bucket='some',
  Key='key',
  Fileobj=Writable(),
)

请注意,Writable 故意可搜索:在我的真实代码中,我使用的是不可搜索的类文件对象。

是的,moto 可以用来制作模拟 S3,我这样做是为了其他测试,但对于这个特定的测试,我想要“真实”服务器。涉及到自定义文件对象,并希望确保 S3Transfer 以及与此问题无关的其他代码按照我的预期一起运行。

如何设置使用HTTP/1.1 并且可以从中下载 S3Transfer 的模拟 S3 服务器?

【问题讨论】:

  • 超级有趣的问题。我怀疑它与它有什么关系,但是你可以添加一个 Content-type 标题吗?
  • 啊,我怀疑 Web 服务器不是线程安全的,并且有一个线程阻塞了它……但我不确定它为什么可以与 HTTP/1.0 一起使用。请参阅this 可能相关的答案。
  • @erip 尝试使用 application/octet-stream 的内容类型,同样的事情发生了。关于不是线程安全的,我确实在另一个线程中加载了 Web 服务器,但是对于 Web 服务器来说,在这方面不是线程安全的,即不处理多个并发请求,这将是一件很奇怪的事情?我想知道这是否与 HTTP/1.1 的持久连接有关,但不太确定如何。
  • 好问题,但我认为HTTPServer 将同步处理请求,直到添加mixin。我自己没有对此进行测试,但查看了一些问题(例如之前发布的问题,this one 建议这是真的。
  • @erip 啊,是的!是的,我现在意识到服务器在一个单独的线程中并不意味着它可以安全地处理并发请求。我已经添加了ThreadingMixIn,现在它可以工作了。如果你想用这个发布答案,很高兴。

标签: python testing boto3 awss3transfermanager


【解决方案1】:

您的线程逻辑中存在错误。您当前正在做的是在单独的线程上提供服务,但您真正想要做的是同时处理多个线程上的请求。

这可以通过创建一个非常愚蠢的 HTTP 服务器来实现,该服务器只是混合了线程功能:

class ThreadingServer(ThreadingMixIn, HTTPServer):
    pass

并从此服务器而不是基础HTTPServer 提供服务。

至于为什么这适用于HTTP/1.0,在处理了一个请求后连接就关闭了。

【讨论】:

    猜你喜欢
    • 2016-07-29
    • 1970-01-01
    • 1970-01-01
    • 2014-10-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-13
    相关资源
    最近更新 更多