Python 如何在烧瓶中获得裸露的wsgi流?

Python 如何在烧瓶中获得裸露的wsgi流?,python,flask,wsgi,werkzeug,Python,Flask,Wsgi,Werkzeug,使用Flask,我想获得裸露的wsgi.input引用。看看代码,似乎有不止一种方法可以做到这一点,这两种方法都出现在: werkzeug.wsgi.get_input_stream(environ, safe_fallback=True): ... if environ.get('wsgi.input_terminated'): return stream ... if content_length is None: return

使用Flask,我想获得裸露的wsgi.input引用。看看代码,似乎有不止一种方法可以做到这一点,这两种方法都出现在:

werkzeug.wsgi.get_input_stream(environ, safe_fallback=True):
    ...
    if environ.get('wsgi.input_terminated'):
        return stream
    ...
    if content_length is None:
        return safe_fallback and _empty_stream or stream
    ...
令人恼火的是,我不知道如何真正让这两种情况发生,而且在文档中几乎没有提及

wsgi.input_terminated:我知道如果我使用Apache这样的合适服务器,我可以设置wsgi环境,但是如果Werkzeug在Werkzeug.service.make_环境中硬编码它的wsgi环境,我该如何在Flask dev服务器下设置呢

安全退路:根本无法理解这一点。。。如果这个参数只是自己调用而从未传递,那么它在这里做什么?我该如何激活它


这里很可能缺少一些简单的东西…

我知道这是一个非常老的线程,但我找到了一种处理分块编码请求的方法,我需要流而不是数据,在自定义python应用程序gunicorn+flask中,所以我创建了子类,而不是使用flask.flask作为应用程序:

class FlaskApp(flask.Flask):
    def request_context(self, environ):
        # it's the only way I've found to handle chunked encoding request (otherwise flask.request.stream is empty)
        environ['wsgi.input_terminated'] = 1
        return super(FlaskApp, self).request_context(environ)

有人知道如何更好地实现这一点吗?

我知道这是一个非常古老的线程,但我找到了一种处理分块编码请求的方法,我需要的是流而不是数据,在自定义python应用程序gunicorn+flask中,所以我创建了子类,而不是使用flask.flask作为应用程序:

class FlaskApp(flask.Flask):
    def request_context(self, environ):
        # it's the only way I've found to handle chunked encoding request (otherwise flask.request.stream is empty)
        environ['wsgi.input_terminated'] = 1
        return super(FlaskApp, self).request_context(environ)

任何人都知道如何更好地做到这一点吗?

解决方案@ddzialak posted可以工作,但使用request.stream.readchunk\u size或request.get\u数据读取流会给出完整的流内容,包括标题。以下是我用来获取工具及其使用信息的方法:

str_data    = request.get_data() # stream data
pattern = re.compile(r'\r\n\r\n(.+?)\n\r\n', flags=re.DOTALL) # content regex
file_data   = pattern.findall( str_data.decode('UTF-8') )[0] # what my tools use

@ddzialak发布的解决方案有效,但使用request.stream.readchunk\u size或request.get\u数据读取流会给出完整流的内容,包括标题。以下是我用来获取工具及其使用信息的方法:

str_data    = request.get_data() # stream data
pattern = re.compile(r'\r\n\r\n(.+?)\n\r\n', flags=re.DOTALL) # content regex
file_data   = pattern.findall( str_data.decode('UTF-8') )[0] # what my tools use

下面是@javabrett在对@ddzialek答案的评论中建议的函数的一个稍微复杂的版本。这一个在设置标志I'm not positive这是必要的之前检查分块输入,但是设置一个可能不需要的标志似乎不是一个好主意

@app.before_request
def handle_chunking():
    """
    Sets the "wsgi.input_terminated" environment flag, thus enabling
    Werkzeug to pass chunked requests as streams; this makes the API
    compliant with the HTTP/1.1 standard.  The gunicorn server should set
    the flag, but this feature has not been implemented.
    """

    transfer_encoding = request.headers.get("Transfer-Encoding", None)
    if transfer_encoding == "chunked":
        request.environ["wsgi.input_terminated"] = True
实际传递的传输编码值可能是Unicode而不是ASCII,因此u“chunked”更准确,但对于ASCII范围内的字符,不同之处在于Python将以任何方式匹配字符串,Python 3不需要u


编辑:需要注意的是,一些WSGI服务器不再需要此修复。具体来说,gunicorn从版本20.0开始就尊重wsgi.input_terminated标志,不过应该注意的是,20.0是第一个不支持Python 2.x的版本,因此如果您一直使用Python 2.x,您仍然需要此修复。

这里是@javabrett在对@ddzialek答案的评论中建议的函数的一个稍微复杂的版本。这一个在设置标志I'm not positive这是必要的之前检查分块输入,但是设置一个可能不需要的标志似乎不是一个好主意

@app.before_request
def handle_chunking():
    """
    Sets the "wsgi.input_terminated" environment flag, thus enabling
    Werkzeug to pass chunked requests as streams; this makes the API
    compliant with the HTTP/1.1 standard.  The gunicorn server should set
    the flag, but this feature has not been implemented.
    """

    transfer_encoding = request.headers.get("Transfer-Encoding", None)
    if transfer_encoding == "chunked":
        request.environ["wsgi.input_terminated"] = True
实际传递的传输编码值可能是Unicode而不是ASCII,因此u“chunked”更准确,但对于ASCII范围内的字符,不同之处在于Python将以任何方式匹配字符串,Python 3不需要u


编辑:需要注意的是,一些WSGI服务器不再需要此修复。具体地说,gunicorn从版本20.0开始就尊重wsgi.input_terminated标志,不过应该注意的是,20.0是第一个不支持Python 2.x的版本,因此如果您一直在使用Python 2.x,您仍然需要此修复。

