乘客+烧瓶和 URL 逃脱
Passenger+flask and URL escaping
我正在用 Flask 编写一个应用程序,将通过 Passenger 部署在 Dreamhost 上。我有一个设置,这样我可以 运行 在本地使用 ./run.py
(env
是我的 virtualenv 目录):
#!env/bin/python
from my_website import app
app.run(debug=True)
并部署到 Dreamhost 使用以下 passenger_wsgi.py
:
#!env/bin/python
import sys, os
INTERP = os.path.join(os.getcwd(), 'env', 'bin', 'python')
if sys.executable != INTERP:
os.execl(INTERP, INTERP, *sys.argv)
sys.path.append(os.getcwd())
from my_website import app as application
大多数东西都运行良好。 但是,我运行遇到了一个问题,Passenger 没有像 WSGI 应该做的那样解码 URL 的 PATH_INFO
。例如,我设置了一条路线(在 my_website/__init__.py
:
app.add_url_rule('/example/<key>', 'examplepage', examplepage.show_page)
对于具有简单键的页面,这在本地 Passenger 和 运行ning 上都可以正常工作。但是,如果我去,例如,example.com/example/test%20key
,在我的本地开发系统上,examplepage.show_page
会按预期被调用 key='test key'
,但是通过 Passenger,它会被调用 key='test%20key'
.
看起来 Flask 的内置 HTTP 服务器正在 URL 解码 PATH_INFO
,甚至在它到达 Flask 的 URL 解析器之前,因此,%2F
字符也会过早解码;因为 Flask 期望 URL 在那个时候已经被 URL 解码,所以它不是 URL 解码单个解析出的路径组件。但是,Passenger+WSGI 保留 PATH_INFO
,因此 URL 编码的字符保持 URL 编码(这似乎是 Passenger 的 WSGI 实现中的错误)。
那么,让 Passenger 和 ./run.py
之间的行为保持一致的最简单方法是什么?
这似乎运行良好(在 passenger_wsgi.py
中),尽管可能存在一些问题:
from my_website import app
# hackish way to apply WSGI's url decoding in Passenger
import urllib2
def application(environ, start_response):
environ["PATH_INFO"] = urllib2.unquote(environ["PATH_INFO"])
return app(environ, start_response)
一个值得注意的问题是,这意味着 %2f
不再被正确处理,而它本可以通过 Passenger;然而,正确处理它需要对 Flask 进行大量更改,这将与绝大多数 WSGI 堆栈不兼容。
我正在用 Flask 编写一个应用程序,将通过 Passenger 部署在 Dreamhost 上。我有一个设置,这样我可以 运行 在本地使用 ./run.py
(env
是我的 virtualenv 目录):
#!env/bin/python
from my_website import app
app.run(debug=True)
并部署到 Dreamhost 使用以下 passenger_wsgi.py
:
#!env/bin/python
import sys, os
INTERP = os.path.join(os.getcwd(), 'env', 'bin', 'python')
if sys.executable != INTERP:
os.execl(INTERP, INTERP, *sys.argv)
sys.path.append(os.getcwd())
from my_website import app as application
大多数东西都运行良好。 但是,我运行遇到了一个问题,Passenger 没有像 WSGI 应该做的那样解码 URL 的 PATH_INFO
。例如,我设置了一条路线(在 my_website/__init__.py
:
app.add_url_rule('/example/<key>', 'examplepage', examplepage.show_page)
对于具有简单键的页面,这在本地 Passenger 和 运行ning 上都可以正常工作。但是,如果我去,例如,example.com/example/test%20key
,在我的本地开发系统上,examplepage.show_page
会按预期被调用 key='test key'
,但是通过 Passenger,它会被调用 key='test%20key'
.
看起来 Flask 的内置 HTTP 服务器正在 URL 解码 PATH_INFO
,甚至在它到达 Flask 的 URL 解析器之前,因此,%2F
字符也会过早解码;因为 Flask 期望 URL 在那个时候已经被 URL 解码,所以它不是 URL 解码单个解析出的路径组件。但是,Passenger+WSGI 保留 PATH_INFO
,因此 URL 编码的字符保持 URL 编码(这似乎是 Passenger 的 WSGI 实现中的错误)。
那么,让 Passenger 和 ./run.py
之间的行为保持一致的最简单方法是什么?
这似乎运行良好(在 passenger_wsgi.py
中),尽管可能存在一些问题:
from my_website import app
# hackish way to apply WSGI's url decoding in Passenger
import urllib2
def application(environ, start_response):
environ["PATH_INFO"] = urllib2.unquote(environ["PATH_INFO"])
return app(environ, start_response)
一个值得注意的问题是,这意味着 %2f
不再被正确处理,而它本可以通过 Passenger;然而,正确处理它需要对 Flask 进行大量更改,这将与绝大多数 WSGI 堆栈不兼容。