Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Webフレームワークを作ってる話 #osakapy

1,480 views

Published on

WSGIの話と自作WAFのKobinの話

Published in: Technology
  • Be the first to comment

Webフレームワークを作ってる話 #osakapy

  1. 1. WAFをつくってる話 大阪Pythonユーザの集まり 2016/04 MASASHI SHIBATA ! c_bata_
  2. 2. @c_bata_ django / flask / pandas 明石高専
  3. 3. 話すこと 1. WSGIの話とか 2. WAFに欲しい機能を考える 3. Kobinの紹介 4. Kobinにおける取り組み
  4. 4. WSGI Web Server Gateway Interface
  5. 5. WSGI?? • Pythonで作るWebアプリケーションの実装方 法の標準化仕様 • 実装を切り離して、WebサーバとWAFの組み 合わせを柔軟に https://www.python.org/dev/peps/pep-3333/ https://www.python.org/dev/peps/pep-333/
  6. 6. WSGI v1.0.1 (PEP3333) • 2つの引数を持った呼び出し可能なオブジェクト • 第2引数として渡されたオブジェクトにHTTPス テータスコードと (header_name, header_value) タプルのリストを渡す • 返り値はバイト文字列を yield する iterableなオ ブジェクト https://www.python.org/dev/peps/pep-3333/
  7. 7. WSGI v1.0.1 (PEP3333) def app(env, start_response): start_response('200 OK', [('Content-Type', 'text/plain')]) return [b"Hello World"] • 2つの引数を持った呼び出し可能なオブジェクト https://www.python.org/dev/peps/pep-3333/
  8. 8. WSGI v1.0.1 (PEP3333) def app(env, start_response): start_response('200 OK', [('Content-Type', 'text/plain')]) return [b"Hello World"] • 第2引数として渡されたオブジェクトの引数は
 HTTPステータスコードと
 (header_name, header_value) タプルのリスト https://www.python.org/dev/peps/pep-3333/
  9. 9. WSGI v1.0.1 (PEP3333) def app(env, start_response): start_response('200 OK', [('Content-Type', 'text/plain')]) return [b"Hello World"] • バイト文字列を yield する iterable を返さなければ ならない • 例えば、バイト文字列のリストを返すようにする https://www.python.org/dev/peps/pep-3333/
  10. 10. Hello World with gunicorn $ gunicorn -w 1 main:app [2016-04-15 10:17:00 +0900] [1873] [INFO] Starting gunicorn 19.4.5 [2016-04-15 10:17:00 +0900] [1873] [INFO] Listening at: http://127.0.0.1:8000 (1873) [2016-04-15 10:17:00 +0900] [1873] [INFO] Using worker: sync [2016-04-15 10:17:00 +0900] [1878] [INFO] Booting worker with pid: 1878 ^C[2016-04-15 10:17:08 +0900] [1873] [INFO] Handling signal: int [2016-04-15 10:17:08 +0900] [1878] [INFO] Worker exiting (pid: 1878) [2016-04-15 10:17:08 +0900] [1873] [INFO] Shutting down: Master def app(env, start_response): start_response('200 OK', [('Content-Type', 'text/plain')]) return [b"Hello World"]
  11. 11. Hello World with wsgiref $ python main.py 127.0.0.1 - - [15/Apr/2016 10:24:21] "GET / HTTP/1.1" 200 11 127.0.0.1 - - [15/Apr/2016 10:24:21] "GET /favicon.ico HTTP/1.1" 200 11 def app(env, start_response): start_response('200 OK', [('Content-Type', 'text/plain')]) return [b"Hello World"]
 
 if __name__ == '__main__': from wsgiref.simple_server import make_server httpd = make_server('', 8080, app) httpd.serve_forever()
  12. 12. WAFで欲しい機能を考える
  13. 13. 最低限欲しい機能 • ルーティング • どこにアクセスしても Hello World • HTMLテンプレート • 今はplain text返してるだけ • Jinja2のTemplate Loaderを用意
  14. 14. 最低限欲しい機能 • 静的ファイルをいい感じに返す機能 • 本番だとNginxとか使うけど、開発中は... • リクエスト・レスポンスオブジェクト • リクエスト情報はenvが渡されてるけど、
 ただのdictなのでうまくパースしてほしい • ステータスとかヘッダ情報をコントロール
  15. 15. a small and statically-typed web framework kobin https://github.com/c-bata/kobin
  16. 16. a small and statically-typed web framework kobin https://github.com/c-bata/kobin
  17. 17. Hello World from kobin import Kobin app = Kobin() @app.route('^/(?P<name>w*)$') def hello(name: str): return "Hello {}!!".format(name) if __name__ == '__main__': app.run() • 日本語: https://kobin.readthedocs.org/ja/latest/ • English: https://kobin.readthedocs.org/en/latest/
  18. 18. Hello World with Jinja2 import os from kobin import Kobin, template app = Kobin() @app.route('^/$') def index(): return template('index') • https://github.com/c-bata/kobin-example • https://kobin.herokuapp.com/
  19. 19. 特徴 • Type Hintsの活用 • Bottleのコードを読んでる時に結構混乱 • mypy 使いたい • ルーティングへの活用
  20. 20. Routing in Django from django.conf.urls import url urlpatterns = [ url(r'^blog/page(?P<num>[0-9]+)/$', page), ] def page(request, num="1"): # Output the appropriate page of blog entries ... https://docs.djangoproject.com/en/1.9/topics/http/urls/ • 引数が全て文字列
  21. 21. Routing in Bottle from bottle import route @route('/object/<id:int>') def callback(id): assert isinstance(id, int) http://bottlepy.org/docs/dev/tutorial.html#request-routing • 独自DSL • 型が分かるため、view関数には型変換したオブジェ クトを渡すことができる
  22. 22. ルーティングに対する考察 • 正規表現ベース (Django等) • 自由度は高い • 型情報を取得出来ない • 独自DSL (Bottle, Flask等) • 自由度は低い • 型情報を自由に付けれる
  23. 23. Routing in Kobin from kobin import Kobin app = Kobin() @app.route('^/years/(?P<year>d{4})$') def casted_year( year: int ): return 'A "year" argument is integer? : {}’ .format(isinstance(year, int)) https://github.com/c-bata/kobin/blob/master/example/hello_world.py • 正規表現により自由度が高い • Type Hintsの恩恵(IDE, mypy)をそのまま受けれる
  24. 24. Ecosystem Threats to Python • Pythonのエコシステムはその巨大さゆえに、バー ジョンアップについていきづらい • コミュニティとしてもPython3に移行していきたい • Type Hintsを移行のきっかけに PyCon APAC/Taiwan 2015: Keynote
  25. 25. References • Documentations • https://kobin.readthedocs.org/ja/latest/ • https://kobin.readthedocs.org/en/latest/ • Kobin Example • https://github.com/c-bata/kobin-example • https://kobin.herokuapp.com/
  26. 26. おまけ PEP333とPEP3333
  27. 27. PEP333 と PEP3333 $ python2.7 >>> b'hoge' + u'日本語' u'hogeu65e5u672cu8a9e' $ python3.5 >>> b'hoge' + u'日本語' Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: can't concat bytes to str
  28. 28. PEP333 と PEP3333 • PEP333 (WSGI v1.0) • Python2ではbytesとstrを結合出来たり… • Python3で文字列の扱いが大きく変わった • PEP3333 (WSGI v1.0.1) • 後方互換は保ったまま、文字列の扱いを整備して 長年たまってたデファクトの修正案も取り込み
  29. 29. Thanks!

×