python http客户端卡在100继续

时间:2016-06-28 19:43:16

标签: python python-3.x http

我在python中有一个简单的http服务器,它使用100继续实现PUT:

class TestHandler(SimpleHTTPRequestHandler):
    def do_PUT(self):
        length = int(self.headers.get('Content-Length'))
        self.send_response_only(100)
        self.end_headers()
        data = self.rfile.read(length)
        res = manipulate(data)
        new_length = len(res)
        self.send_response(200)
        self.send_header("Content-Length", new_length)
        self.end_headers()
        self.wfile.write(res)

server = HTTPServer(("localhost", 8080), TestHandler)
server.serve_forever()

我尝试使用此客户端连接到服务器:

def send_put(data):
    c = HTTPConnection('localhost', 8080)
    c.request('PUT', 'http://localhost:8080/', headers={'Content-Length': len(data), 'Expect': '100-continue'})
    r = c.getresponse()
    if 100 != r.status:
        return
    c.request('PUT', 'http://localhost:8080/', body=data)
    r = c.getresponse()
    print(r.read())

但代码总是卡在第一个'getresponse'上,即使我能看到wireshark上的100-continue响应,我在这里做错了什么? python http甚至支持100-continue?

编辑:在查看了一些python http代码后,我发现为什么getresponse被卡住了; python的http只是忽略100-continue并等待下一个永远不会发生的响应(来自python3.4 / http / client.py):

# read until we get a non-100 response
while True:
    version, status, reason = self._read_status()
    if status != CONTINUE:
        break
    # skip the header from the 100 response
    while True:
        skip = self.fp.readline(_MAXLINE + 1)
        if len(skip) > _MAXLINE:
            raise LineTooLong("header line")
        skip = skip.strip()
        if not skip:
            break
        if self.debuglevel > 0:
            print("header:", skip)

1 个答案:

答案 0 :(得分:2)

我也碰到了这个;它是nine year old Python issue。我提出了以下相当严重的问题"只是让它运行"解决方法,这似乎适用于我的情况(Python 3.5,仅限HTTPS):

class ContinueHTTPResponse(http.client.HTTPResponse):
    def _read_status(self, *args, **kwargs):
        version, status, reason = super()._read_status(*args, **kwargs)
        if status == 100:
            status = 199
        return version, status, reason

    def begin(self, *args, **kwargs):
        super().begin(*args, **kwargs)
        if self.status == 199:
            self.status = 100

    def _check_close(self, *args, **kwargs):
        return super()._check_close(*args, **kwargs) and self.status != 100


class ContinueHTTPSConnection(http.client.HTTPSConnection):
    response_class = ContinueHTTPResponse

    def getresponse(self, *args, **kwargs):
        logging.debug('running getresponse')
        response = super().getresponse(*args, **kwargs)
        if response.status == 100:
            setattr(self, '_HTTPConnection__state', http.client._CS_REQ_SENT)
            setattr(self, '_HTTPConnection__response', None)
        return response

我使用它有点像这样:

conn = ContinueHTTPSConnection(host)
conn.request(...)
resp = conn.getresponse()

if resp.status == http.client.CONTINUE:
    resp.read()
    conn.send(body)
    resp = conn.getresponse()

# do something with resp if you want...
警告:超级hacky。可能充满了bug。使用风险自负。