Last active
August 29, 2015 13:56
-
-
Save sprin/8889173 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from flask import Flask | |
app = Flask(__name__) | |
import datetime | |
from threading import local | |
threadlocal = local() | |
@app.route('/') | |
def abuse_threadlocals(): | |
# Get the threadlocal and return it if it is defined, | |
# otherwise set it to current time and return that value. | |
x = getattr(threadlocal, 'x', None) | |
if not x: | |
threadlocal.x = datetime.datetime.now() | |
x = threadlocal.x | |
return 'You made this request on {}'.format(x) | |
# So what's wrong here? If the application is not using threads, but is | |
# instead running in a persistent single-threaded process, x will have the value | |
# that was set from the first request for the life of the process. If the web | |
# server is using a thread pool, each thread will retain the value from the | |
# first request it handled for the life of the thread. | |
# The solution? If you read my other gist on threadlocal abuse and the | |
# problems associated with readability and testing, and still | |
# think you have very compelling reasons to use threadlocals.... | |
# https://gist.github.com/sprin/8887860 | |
# Use a proven solution for context locals that handles access safety and | |
# cleanup, such as werkzeug.local: | |
# http://werkzeug.pocoo.org/docs/local/ | |
# https://github.com/mitsuhiko/werkzeug/blob/master/werkzeug/local.py | |
# This works not only in threads, but in the general case. A quote: | |
# | |
# The same context means the same greenlet (if you're using greenlets) | |
# in the same thread and same process. | |
# | |
# The Flask microframework provides an easy-to-use context-local object | |
# called request which uses werkzueg.local. | |
# http://flask.pocoo.org/docs/reqcontext/ | |
# | |
# However, to store your own context-local information, flask provides flask.g. | |
import flask | |
from flask import request, render_template_string | |
@app.route('/safer') | |
def safer_threadlocals(): | |
x = getattr(flask.g, 'x', None) | |
if not x: | |
flask.g.x = datetime.datetime.now() | |
x = flask.g.x | |
ctx = { | |
'x': x, | |
'request': request.__dict__, | |
} | |
return render_template_string(SAFER_TMPL, **ctx) | |
SAFER_TMPL = ( | |
""" | |
You made this request on {{x}}.<br><br> | |
Here is your request object: | |
<dl> | |
{% for key, value in request.items() %} | |
<dt>{{ key|e }}</dt> | |
{% if value.items %} | |
<dd> | |
<dl> | |
{% for k, v in value.items() %} | |
<dt>{{ k|e }}</dt> | |
<dd>{{ v|e }}</dd> | |
{% endfor %} | |
</dl> | |
</dd> | |
{% else %} | |
<dd>{{ value|e }}</dd> | |
{% endif %} | |
{% endfor %} | |
</dl> | |
""" | |
) | |
if __name__ == '__main__': | |
app.run(debug=True) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment