为什么environ ['wsgi.input']。read()阻止,即使它被PEP-3333允许?

时间:2014-04-06 12:33:49

标签: python python-3.x wsgi

问题

这是一个应该打印Content-Length的简单WSGI应用程序 和标题中的请求正文。

def application(environ, start_response):
    start_response('200 OK', [('Content-Type','text/plain')])
    content_length = int(environ['CONTENT_LENGTH'])
    print('---- Begin ----')
    print('CONTENT_LENGTH:', content_length)
    print('wsgi.input:', environ['wsgi.input'].read())
    print('---- End ----')
    return [b'Foo\n']

if __name__ == '__main__':
    from wsgiref import simple_server
    server = simple_server.make_server('0.0.0.0', 8080, application)
    server.serve_forever()

当我运行此应用程序时,它会在以下调用时被阻止:environ['wsgi.input'].read()

我使用Python 3解释器运行应用程序,并使用curl向它提交HTTP post请求。

lone@debian:~$ curl --data "a=1&b=2" http://localhost:8080/

curl命令被阻塞等待输出。 python解释器在environ['wsgi.input'].read()调用时被阻止。

lone@debian:~$ python3 foo.py
---- Begin ----
CONTENT_LENGTH: 7

正如您在上面的输出中所看到的,application()功能在打印CONTENT_LENGTH后被阻止。

解决方法

我知道如何解决此问题:将Content-Length标头值传递给read()电话。

修改代码以解决此问题:

def application(environ, start_response):
    start_response('200 OK', [('Content-Type','text/plain')])
    content_length = int(environ['CONTENT_LENGTH'])
    print('---- Begin ----')
    print('CONTENT_LENGTH:', content_length)
    print('wsgi.input:', environ['wsgi.input'].read(content_length))
    print('---- End ----')
    return [b'Foo\n']

if __name__ == '__main__':
    from wsgiref import simple_server
    server = simple_server.make_server('0.0.0.0', 8080, application)
    server.serve_forever()

curl命令现在获得有效的HTTP响应。

lone@debian:~$ curl --data "a=1&b=2" http://localhost:8080/
Foo
lone@debian:~$

application()函数也完成了它的执行。

lone@debian:~$ python3 foo.py
---- Begin ----
CONTENT_LENGTH: 7
wsgi.input: b'a=1&b=2'
---- End ----
127.0.0.1 - - [06/Apr/2014 17:53:21] "POST / HTTP/1.1" 200 4

问题

为什么在没有任何参数的情况下调用environ['wsgi.input'].read()read调用阻塞?

PEP-3333文件似乎暗示它应该有效。这是相关文字。

  

服务器不需要读取客户端指定的内容   Content-Length应该模拟文件结束条件   应用程序试图阅读过这一点。应用程序   不应尝试读取的数据超过CONTENT_LENGTH变量指定的数据。

     

服务器应该允许在没有参数的情况下调用read(),   并返回客户端输​​入流的其余部分。

我知道应用程序不应该尝试读取比CONTENT_LENGTH变量指定的数据更多的数据。我不服从这个指令。但是服务器应该允许在没有参数的情况下调用read()并返回整个输入流。为什么不这样做?

1 个答案:

答案 0 :(得分:3)

因为它只实现了PEP 333而不是PEP 3333。

PEP 333没有关于通过返回空字符串来模拟流结束的条件。

在PEP 333中,如果您尝试读取超过CONTENT_LENGTH,如果WSGI服务器支持HTTP 1.1并且正在使用请求管道衬里(保持活动状态),则会出现问题。

我建议你阅读PEP 333并将语言与PEP 3333进行比较。

同时阅读:

我描述了整个问题,因此在为Python 3更新PEP时对PEP的更改做出了贡献。