您到底想做什么?Flask中的'wsgi.input_terminated'值不是官方wsgi规范的一部分,您不想依赖它。真正的输入流是'wsgi.input'。只是尝试获取输入流-也许我不清楚,但是wsgi.input_终止只是一个bool,它有效地确定Flask中的助手返回什么;流或它自己的包装流包装器似乎在所有情况下都会耗尽流。我可以将这个问题重新表述为在Flask清空输入流之前如何获取输入流。“wsgi.input_terminated”是一个Flask web服务器扩展,以便Flask知道它正在处理一个能够处理分块请求内容的wsgi服务器,这在技术上是wsgi规范不支持的。它会导致它忽略内容长度。无论如何,在request.environ中看不到wsgi.input吗?仍然不清楚您试图解决的问题是什么。你在问如何用你的解决方案解决问题。Flask通常处理请求内容的方式有什么问题,需要下拉到wsgi.input.OK,所以我希望能够将数据从wsgi输入管道传输到另一个二进制文件。这不是很有趣,但对于某些备份来说,它是一个不同的协议
软件换句话说就是一种流代理。为了保持它的可伸缩性,我希望能够通过它超过100KB左右的时间。不幸的是,无论是流式处理还是分块处理似乎都无法将数据保存在内存中,或者至少保存在临时文件中。所以,因为我只需要对数据执行一项任务,所以我想我可以编写自己的流包装器,一次读取x字节,直到出现EOF。Flask似乎有一些设备你到底想做什么?Flask中的'wsgi.input_terminated'值不是官方wsgi规范的一部分,您不想依赖它。真正的输入流是'wsgi.input'。只是尝试获取输入流-也许我不清楚,但是wsgi.input_终止只是一个bool,它有效地确定Flask中的助手返回什么;流或它自己的包装流包装器似乎在所有情况下都会耗尽流。我可以将这个问题重新表述为在Flask清空输入流之前如何获取输入流。“wsgi.input_terminated”是一个Flask web服务器扩展,以便Flask知道它正在处理一个能够处理分块请求内容的wsgi服务器,这在技术上是wsgi规范不支持的。它会导致它忽略内容长度。无论如何,在request.environ中看不到wsgi.input吗?仍然不清楚您试图解决的问题是什么。你在问如何用你的解决方案解决问题。Flask通常处理请求内容的方式有什么问题,需要下拉到wsgi.input.OK,因此我希望能够将数据从wsgi输入管道传输到另一个二进制文件。这样做并不十分有趣,但对于某些备份软件来说,这是一种不同的协议。换句话说就是一种流代理。为了保持它的可伸缩性,我希望能够通过它超过100KB左右的时间。不幸的是,无论是流式处理还是分块处理似乎都无法将数据保存在内存中,或者至少保存在临时文件中。所以,因为我只需要对数据执行一项任务,所以我想我可以编写自己的流包装器,一次读取x字节,直到出现EOF。Flask似乎有一些设备。可以通过添加@app.before_request def before_request:request.environ['wsgi.input_terminated']=1来避免子类。可以通过添加@app.before_request def before_request:request.environ['wsgi.input_terminated']=1传输编码标题设置为chunked并不意味着您可以自己设置wsgi.input\u。能否做到这一点取决于WSGI服务器的实现方式。主要WSGI服务器的最新版本现在支持设置WSGI.input_,因此您不需要在适当的时候自行终止。我知道服务器应该设置它,但事实是gunicorn不这样做,并且在适当的时候自己设置,确实解决了这个问题上面的代码来自一个Flask服务,该服务目前正在运行,运行良好。奇怪的是,我记得不久前的一次twitter讨论,gunicorn的作者说正在添加标志设置。除非他们决定不发布新版本,或者从那以后就没有发布新版本。这里有一个悬而未决的问题:。他们原本打算在2017年12月中旬的一次发布中解决这个问题,但这次推迟了:。我相信上面第一个链接中提到的症结是担心在没有请求大小限制的情况下添加流支持会造成DoS攻击的漏洞。在我的情况下,这不是一个问题,我们计划用NGINX反向代理API,NGINX可以设置大小限制。我看不出DoS攻击与此特定更改有关。他们提到的DoS攻击是Sloworis,这已经是一个问题。只要gunicorn不缓冲分块请求内容(我不相信它会这样做),wsgi.input_就不会有问题。在我看来,只是有一些保留,所以推迟了它,没有回去重新访问它。传输编码标题被设置为chunked并不意味着你可以自己设置wsgi.input\u。能否做到这一点取决于WSGI服务器的实现方式。主要WSGI服务器的最新版本现在支持设置WSGI.input_,因此您不需要在适当的时候自行终止。我知道服务器应该设置它,但事实是gunicorn不这样做,并且在适当的时候自己设置,确实解决了这个问题上面的代码来自一个Flask服务,该服务目前正在运行,运行良好。奇怪的是,我记得不久前的一次twitter讨论,gunicorn的作者说正在添加标志设置。除非他们决定不发布新版本,或者从那以后就没有发布新版本。这里有一个悬而未决的问题:。他们原本打算在2017年12月中旬的一次发布中解决这个问题,但这次推迟了:。我相信上面第一个链接中提到的症结是担心添加流支持
尽管请求大小限制会造成DoS攻击的漏洞。在我的情况下,这不是一个问题,我们计划用NGINX反向代理API,NGINX可以设置大小限制。我看不出DoS攻击与此特定更改有关。他们提到的DoS攻击是Sloworis,这已经是一个问题。只要gunicorn不缓冲分块请求内容(我不相信它会这样做),wsgi.input_就不会有问题。在我看来,只是有一些保留,所以推迟了它,并没有回去重新访问它。