2012-04-19 5 views
4

私はPyramidでWebアプリケーションを作成しており、POSTリクエストの最大長を制限したいので、膨大な量のデータを投稿したり、サーバ。しかし、私は(Pyramid、WebOb、Paster)を考えることができ、どこでもこれを達成するためのオプションを見つけることができませんでした。私は、PasterにHTTPヘッダーの数、各ヘッダーの長さなどの制限があるのを見ましたが、要求本体のサイズについては何も見ませんでした。PyramidでPOSTリクエストを最大サイズに制限

サーバーはJSON-RPC専用のPOSTリクエストを受け付けますので、リクエスト本体のサイズを大きくする必要はありません。これを達成する方法はありますか?

これは残りの部分から明白ではない場合があります。長さをチェックして4xxエラーコードを返す前に、リクエストボディ全体を受け入れてメモリにロードする必要があるソリューションは、私がしようとしていることの目的を破ります私が探しているものではありません。

+0

現在、Webサーバーは「paster serve」です。しかし、その文書では何も見つかりませんでした。私はまた、(WSGIがストリーミングモードで使用される場合)Pyramid WSGIハンドリングの腸の中でこれに方法があるかもしれないと考えましたが、私はそれについてはあまりよく分かりません。しかし、私は、このために何か(そしてそれのデフォルト値)がパスタ(ウェブサーバ)にあるべきだと考えていたので、私はそれを見つけることができなかったのに驚いたのです。 –

+0

paster docsには、この種の設定オプションはありません。彼らがフォーラムやメーリングリストを持っているなら、そこに尋ねたいかもしれません。それ以外の場合は、ソースにダイビングする必要があります。 – agf

答えて

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() 
+1

ありがとう、この素晴らしい!私は、ミドルウェアなどを書くためにWSGIについて十分に学ぶことを意味してきました。これは読みやすい、すばらしい例です。しかし、2つの簡単な質問。まず、WSGI、WebObなどに何かがありますか?コンテンツ長ヘッダーが常に設定されていることを確認しますか? (私の理解では、HTTPクライアントは必ずしもこれを設定するとは限りません。)次に、このWSGIミドルウェアが呼び出されるまでに、要求本体全体がメモリ内に読み込まれましたか? –

+2

ミドルウェアを作成して、必要に応じてヘッダーの有無を確認することができます。 webobは、送信されなかった場合、おそらくNoneを返すと思います。あなたの2番目の質問で、私はそれがメモリに読み込まれるかどうかはわかりません。私はそれらの低レベルの詳細は、Apacheやnginxのようなフロントエンドサーバーのためだと思う(これは私がLoicの答えに投票した理由です:))。 wsgiの仕事は、WebサーバーとPythonコードの間の通信を処理しています.Webobsの仕事は、あなたがHTTP要求と応答を作成して支援することです。 –

2

あなたの質問に直接答えはありません。あなたが次のWSGIレイヤーに渡すことができる構成設定の下にある場合は、私が知る限り、要求をロードするwsgiアプリケーションを作成できます。それ以上になると、読み込みを停止してエラーを直接返すことができます。

しかし、正直言って、私は実際にはピラミッドでそれを行うためのポイントが表示されません。たとえば、nginxやapacheなどでリバースプロキシの背後でピラミッドを実行すると、フロントエンドサーバでリクエストのサイズを制限できます。

プロキシを使わずに直接WaitressやPasterでピラミッドを実行する場合を除き、フロントエンドサーバーのボディサイズはPythonよりも効率的でなければなりません。

編集

私はいくつかの研究をした、それは完全な答えはありませんが、ここで私が推測使用することができるものです。私が知る限り、environ ['wsgi_input']を読まなければなりません。これは、例えばnginxやapacheからデータのチャンクを受け取るオブジェクトのようなファイルです。

あなたが本当にしなければならないことは、最大音量に達するまでそのファイルを読み込むことです。到達した場合は、リクエストを続行しない場合はエラーを発生します。あなたはさまざまな方法でそれを行うことができます。このanswer

+0

あなたはそうです。展開のために、ロードバランシングプロキシサーバーでこれを処理します。しかし、私はPasterでこのような機能を見つけないように、少しは驚いた。ありがとう。 –

関連する問題