session working with builtin server, not with apache+mod_wsgi

285 views
Skip to first unread message

Thierry

unread,
Mar 24, 2009, 10:48:40 PM3/24/09
to web.py
Hello everybody,

I've tried for the last 4 hours to have my web.py application working
with sessions in apache+mod_wsgi, but could not make it.
I've looked in docs, tutorials, searched on google, but could not find
anything...
I'm using web.py 0.3, with python 2.5 and mod_wsgi 2.3

I'm creating a simple document management interface for an association
I'm member of, and I need to use sessions for login states.
Using the web.py integrated server, I've got everything working, with
both a datastore file or db based (the db was sqlite, if it counts).

Now, I've switched to apache as the web server, and nothing works
anymore.
First, my code:

class config:
def __init__(self):
self.curPath = os.path.dirname(__file__)
self.basePath=os.path.join(self.curPath,'..')
self.storePath = os.path.join(self.basePath, 'files')
self.tplPath=os.path.join(self.basePath,'tpl/')
self.sessPath=os.path.join(self.basePath,'sess/')
self.dbPath=os.path.join(self.basePath,'sqlite')
self.dbFile='arcenciel.sqlite3'
self.finalDb=os.path.join(self.dbPath, self.dbFile)
self.debugMode=False
self.frmHome = form.Form(
form.Password('pwd', description='Veuillez donner votre nouveau
mot de passe'),
form.Password('pwd2', description='Veullez retaper votre nouveau
mot de passe'),
form.Button("submit", type="submit", description="Changer de mot
de passe"),
)
self.frmLogin = form.Form(
form.Textbox('username', description="Utilisateur"),
form.Password('pwd', description='Mot de passe'),
form.Button("submit", type="submit",
description="S'authentifier"),
)
self.frmNewFolder=form.Form(
form.Textbox('folderName', description='Donnez le nom du dossier
à créer'),
form.Button("submit", type="submit", description="Créer le
dossier"),
)
self.frmUp=form.Form(
form.File('newFile', description='Fichier à transmettre' ),
form.Button("submit", type="submit", description="Créer le
dossier"),
)

cfg=config()
web.config.debug = cfg.debugMode
app = web.application(urls, globals())
db=web.database(dbn='sqlite', db=cfg.finalDb)
sessVals={'logged': False,
'msg':'',
'user':'',
'uid':False,
}
store = web.session.DBStore(db, 'sessions')
#store = web.session.DiskStore(cfg.curPath+'/sess')
session = web.session.Session(app, store, initializer=sessVals)

The path have all been checked, and they are correct, with permissions
relaxed enough for apache to open/read the files.
the cfg.finalDb resolves to "/var/www/arc_en_ciel/htdocs/../sqlite/
arcenciel.sqlite3", which is an sqlite3 database I created using the
sqlite cli tools.
cfg.debugMode is False, just as a security.

When I enter my first page, I've declared
web.debug(session)
to see the session content.
From an web.py server, the result is:
<Storage {'msg': u'Erreur de connection.', 'ip': u'127.0.0.1',
'logged': False, 'session_id':
'3f63b62e016a10b8db33a7ef98bc35b712fd0f40'}>
From apache, the result is
<Storage {}>, referer: http://aec.dev/base.py/
Of course, the same file is used each time.

Has anyone ever faced this situation ?
I'm just "that" close to throw web.py away and redo this with django,
but I love web.py simplicity sooooo much more that it would really
hurt.

The complete code is:
#!/bin/python
# -*- coding: utf-8 -*-
import web, os, os.path, stat
import mimetypes
from web import form

urls = (
'/' , 'login',
'/login/' , 'login',
'/upload/(.*)$' , 'upload',
'/newFolder/(.*)' , 'newFolder',
'/del/(.*)' , 'delete',
'/search/(.*)$' , 'search',
'/browse/(.*)$' , 'browse',
'/download/(.*)$' , 'download',
'/my(.*)' , 'home',
'/sess' , 'sess',
)
#DONE: login
#DONE: navigation dans le repository
#DONE: ajouter une page de changement des infos persos
#DONE: download des fichiers
#DONE: upload des fichiers
#TODO: indexage des fichiers uploadés

def walktree (top = ".", depthfirst = True):
names = os.listdir(unicode(top))
if not depthfirst:
yield top, names
for name in names:
if name.startswith('.')==False:
try:
st = os.lstat(os.path.join(top, name))
except os.error:
continue
if depthfirst:
yield top, names

def getMsg():
ret=''
if session.get('msg','')!='':
ret=session.msg
session.msg=''
return ret

def parentPath(opath):
aryTmp=opath.split(os.path.sep)
path=''
for i in aryTmp[:-1]:
path=os.path.join(path, i)
return path

def cleanPath(path):
return path.replace('//','/')

class config:
def __init__(self):
self.curPath = os.path.dirname(__file__)
self.basePath=os.path.join(self.curPath,'..')
self.storePath = os.path.join(self.basePath, 'files')
self.tplPath=os.path.join(self.basePath,'tpl/')
self.sessPath=os.path.join(self.basePath,'sess/')
self.dbPath=os.path.join(self.basePath,'sqlite')
self.dbFile='arcenciel.sqlite3'
self.finalDb=os.path.join(self.dbPath, self.dbFile)
self.debugMode=False
self.frmHome = form.Form(
form.Password('pwd', description='Veuillez donner votre nouveau
mot de passe'),
form.Password('pwd2', description='Veullez retaper votre nouveau
mot de passe'),
form.Button("submit", type="submit", description="Changer de mot
de passe"),
)
self.frmLogin = form.Form(
form.Textbox('username', description="Utilisateur"),
form.Password('pwd', description='Mot de passe'),
form.Button("submit", type="submit",
description="S'authentifier"),
)
self.frmNewFolder=form.Form(
form.Textbox('folderName', description='Donnez le nom du dossier
à créer'),
form.Button("submit", type="submit", description="Créer le
dossier"),
)
self.frmUp=form.Form(
form.File('newFile', description='Fichier à transmettre' ),
form.Button("submit", type="submit", description="Créer le
dossier"),
)

cfg=config()
web.config.debug = cfg.debugMode
app = web.application(urls, globals())
db=web.database(dbn='sqlite', db=cfg.finalDb)
sessVals={'logged': False,
'msg':'',
'user':'',
'uid':False,
}
store = web.session.DBStore(db, 'sessions')
#store = web.session.DiskStore(cfg.curPath+'/sess')
session = web.session.Session(app, store, initializer=sessVals)

#===============================================================================
# if web.config.get('_session') is None:
# session = web.session.Session(app, store, sessVals)
# web.config._session = session
# else:
# session = web.config._session
#===============================================================================

session.logged=False
cfg.app=app
rdr = web.template.render(cfg.tplPath)
application = web.application(urls, globals()).wsgifunc()

class dbg:
def GET(self):
return rdr.debug(cfg.curPath, cfg.basePath, cfg.storePath,
cfg.finalDb, os.path.join(cfg.curPath, 'sess'))

class login:
'''
Let the users login
'''
def GET(self):
web.debug(session)
web.debug(db)
session.logged=False
msg=getMsg()
if session.logged==False:
return rdr.welcome(cfg.frmLogin, msg)
else:
web.redirect('/browse/')

def POST(self):
i=web.input()
ret=False
if i.username!='' and i.pwd!='':
ret=db.select('users',where='lower(username)=\'%s\' and password=
\'%s\''%(i.username, i.pwd))
cpt=0
for row in ret:
cpt+=1
uid=row.userid
if cpt==1:
session.logged=True
session.user=i.username
session.id=uid
web.redirect('/browse/')
else:
session.msg='Erreur de connection.'.decode('utf-8')
web.redirect('/')
else:
session.msg='Pas de mot de passe spécifié'.decode('utf-8')
web.redirect('/')

class newFolder:
def GET(self, path):
return rdr.newFolder(cleanPath(path), cfg.frmNewFolder, '')

def POST(self, path):
path=cleanPath(path)
i=web.input()
msg=''
try:
os.mkdir(os.path.join(cfg.storePath, path, i.folderName))
except OSError, err:
msg='Erreur lors de la création du dossier %s: %s'.decode
('utf-8')%(i.folderName, err)
finally:
if msg=='':
web.redirect('/browse/%s'%(path))
else:
return rdr.newFolder(path, cfg.frmNewFolder, msg)

class delete:
def GET(self, opath):
opath=cleanPath(opath.encode('utf-8'))
finPath=os.path.join(cfg.storePath, opath)
path=parentPath(opath)
try:
if os.path.isdir(finPath):
trg='dossier'
os.rmdir(finPath)
else:
trg='fichier'
os.unlink(finPath)
except OSError, err:
session.msg='Erreur lors de la supression du %s %s: %s'.decode
('utf-8')%(trg, opath, err)
finally:
web.redirect('/browse/%s'%(path))

class upload:
'''
Upload a file in a given directory.
'''
def GET(self, path):
path=cleanPath(path)
msg=getMsg()
return rdr.upload(cfg.frmUp, path, msg)

def POST(self, path):
path=cleanPath(path.encode('utf-8'))
x = web.input(newFile={})
finPath=os.path.join(unicode(cfg.storePath), unicode(path), x
['newFile'].filename.decode('utf-8'))
web.debug(finPath)
web.debug(len(x['newFile'].value))
try:
h=open(finPath.encode('utf-8'),'wb+')
h.write(x['newFile'].value)
h.close()
raise web.seeother('/browse/%s'%(path))
except UnicodeEncodeError, err:
session.msg=err
return web.redirect('/upload/%s'%(path))

class browse:
'''
Browse the filesystem
'''
def GET(self, path=None):
if session.logged!=True:
web.redirect('/login/')
else:
#present a view of the fs files uploaded
if path==None or path=='':
path=cfg.storePath
path=cleanPath(path)
aryTmp=path.replace(cfg.storePath,'').split(os.path.sep)

#check if we are at the top level
top=''
for x in aryTmp[:-1]:
top=os.path.join(top, x)
if top=='' and aryTmp[0]=='':
top=False
aryDirs=[]
aryFiles=[]

#get list of files and dir in the current directory.
for (basepath, children) in walktree(os.path.join
(cfg.storePath,path.encode('utf-8')),False):
for child in children:
if child.startswith('.')==False:
fullPath=os.path.join(unicode(basepath), child.decode
('utf-8'))
parent=parentPath(fullPath.replace(cfg.storePath,''))
o={'name':child, 'base':basepath, 'full':fullPath,
'parent':parent, 'short':fullPath.replace(cfg.storePath+'/','')}
if os.path.isdir(fullPath.encode('utf-8')):
#print 'adding %s to dirs'%child
aryDirs.append(o)
else:
#print 'adding %s to files'%child
aryFiles.append(o)
#end if
#end for
#end for
if path!=cfg.storePath:
loc=path+'/'
else:
loc=''
loc=cleanPath(loc)
msg=getMsg()
return rdr.browse(aryDirs, aryFiles, top, loc, msg, 'browse')
pass

def POST(self):
pass

class home:
def GET(self, jnk):
if session.msg!='':
msg=session.msg
session.msg=''
else:
msg=''
return rdr.home(session, cfg.frmHome, msg)

def POST(self, jnk):
i=web.input()
ret=False
if i.pwd!=i.pwd2:
#pwd mismatch
session.msg="Les mots de passes ne sont pas identiques.<br/
>Veuillez ré-essayer."
web.redirect('/my/')
else:
#update pwd
q="update users set password='%s' where userid='%d'"%(i.pwd,
session.id)
db.update('users',where="userid='%d'"%session.id,
password=i.pwd)
msg='Votre mot de passe à été mis à jour'
return rdr.home(session, cfg.frmHome, msg)

class download:
def GET(self, path):
path=cleanPath(path.encode('utf-8'))
finPath=os.path.join(cfg.storePath,path)
mimetypes.init()
mime=mimetypes.guess_type(path, True)[0]
web.header('Content-Type', mime)
h=open(finPath)
x=h.read()
h.close()
return x

class search:
'''
Search the indexed files for a given string
'''
def GET(self):
pass

def POST(self):
pass

if __name__ == "__main__":
app.run()

Brent Pedersen

unread,
Mar 24, 2009, 11:11:01 PM3/24/09
to we...@googlegroups.com
sqlite needs write permissions on the _directory_
where the sqlite database is located and (r/write permissions)
on the file itself.

so after defining try:

assert os.path.exists(self.finalDb), "db doesnt exist"
assert os.access(self.finalDB, os.W_OK), "cant write to db file"
assert os.access(self.dbPath, os.W_OK), "cant write to db directory"

and see which on fails. then adjust permissions.

Graham Dumpleton

unread,
Mar 24, 2009, 11:19:36 PM3/24/09
to web.py


On Mar 25, 2:11 pm, Brent Pedersen <bpede...@gmail.com> wrote:
> sqlite needs write permissions on the _directory_
> where the sqlite database is located and (r/write permissions)
> on the file itself.
>
> so after defining try:
>
> assert os.path.exists(self.finalDb), "db doesnt exist"
> assert os.access(self.finalDB, os.W_OK), "cant write to db file"
> assert os.access(self.dbPath, os.W_OK), "cant write to db directory"
>
> and see which on fails. then adjust permissions.

However, don't just go making the directories world writable. You are
better off running mod_wsgi daemon mode and run your application as
distinct user from Apache user, perhaps even yourself, such that it
has same access rights as yourself and can use the directories without
having to make them world writable or make the directories owned by
Apache user.

Also double check that your configuration isn't using a relative path
to stuff like the database. In Apache the current working directory
could be anything.

Graham
> ...
>
> read more »

Thierry

unread,
Mar 25, 2009, 2:13:03 AM3/25/09
to web.py
Thanks for the advices.
But sadly, it's not that.
The sqlite parent folder perms are ok.
After that mail, I created a "log" table, and made the script write it
something on the first page loading, and it appears.
Only the sessions table stay empty.

Again, if run it from the webpy server, the sessions appears in the
session table, and everything works.
I'm stumbled...

On Mar 25, 4:19 am, Graham Dumpleton <Graham.Dumple...@gmail.com>
wrote:

Thierry

unread,
Mar 25, 2009, 3:56:46 AM3/25/09
to web.py
And for completness, here is my virtualhost apache config:

<VirtualHost *:80>
ServerName aec.dev
ServerAlias www.aec.dev
DocumentRoot /var/www/arc_en_ciel/htdocs/
CustomLog /var/www/arc_en_ciel/log/access_log combined
ErrorLog /var/www/arc_en_ciel/log/error_log

RewriteEngine on
RewriteCond %{REQUEST_METHOD} ^(TRACE|TRACK)
RewriteRule .* - [F]

include /etc/apache2/vhosts.d/expire
include /etc/apache2/vhosts.d/defRoot

<Files base.py>
SetHandler wsgi-script
Options ExecCGI FollowSymLinks
</Files>
</VirtualHost>

Graham Dumpleton

unread,
Mar 25, 2009, 5:02:31 AM3/25/09
to web.py
Which means you are running in embedded mode and code will be running
as special Apache user and not you.

So, when you claim that permissions on directory where database is
correct, what does that mean?

What is the user/group that Apache runs as?

What do you get for 'ls -las' on directory where database is?

Are all parent directories back up to root also readable by others?

Unless you have made everything writable by everyone, or run both
Apache and webpy server as the same user, it is unlikely to work.

To be absolutely sure it isn't a database permissions problem, please
answer the above with actual details.

Am only pushing this as it is the most common cause of problems and
your configuration doesn't show you running in daemon mode as
yourself, which would be the preferred scenario.

Graham

Thierry

unread,
Mar 25, 2009, 7:11:45 AM3/25/09
to web.py

> So, when you claim that permissions on directory where database is
> correct, what does that mean?
>
The directory and the sqlite db are chmoded to 664 and the owner of
both directory and db is apache:webdev
The creator of the db is tmo:webdev
The server runs with apache:apache, but is member of the webdev group
too

> What is the user/group that Apache runs as?
>
> What do you get for 'ls -las' on directory where database is?
>
root@NAS:/var/www/arc_en_ciel# ls -las sqlite/
total 28
4 drwxrwxrwx 3 tmo webdev 4096 Mar 25 11:13 .
4 drwxrwxr-x 9 tmo webdev 4096 Mar 25 10:06 ..
4 drwxrwxrwx 6 tmo webdev 4096 Mar 25 01:28 .svn
12 -rwxrwxrwx 1 tmo webdev 9216 Mar 25 11:13 arcenciel.sqlite3
4 -rwxrwxrwx 1 tmo webdev 973 Mar 25 03:25 init.sql


> Are all parent directories back up to root also readable by others?
>
yes

> Unless you have made everything writable by everyone, or run both
> Apache and webpy server as the same user, it is unlikely to work.
>
It's the case, I think.
root@NAS:/var/www/arc_en_ciel# ls -lad /var/
drwxr-xr-x 15 root root 4096 Jul 13 2008 /var/
root@NAS:/var/www/arc_en_ciel# ls -lad /var/www/
drwxrwxr-x 23 apache webdev 4096 Mar 25 01:22 /var/www/
root@NAS:/var/www/arc_en_ciel# ls -lad /var/www/arc_en_ciel/
drwxrwxr-x 9 tmo webdev 4096 Mar 25 10:06 /var/www/arc_en_ciel/
root@NAS:/var/www/arc_en_ciel# ls -lad /var/www/arc_en_ciel/sqlite/
drwxrwxrwx 3 tmo webdev 4096 Mar 25 11:13 /var/www/arc_en_ciel/sqlite/

> To be absolutely sure it isn't a database permissions problem, please
> answer the above with actual details.
>

What tells me too that it's not a db problem, is that I can do
inserts.
I've got a simple "log" table, just for testing the db
sqlite> .schema log
CREATE TABLE log(logid integer not null primary key AUTOINCREMENT, txt
text);
sqlite> select * from log;
sqlite>

Into my entry point code, I have added
import datetime
db.insert('log',txt='in log sqlite %s'%(datetime.datetime.now()))

and after the first try to access the page:
sqlite> select * from log;
52|in log sqlite 2009-03-25 11:18:04.067880

But:
sqlite> select * from sessions;
sqlite>

After a couple of reloads, I have:
sqlite> select * from log;
52|in log sqlite 2009-03-25 11:18:04.067880
53|in log sqlite 2009-03-25 11:19:19.253749
54|in log sqlite 2009-03-25 11:46:10.103165
55|in log sqlite 2009-03-25 11:46:11.187960
sqlite> select * from sessions;
sqlite>

I have issued an apachectl2 restart, restarted the browser and the
results are:
sqlite> select * from log;
52|in log sqlite 2009-03-25 11:18:04.067880
53|in log sqlite 2009-03-25 11:19:19.253749
54|in log sqlite 2009-03-25 11:46:10.103165
55|in log sqlite 2009-03-25 11:46:11.187960
56|in log sqlite 2009-03-25 11:47:50.882574
sqlite> select * from sessions;
sqlite>


> Am only pushing this as it is the most common cause of problems and
> your configuration doesn't show you running in daemon mode as
> yourself, which would be the preferred scenario.

I have to admit I've blindly followed the webpy tutorial on how
running webpy apps with mod_wsgi.
Reading about the daemon mode of mod_wsgi, I've almost haven't
understood anything of it.

I don't understand how to configure it, and which modifications I
should make to the script, if any...
I tried to declare my app as the wsgi gateway
WSGIScriptAlias / /var/www/arc_en_ciel/htdocs/base.py
But I get back an error:
[Wed Mar 25 12:02:31 2009] [error] [client 194.209.119.22] File does
not exist: /var/www/arc_en_ciel/htdocs/base.py/

The file is there though:
ls -lah /var/www/arc_en_ciel/htdocs/base.py
-rwxrwxrwx 1 tmo webdev 9.5K Mar 25 11:17 /var/www/arc_en_ciel/htdocs/
base.py

Sigh..
Days like this one make me really miss the ease of an PHP script
deployment...

Thierry

unread,
Mar 25, 2009, 7:56:21 AM3/25/09
to web.py
I succeeded in running the application in daemon mode, I think, but
the problem is still there.
My apache configuration is now

<VirtualHost *:80>
ServerName aec.dev
ServerAlias www.aec.dev
serverAlias tmain.ath.cx
DocumentRoot /var/www/arc_en_ciel/htdocs/
CustomLog /var/www/arc_en_ciel/log/access_log combined
ErrorLog /var/www/arc_en_ciel/log/error_log

RewriteEngine on
RewriteCond %{REQUEST_METHOD} ^(TRACE|TRACK)
RewriteRule .* - [F]

include /etc/apache2/vhosts.d/expire
include /etc/apache2/vhosts.d/defRoot

WSGIScriptAlias / /var/www/arc_en_ciel/htdocs/base.py
</VirtualHost>

I've switched to a file store for the session, hoping it would be
better, but still nothing.
The file store session path is
/var/www/arc_en_ciel/htdocs/../sess
I've chmoded it to 777, but no files are created in that folder from
mod_wsgi.
No errors, no warning, nothing.

I've extended my entry point with
if session.get('truc',False)==False:
session.truc=1
else:
session.truc=session.truc+1
web.debug(session)
and a web.debug(session) always give me a value of 1.
[Wed Mar 25 12:37:16 2009] [error] [client 194.209.119.22] <Storage
{'truc': 1, 'logged': False}>
[Wed Mar 25 12:37:24 2009] [error] [client 194.209.119.22] <Storage
{'truc': 1}>
[Wed Mar 25 12:39:21 2009] [error] [client 194.209.119.22] <Storage
{'truc': 1}>
[Wed Mar 25 12:39:52 2009] [error] [client 194.209.119.22] <Storage
{'truc': 1, 'logged': False}>
[Wed Mar 25 12:40:04 2009] [error] [client 194.209.119.22] <Storage
{'truc': 1, 'logged': False}>
[Wed Mar 25 12:40:15 2009] [error] [client 194.209.119.22] <Storage
{'truc': 1}>
[Wed Mar 25 12:40:16 2009] [error] [client 194.209.119.22] <Storage
{'truc': 1}>
[Wed Mar 25 12:40:17 2009] [error] [client 194.209.119.22] <Storage
{'truc': 1}>

The session is not stored between requests. I think I could mimic it
with the db, via a db.insert() and db.select() sequence, but I'd like
to understand if I did anything wrong...
What looks strange too, is that when I dump
web..config.session_parameters, the cookie domain is empty, and I get
the same secret_key with any browser or session I use to connect to
the site:
With opera:
[Wed Mar 25 12:51:27 2009] [error] [client 194.209.119.22] <Storage
{'ignore_expiry': True, 'expired_message': 'Session expired',
'timeout': 86400, 'ignore_change_ip': True, 'cookie_domain': None,
'secret_key': 'fLjUfxqXtfNoIldA0A0J', 'cookie_name':
'webpy_session_id'}>
With IE 7:
[Wed Mar 25 12:50:46 2009] [error] [client 194.209.119.22] <Storage
{'ignore_expiry': True, 'expired_message': 'Session expired',
'timeout': 86400, 'ignore_change_ip': True, 'cookie_domain': None,
'secret_key': 'fLjUfxqXtfNoIldA0A0J', 'cookie_name':
'webpy_session_id'}>, referer: http://tmain.ath.cx/
with firefox 3.0:
[Wed Mar 25 12:48:59 2009] [error] [client 194.209.119.22] <Storage
{'ignore_expiry': True, 'expired_message': 'Session expired',
'timeout': 86400, 'ignore_change_ip': True, 'cookie_domain': None,
'secret_key': 'fLjUfxqXtfNoIldA0A0J', 'cookie_name':
'webpy_session_id'}>

And I get no session cookie when serving from apache.
Only when serving from python.

Thierry

unread,
Mar 25, 2009, 6:18:22 PM3/25/09
to web.py
I give up...
I've spent almost 2 full days trying to get it working, for 10 hours
of development that worked with web.y internal server.

I'll start migrating my work to PHP.
I'm really surprized that something as simple as session are so hard
to get working. I always had thought it was an already acquired point.

Anyway, if anyone have an explanation, I'm still curious to know it.
I tried to look for beaker or flup sessions, but found almost no
documentation and could not get any examples I've found to work
neither...
They seems all to have been made for web.py 0.23

Graham Dumpleton

unread,
Mar 25, 2009, 7:25:13 PM3/25/09
to web.py


On Mar 25, 10:11 pm, Thierry <tsch...@gmail.com> wrote:
> > So, when you claim that permissions on directory where database is
> > correct, what does that mean?
>
> The directory and the sqlite db are chmoded to 664 and the owner of
> both directory and db is apache:webdev

Which isn't what your 'ls' output below says. A directory would never
be 664 as it would block directory search.

> The creator of the db is tmo:webdev
>
> The server runs with apache:apache, but is member of the webdev group
> too
>
> > What is the user/group that Apache runs as?
>
> > What do you get for 'ls -las' on directory where database is?
>
> root@NAS:/var/www/arc_en_ciel# ls -las sqlite/
> total 28
>  4 drwxrwxrwx 3 tmo webdev 4096 Mar 25 11:13 .
>  4 drwxrwxr-x 9 tmo webdev 4096 Mar 25 10:06 ..
>  4 drwxrwxrwx 6 tmo webdev 4096 Mar 25 01:28 .svn
> 12 -rwxrwxrwx 1 tmo webdev 9216 Mar 25 11:13 arcenciel.sqlite3
>  4 -rwxrwxrwx 1 tmo webdev  973 Mar 25 03:25 init.sql

Graham

Graham Dumpleton

unread,
Mar 25, 2009, 7:27:00 PM3/25/09
to web.py


On Mar 25, 10:56 pm, Thierry <tsch...@gmail.com> wrote:
> I succeeded in running the application in daemon mode, I think, but
> the problem is still there.
> My apache configuration is now

If that is really your Apache configuration, then no you are not
running in daemon mode. There are no WSGIDaemonProcess or
WSGIProcessGroup directives present.

See:

http://code.google.com/p/modwsgi/wiki/QuickConfigurationGuide

Anyway, all academic now if you have gone back to PHP.

Graham

Thierry

unread,
Mar 25, 2009, 8:18:49 PM3/25/09
to web.py
I tried with it, reverted back to another one...
Just for the sake of testing it, I've tried it, and still no luck.
My apache cfg is noe
<VirtualHost *:80>
ServerName aec.dev
ServerAlias www.aec.dev
serverAlias tmain.ath.cx
DocumentRoot /var/www/arc_en_ciel/htdocs/
CustomLog /var/www/arc_en_ciel/log/access_log combined
ErrorLog /var/www/arc_en_ciel/log/error_log

RewriteEngine on
RewriteCond %{REQUEST_METHOD} ^(TRACE|TRACK)
RewriteRule .* - [F]

include /etc/apache2/vhosts.d/expire
include /etc/apache2/vhosts.d/defRoot

#setEnv LOCATION dev
#php_admin_value auto_prepend_file /var/www/arc_en_ciel/htdocs/libs/
prepend/prepend.php
#php_admin_value auto_append_file /var/www/arc_en_ciel/htdocs/libs/
append/append.php
#php_admin_value error_log /var/www/arc_en_ciel/log/php.log
#php_admin_flag display_errors 1
#php_admin_flag log_errors 1

WSGIDaemonProcess tmain.ath.cx processes=2 threads=15 display-name=%
{GROUP}
WSGIProcessGroup tmain.ath.cx
WSGIScriptAlias / /var/www/arc_en_ciel/htdocs/base.py
</VirtualHost>

> > So, when you claim that permissions on directory where database is
> > correct, what does that mean?

> The directory and the sqlite db are chmoded to 664 and the owner of
> both directory and db is apache:webdev

> Which isn't what your 'ls' output below says. A directory would never
> be 664 as it would block directory search.
True, I've spotted it after sending the message, and had chmodded the
whole path to 777, for testing.
But still, it was the same.

> Anyway, all academic now if you have gone back to PHP.
Not at all. I have not totally ditched web.py, but I need to have
something running in the next days, and I cannot waste more time on a
configuration problem.
I cannot replace apache with lighthttpd neither, as I have many sites
running now on the future server, and I won't go in the hassle of
updating them all just for that.
I thought about running a second webserver on a different port, but
not for now.

The point is, that even with the bare session demo of web.py 0.3 and
following the recommanded setup of apache+mod_wsgi, it don't work.
I now have spent around 15 hours to try to have it working in apache,
for around 5 hours of development.
So, my quetion could be trivial, but does anyone have ever tried to
use the sessions on an web.py 0.3 on apache with mod_wsgi with the
recommanded settings?

Maybe it's my apache configuration, maybe it's my wsgi directives,
maybe it's my python install. I have absolutely no clues.
I've reinstalled apache, tried worker and prefork mpm's.
I've tried to install other session middleware, I've downgraded
web.py. mod_wsgi and apache, and nothing have made it working.
I've even tested the script on 3 servers, the same results on the 3.

My impression is that the session object is only attached to the
web.py object, not the wsgi object.
If I try to attache it to the wsgi object, I've got an error telling
me:
AttributeError: 'function' object has no attribute 'add_processor'
At this point, I stopped trying, and switched to PHP.
But this saddens me...

Graham Dumpleton

unread,
Mar 25, 2009, 8:36:50 PM3/25/09
to web.py
You have not supplied the 'user' and 'group' options to
WSGIDaemonProcess and with the exact same user and group that you are
running the webpy server as. That was the whole point of using daemon
mode in the first place. For further information on those options see:

http://code.google.com/p/modwsgi/wiki/ConfigurationDirectives#WSGIDaemonProcess

If when WSGI process runs as the exact same user, such that it has
exact same privileges, then we can discount directory/file
permissions.

Beyond that other problems may be:

1. When you run webpy server, webpy or sqlite is making use of user
environment variables you have set which aren't then available to the
application when run under Apache/mod_wsgi.

2. Your application has somewhere in its configuration or code a
dependence on the application being run in a specific directory. In
other words, it is using relative paths instead of absolute paths. One
way around that is to set the 'home' option to WSGIDaemonProcess to be
the same directory in which you were running the webpy server by hand.
Better still, eliminate dependencies on relative paths.

3. You are being affected by a clash between mod_cache in Apache and
sqlite which is causing sqlite to fail. This is a known issue due to a
class in symbol names. You need to disable mod_cache in Apache if
affected by this.

You should also set:

LogLevel info

for the VirtualHost. This way mod_wsgi will output more information in
Apache error logs, including information that can be used to confirm
that it is running in daemon mode.

Graham

Thierry

unread,
Mar 26, 2009, 4:20:23 AM3/26/09
to web.py
> You have not supplied the 'user' and 'group' options to
> WSGIDaemonProcess and with the exact same user and group that you are
> running the webpy server as. That was the whole point of using daemon
> mode in the first place. For further information on those options see:
>
> http://code.google.com/p/modwsgi/wiki/ConfigurationDirectives#WSGIDae...

Ok, I have added the group, user and home directives to be the same as
my interactive session
WSGIDaemonProcess tmain.ath.cx processes=2 threads=15 display-name=%
{GROUP} user=tmo group=webdev home=/home/tmo
With logLevel set, and after an restart, I see this in the error log:
[Thu Mar 26 09:10:41 2009] [info] mod_wsgi (pid=5205): Shutdown
requested 'tmain.ath.cx'.
[Thu Mar 26 09:10:41 2009] [info] mod_wsgi (pid=5205): Stopping
process 'tmain.ath.cx'.
[Thu Mar 26 09:10:41 2009] [info] mod_wsgi (pid=5205): Destroy
interpreter 'aec.dev|'.
[Thu Mar 26 09:10:41 2009] [info] mod_wsgi (pid=5205): Cleanup
interpreter ''.
[Thu Mar 26 09:10:41 2009] [info] mod_wsgi (pid=5205): Terminating
Python.
[Thu Mar 26 09:10:41 2009] [info] mod_wsgi (pid=5204): Shutdown
requested 'tmain.ath.cx'.
[Thu Mar 26 09:10:41 2009] [info] mod_wsgi (pid=5204): Stopping
process 'tmain.ath.cx'.
[Thu Mar 26 09:10:41 2009] [info] mod_wsgi (pid=5204): Destroy
interpreter 'aec.dev|'.
[Thu Mar 26 09:10:41 2009] [info] mod_wsgi (pid=5204): Cleanup
interpreter ''.
[Thu Mar 26 09:10:41 2009] [info] mod_wsgi (pid=5204): Terminating
Python.
[Thu Mar 26 09:10:42 2009] [info] mod_wsgi (pid=5351): Attach
interpreter ''.
[Thu Mar 26 09:10:42 2009] [info] mod_wsgi (pid=5351): Enable
deadlock thread in process 'tmain.ath.cx'.
[Thu Mar 26 09:10:42 2009] [info] mod_wsgi (pid=5350): Attach
interpreter ''.
[Thu Mar 26 09:10:42 2009] [info] mod_wsgi (pid=5350): Enable
monitor thread in process 'tmain.ath.cx'.
[Thu Mar 26 09:10:42 2009] [info] mod_wsgi (pid=5350): Enable
deadlock thread in process 'tmain.ath.cx'.
[Thu Mar 26 09:10:42 2009] [info] mod_wsgi (pid=5351): Enable
monitor thread in process 'tmain.ath.cx'.
[Thu Mar 26 09:10:58 2009] [info] mod_wsgi (pid=5351): Create
interpreter 'aec.dev|'.
[Thu Mar 26 09:10:58 2009] [info] [client 194.209.119.22] mod_wsgi
(pid=5351, process='tmain.ath.cx', application='aec.dev|'): Loading
WSGI script '/var/www/arc_en_ciel/htdocs/base.py'.
[Thu Mar 26 09:10:58 2009] [error] [client 194.209.119.22] <Storage
{'msg': u'Pas de mot de passe sp\\xe9cifi\\xe9', 'logged': False}>

on each requests. But the session still don't works.
On the login page, if nothing is provided, I put a message in the
session and redirect to the GET part of the class.

> If when WSGI process runs as the exact same user, such that it has
> exact same privileges, then we can discount directory/file
> permissions.
>
> Beyond that other problems may be:
>
> 1. When you run webpy server, webpy or sqlite is making use of user
> environment variables you have set which aren't then available to the
> application when run under Apache/mod_wsgi.

I have not (conscientiously) make the application rely on any
environment variable.

> 2. Your application has somewhere in its configuration or code a
> dependence on the application being run in a specific directory. In
> other words, it is using relative paths instead of absolute paths. One
> way around that is to set the 'home' option to WSGIDaemonProcess to be
> the same directory in which you were running the webpy server by hand.
> Better still, eliminate dependencies on relative paths.

I'm not sure that's the case.
I base all my paths on the dirname of __file__, and construct the
other path from that value.
class config:
def __init__(self):
self.curPath = os.path.dirname(__file__)
self.basePath=os.path.join(self.curPath,'..')

> 3. You are being affected by a clash between mod_cache in Apache and
> sqlite which is causing sqlite to fail. This is a known issue due to a
> class in symbol names. You need to disable mod_cache in Apache if
> affected by this.

I've checked, and mod_cache is not installed in apache.
By the way, I tried to use postgresql as the session store at one
moment, but the symptoms where the same.

Thank you for the time you put in this, Graham.
I really do appreciate it.

Thierry.

Andrew Gwozdziewycz

unread,
Mar 26, 2009, 6:03:24 AM3/26/09
to we...@googlegroups.com
I think it's obvious that the database is not the problem here.
Sessions weren't
working for him with a database store, despite the fact that he could
log requests
to the database.

The one question that I haven't seen asked is, are you sure you have cookies
enabled? I apologize for the absurdity of the question.
--
http://www.apgwoz.com

Thierry

unread,
Mar 26, 2009, 6:05:31 AM3/26/09
to web.py
On Mar 26, 11:03 am, Andrew Gwozdziewycz <apg...@gmail.com> wrote:
> I think it's obvious that the database is not the problem here.
> Sessions weren't
> working for him with a database store, despite the fact that he could
> log requests
> to the database.
>
> The one question that I haven't seen asked is, are you sure you have cookies
> enabled? I apologize for the absurdity of the question.

It's not absurd, and yes, the cookies are enabled.
I had even cleaned the one generated by web.py internal server to have
a complete "blank state" prior to my tests.

Thierry

Graham Dumpleton

unread,
Mar 26, 2009, 6:06:04 AM3/26/09
to web.py


On Mar 26, 9:03 pm, Andrew Gwozdziewycz <apg...@gmail.com> wrote:
> I think it's obvious that the database is not the problem here.
> Sessions weren't
> working for him with a database store, despite the fact that he could
> log requests
> to the database.
>
> The one question that I haven't seen asked is, are you sure you have cookies
> enabled? I apologize for the absurdity of the question.

But he said it worked for webpy server, so presuming that same browser
is being used, they must be enabled.

Graham

Thierry

unread,
Mar 26, 2009, 7:26:04 PM3/26/09
to web.py
Ok, I've got it running finally....

The key is, in the wsgi daemon config to specify 1 process only.
Once I did that, and installed beaker (I've finally understood how to
use it. Unbelievable what 1 night of sleep can do) the sessions
worked.

My vhost wsgi config is now
WSGIDaemonProcess tmain.ath.cx processes=1 threads=15 display-name=%
{GROUP} user=tmo group=webdev home=/home/tmo
WSGIProcessGroup tmain.ath.cx
WSGIScriptAlias / /var/www/arc_en_ciel/htdocs/base.py


and my application starts with
import web, os, os.path, stat
from web import form
import sqlite3, StringIO, mimetypes
from beaker.middleware import SessionMiddleware

urls = (
'/' , 'login',
'/login/' , 'login',
'/upload/(.*)$' , 'upload',
'/newFolder/(.*)' , 'newFolder',
'/del/(.*)' , 'delete',
'/search/(.*)$' , 'search',
'/browse/(.*)$' , 'browse',
'/download/(.*)$' , 'download',
'/my(.*)' , 'home',
)
#DONE: login
#DONE: navigation dans le repository
#TODO: ajouter une page de changement des infos persos
#TODO: download des fichiers
#TODO: upload des fichiers
#TODO: indexage des fichiers uploadés

def init():
web.header("Content-Type","text/html; charset=utf-8")
session = web.ctx.environ['beaker.session']
if not 'initialized' in session:
session['logged']=False
session['msg']=''
session['user']=''
session['uid']=None
session['initialized']=True
session.save()
return session
#...
application = web.application(urls, globals()).wsgifunc()
application = SessionMiddleware(application, key='mysession',
secret='randomsecret')
cfg=config()
web.config.debug = cfg.debugMode
db=web.database(dbn='sqlite', db=cfg.finalDb)
rdr = web.template.render(cfg.tplPath)

class login:
'''
Let the users login
'''
def GET(self):
session=init()
web.debug(session)
return rdr.welcome(cfg.frmLogin, getMsg())

def POST(self):
session=init()
web.debug(session)
i=web.input()
ret=False
if i.username!='' and i.pwd!='':

ret=db.select('users',where='lower(username)=\'%s\' and password=
\'%s\''%(i.username, i.pwd))
cpt=0
for row in ret:
cpt+=1
uid=row.userid
if cpt==1:
session['logged']=True
session['user']=i.username
session['id']=uid
session.save()
web.redirect('/browse/')
else:
session['msg']='Erreur de connection.'.decode('utf-8')
session.save()
web.redirect('/login/')
else:
session['msg']='Pas de mot de passe spécifié'.decode('utf-8')
session.save()
web.redirect('/login/')
#...

Reply all
Reply to author
Forward
0 new messages