我正在使用Pyramid编写一个Web应用程序,并希望限制POST请求的最大长度,以便人们无法发布大量数据并耗尽服务器上的所有内存。然而,我几乎到处都能看到(金字塔,WebOb,Paster)并且无法找到完成此任务的任何选项。我已经看到Paster对HTTP头的数量,每个头的长度等有限制,但我没有看到请求体的大小。
服务器将仅接受JSON-RPC的POST请求,因此我不需要允许庞大的请求体大小。金字塔堆栈中有没有办法实现这个目标?
为了防止其他问题不明显,在检查长度并返回4xx错误代码之前必须接受并将整个请求主体加载到内存中的解决方案违背了我正在尝试做的目的,并不是我想要的。
答案 0 :(得分:2)
并非真正直接回答您的问题。据我所知,你可以创建一个wsgi应用程序,如果正文低于配置设置,你可以加载请求,你可以将它传递给下一个WSGI层。如果它超过你可以停止阅读并直接返回错误。
但说实话,我真的没有看到在金字塔中这样做的意义。例如,如果您使用nginx或apache或其他东西在反向代理后面运行金字塔...您始终可以使用前端服务器限制请求的大小。
除非您想在没有任何代理的情况下直接使用Waitress或Paster运行金字塔,否则您应该在前端服务器中处理应该比python更高效的主体大小。
修改强>
我做了一些研究,但这不是一个完整的答案,但我猜这里可以使用。据我所知,你必须阅读environ ['wsgi_input']。这是一个类似于对象的文件,例如从nginx或apache接收大量数据。
您真正需要做的是读取该文件,直到达到最大长度。如果达到,则在没有继续请求的情况下引发错误。
您可能需要查看此answer
答案 1 :(得分:1)
您可以通过多种方式进行此操作,这里有几个例子。一个使用基于webob的wsgi中间件(当你在其他东西中安装金字塔时安装)。和一个使用金字塔event mechanism
"""
restricting execution based on request body size
"""
from pyramid.config import Configurator
from pyramid.view import view_config
from pyramid.events import NewRequest, subscriber
from webob import Response, Request
from webob.exc import HTTPBadRequest
import unittest
def restrict_body_middleware(app, max_size=0):
"""
this is straight wsgi middleware and in this case only depends on
webob. this can be used with any wsgi compliant web
framework(which is pretty much all of them)
"""
def m(environ, start_response):
r = Request(environ)
if r.content_length <= max_size:
return r.get_response(app)(environ, start_response)
else:
err_body = """
request content_length(%s) exceeds
the configured maximum content_length allowed(%s)
""" % (r.content_length, max_size)
res = HTTPBadRequest(err_body)
return res(environ, start_response)
return m
def new_request_restrict(event):
"""
pyramid event handler called whenever there is a new request
recieved
http://docs.pylonsproject.org/projects/pyramid/en/1.2-branch/narr/events.html
"""
request = event.request
if request.content_length >= 0:
raise HTTPBadRequest("too big")
@view_config()
def index(request):
return Response("HI THERE")
def make_application():
"""
make appplication with one view
"""
config = Configurator()
config.scan()
return config.make_wsgi_app()
def make_application_with_event():
"""
make application with one view and one event subsriber subscribed
to NewRequest
"""
config = Configurator()
config.add_subscriber(new_request_restrict, NewRequest)
return config.make_wsgi_app()
def make_application_with_middleware():
"""
make application with one view wrapped in wsgi middleware
"""
return restrict_body_middleware(make_application())
class TestWSGIApplication(unittest.TestCase):
def testNoRestriction(self):
app = make_application()
request = Request.blank("/", body="i am a request with a body")
self.assert_(request.content_length > 0, "content_length should be > 0")
response = request.get_response(app)
self.assert_(response.status_int == 200, "expected status code 200 got %s" % response.status_int)
def testRestrictedByMiddleware(self):
app = make_application_with_middleware()
request = Request.blank("/", body="i am a request with a body")
self.assert_(request.content_length > 0, "content_length should be > 0")
response = request.get_response(app)
self.assert_(response.status_int == 400, "expected status code 400 got %s" % response.status_int)
def testRestrictedByEvent(self):
app = make_application_with_event()
request = Request.blank("/", body="i am a request with a body")
self.assert_(request.content_length > 0, "content_length should be > 0")
response = request.get_response(app)
self.assert_(response.status_int == 400, "expected status code 400 got %s" % response.status_int)
if __name__ == "__main__":
unittest.main()