I am using cherrypy 3.6.0, nginx 1.6.2 and uWSGI 2.0.9 on amazon linux.
uwsgi.json config:
{
"uwsgi": {
"socket": ["127.0.0.1:8080"],
"master": True,
"processes": 1,
"threads": 24,
"uid": "ec2-user",
"protocol": "http",
"vacuum": True
"chdir": "/usr/local/src/myapp",
"wsgi-file": "/usr/local/src/myapp/wsgi.py",
"logto": "/var/log/uwsgi.log"
}
}
I try enabling sessions:
cherrypy.config.update({
'server.socket_host': '0.0.0.0',
'engine.autoreload.on': False,
'server.socket_port': 8080,
'request.dispatch': cherrypy.dispatch.MethodDispatcher(),
'tools.sessions.on' : True,
'tools.sessions.storage_type': "file",
'tools.sessions.storage_path': "/home/ec2-user/.cherrypy_sessions",
'tools.sessions.timeout': 60
})
to use them here:
import cherrypy
import random
import string
import json
import urllib.parse
class IdentityApi(object):
@cherrypy.expose
def gen_crosssite(self):
crsf = ''.join(random.choice(string.ascii_uppercase + string.digits) for x in range(32))
cherrypy.session['my_state'] = crsf;
return json.dumps({'crsf': crsf})
I get the following exception:
[25/Feb/2015:15:51:36] HTTP Traceback (most recent call last):
File "/usr/local/lib/python3.4/site-packages/cherrypy/_cprequest.py", line 670, in respond
response.body = self.handler()
File "/usr/local/lib/python3.4/site-packages/cherrypy/lib/encoding.py", line 217, in __call__
self.body = self.oldhandler(*args, **kwargs)
File "/usr/local/lib/python3.4/site-packages/cherrypy/_cpdispatch.py", line 61, in __call__
return self.callable(*self.args, **self.kwargs)
File "./api/IdentityApi.py", line 25, in gen_crsf
cherrypy.session['my_state'] = crsf;
AttributeError: 'module' object has no attribute 'session'
update: Running it from the commandline 'python3 wsgi.py' and WITHOUT uWSGI works.
Had to comment out:
cherrypy.server.unsubscribe()
cherrypy.engine.start()
updated wsgi.py:
if __name__ == '__main__':
cherrypy.log('jobtagr log file = %s', cherrypy.log.access_file)
setup_logging()
cherrypy.config.update({
'server.socket_host': '0.0.0.0',
'engine.autoreload.on': False,
'server.socket_port': 8080,
'request.dispatch': cherrypy.dispatch.MethodDispatcher(),
'tools.sessions.on' : True,
'tools.sessions.storage_type': "file",
'tools.sessions.storage_path': "/home/ec2-user/.cherrypy_sessions",
'tools.sessions.timeout': 60
})
# cherrypy.server.unsubscribe()
# cherrypy.engine.start()
cherrypy.quickstart(application)
How do I get sessions to work under uWSGI?
Observations:
cherrypy.session
attribute doesn't exist unless sessions.init
is called by the session tool,gen_crosssite
.I've modelled your case and see the problem now. It's documented behaviour but it is a little subtle anyway. It happens when you switch from cherrypy.quickstart
which is more demo thing, to managing real setup with cherrypy.tree.mount
without paying attention to what happens with configuration. Here's cherrypy.quickstart
, it's small:
def quickstart(root=None, script_name="", config=None):
if config:
_global_conf_alias.update(config)
tree.mount(root, script_name, config)
engine.signals.subscribe()
engine.start()
engine.block()
As you see, it sets both, server (global) config and application config in tree.mount
. Here's the warning from Basics documentation section about global config:
cherrypy.config.update()
is not meant to be used to configure the application. It is a common mistake. It is used to configure the server and engine.
And here's Combined Configuration Files section:
If you are only deploying a single application, you can make a single config file that contains both global and app entries. Just stick the global entries into a config section named [global] (or top level key global), and pass the same file to both
config.update
andtree.mount
. If you’re callingcherrypy.quickstart(app root, script name, config)
, it will pass the config to both places for you. But as soon as you decide to add another application to the same site, you need to separate the two config files/dicts.
Here goes your case modelled with two applications:
#!/usr/bin/env python3
import random
import string
import cherrypy
class Api:
def __init__(self):
self.string = String()
# ...
class String:
exposed = True
def GET(self):
return cherrypy.session.get('mystring', '')
def POST(self, length=8):
result = ''.join(random.sample(string.hexdigits, int(length)))
cherrypy.session['mystring'] = result
return result
def PUT(self, new):
cherrypy.session['mystring'] = new
def DELETE(self):
cherrypy.session.pop('mystring', None)
class Token:
@cherrypy.expose
def csrf(self):
crsf = ''.join(random.choice(string.ascii_uppercase + string.digits) for x in range(32))
cherrypy.session['csrf'] = crsf
return {'crsf': crsf}
if __name__ == '__main__':
# global server config
cherrypy.config.update({
'server.socket_host' : '0.0.0.0',
'server.socket_port' : 8080,
})
# applicaton config is provided
cherrypy.tree.mount(Api(), '/api', {
'/' : {
'tools.sessions.on' : True,
'request.dispatch' : cherrypy.dispatch.MethodDispatcher(),
},
'/string' : {
'tools.response_headers.on' : True,
'tools.response_headers.headers' : [('Content-Type', 'text/plain')]
}
})
# applicaton config is provided
cherrypy.tree.mount(Token(), '/token', {'/' : {
'tools.sessions.on' : True,
'tools.json_out.on' : True,
}})
cherrypy.engine.signals.subscribe()
cherrypy.engine.start()
cherrypy.engine.block()