Apache Mod-Python - Issues with "Session use with classes" wiki example.

This is Interesting: Free IT Magazines  
Home > Archive > Apache Mod-Python > December 2006 > Issues with "Session use with classes" wiki example.





You are viewing an archived Text-only version of the thread. To view this thread in it's original format and/or if you want to reply to this thread please [click here]

Author Issues with "Session use with classes" wiki example.
Graham Dumpleton

2006-12-05, 1:13 am

Some more details on issues I brought up before about session example.

BTW, in respect of what version of mod_python we write examples for, my
preference would be that we target mod_python 3.3 and then as followup by way
of embedded notes, footnotes or subpages, indicate how it may have to be
changed to work with older versions or whether it will even work with older
versions. By targeting 3.3, I see it as subtle encouragement for people to
upgrade by making it obvious that if they are using a quite old version, that
they aren't going to be getting too much support going forward as they have
been passed by.

More comments below.

Graham Dumpleton wrote ..
> Sorry, but I am going to take issue with where this session example is
> headed
> as there are number of things being done which I at least would regard
> as being
> bad practice. Please don't take this wrong way, your effort in doing this
> stuff in
> the first place is much appreciated and I hope I don't dissuade you from
> continuing. It is just a matter of using our collective minds to ensure
> that
> overall the example is robust and secure.
>
> I'll quickly mention the issues I see and when I get a chance and if no
> one else
> has piped up and explained it more, I respond in more detail.
>
> The first as I mentioned once before is that you are still using MemorySession
> as the session type which means this example will only work for people
> on
> Windows and will not always work for people using prefork/worker on UNIX
> platforms.


It will also not allow sharing of sessions between interpreter instances on
Windows either. If you are going to stick with using MemorySession then all
these caveats have to be explained, but in doing that, it becomes more than
just a simple example which defeats the purpose. Thus, still prefer not using
PythonOption in a simple example and trust that mod_python makes the
sensible choice for the platform being used.

> The second is that it promotes a bad practice of having functions accessible
> under multiple URLs thereby exacerbating a problem with mod_python.publisher
> related to trailing slashes and determining relative URLs. Ie., the following
> both
> map to the same thing.
>
> http://your.domain.com/ExampleSessi...eSession.py/foo
> http://your.domain.com/ExampleSessi...sion.py/foo/foo


A previous post where I have mentioned this issue is:

http://www.modpython.org/pipermail/...rch/020501.html
http://www.modpython.org/pipermail/...ber/022474.html

The simple way of avoiding this in this example is to made 'foo' be '_foo' so it
can't be accessed direct. A better way though would be not to use a class at
all and instead have the example use a basic function. There is no reason to use
a class and it just makes the example overly complicated and may make users
think they have to wrap up their handlers in classes when they don't have to.

Note though that doing this still will not eliminate all the trailing slash problems
as some are caused by shortcomings in mod_python.publisher that can't
practically be fixed as doing so will break a lot of existing code more than likely.

> The third is that in general it is exposing all sorts of private stuff
> which it should
> not.
>
> http://your.domain.com/ExampleSessi...Session.py/tags
> http://your.domain.com/ExampleSessi...ession.py/foo/t
> http://your.domain.com/ExampleSessi....py/foo/session
> http://your.domain.com/ExampleSessi...oo/session/....


Any private data should have a leading underscore so it can't be accessed.
This includes member data of class instances which can be browsed.

> The fourth is that it isn't thread safe and will fail with a multithread
> MPM.


The example uses a single instance of a class as the request handler, but then
caches information as member attributes of that single instance to allow
subsequent functions called to get access to them. This can stuff up badly
as if there are concurrent threads executing the same handler, a second
request can override the member attributes before the first gets to access
them and use them.

This is another reason why as a simple example, a class should not be involved
and a simple function used instead. If data needs to be held somewhere so
that other functions can access it, it should be stored in the request object
and the request object passed around between functions explicitly.

The only other safe way of doing it is to create an instance of the class for
every request. For example something like:

class Instance:

def __init__(self, type, *args, **kwargs):
self.__type = type
self.__args = args
self.__kwargs = kwargs

def __call__(self, req):
assert(type(self.__type) in [types.ClassType, types.TypeType])
target = self.__type(*self,__args,**self.__kwargs)
return util.fs_apply_data(target, req.form)

foo = Instance(Bar, tags)

> The fifth is that it caches the session object and thus holds a reference
> to
> the request object beyond the actual life time of the request. With the
> exposure
> of private stuff above, my guess is I could crash the web server by using
> the
> following URL after first request has been done.
>
> http://your.domain.com/ExampleSessi...ion/make_cookie


If the session is stored as req.session and req passed around, this wouldn't
be an issue. Creating an instance of the class per request would also avoid the
issue.

> The sixth is that I believe we should be persuading users to not be doing
> session creation stuff inside of individual publisher functions as they
> then
> tend to duplicate the same code everywhere. It might be better to show
> them
> how to use stacked handlers to have the session object created even before
> publisher gets invoked, or at least show them the convention of storing
> the
> session object as req.session and always checking for its existence there
> before creating it, so as to avoid deadlocks. That or at least hive the
> session
> creation into a common function they call.


The first option here is to use:

PythonHandler _sessions
PythonHandler mod_python.publisher

In _sessions.py have:

def handler(req):
if not hasattr(req, 'session'):
req.session = Session.Session(req)
return apache.OK

Any publisher function can then assume that the session already exists and just
access it as req.session. This code file has a leading underscore in its name so
that publisher will ignore it when it is stored in the document tree.

Next option is to use a wrapper class and you wrap every function that wants to
be able to use sessions:

class SessionEnabled:
def __init__(self, target):
self.__target = target
def __call__(self):
return util.apply_fs_data(self.__target, req.form)

def _function(req, a, b):
return a,b

function = SessionEnabled(_function)

If your version of Python supports decorators, you could write code to turn
SessionEnabled into a decorator and you could instead say something like:

@session_enabled
def function(req, a, b):
return a.b

If one was using mod_python 3.3, especially if one was using forms based login,
it would be much better to use an authenhandler. This is a more complicated topic
though.

Graham
[vbcol=seagreen]
> More later.
>
> Graham
>
> Apache Wiki wrote ..
> this
> use
> {{{#!python
> ''req''

Graham Dumpleton

2006-12-05, 1:13 am

Graham Dumpleton wrote ..
> Next option is to use a wrapper class and you wrap every function that
> wants to
> be able to use sessions:
>
> class SessionEnabled:
> def __init__(self, target):
> self.__target = target
> def __call__(self):
> return util.apply_fs_data(self.__target, req.form)
>
> def _function(req, a, b):
> return a,b
>
> function = SessionEnabled(_function)


Whoops forgot to create the session.

class SessionEnabled:
def __init__(self, target):
self.__target = target
def __call__(self):
if not hasattr(req, 'session'):
req.session = Session.Session(req)
return util.apply_fs_data(self.__target, req.form)

Graham

Jorey Bump

2006-12-05, 1:12 pm

Graham Dumpleton wrote:

> BTW, in respect of what version of mod_python we write examples for, my
> preference would be that we target mod_python 3.3 and then as followup by way
> of embedded notes, footnotes or subpages, indicate how it may have to be
> changed to work with older versions or whether it will even work with older
> versions. By targeting 3.3, I see it as subtle encouragement for people to
> upgrade by making it obvious that if they are using a quite old version, that
> they aren't going to be getting too much support going forward as they have
> been passed by.


I agree, and would modify the preference to be that wiki contributions
target the current stable version (soon to be 3.3, in this case), with
an eye towards compatibility. As functionality changes with new
releases, the wiki should stay current. It's always frustrating to use
the latest release of a project only to find obsolete info on a wiki.

If we get to the point where the wiki becomes an important source for
bundled documentation, we can simply add a disclaimer such as:

"This wiki targets the current stable release of mod_python (currently
X.x). If you are using an older version, be sure to refer to the
documentation bundled with your release."

Unfortunately, this will continue to plague mod_python until the code
base stabilizes a bit, but the improvements have been worth it. The main
problem is that package based distributions may fall behind quickly,
even though they started with a recent version. Many users cannot
upgrade mod_python on their systems, for a variety of reasons.
Hopefully, when the dust settles, our documentation will be consistent
for most of the versions in the wild.

Graham Dumpleton

2006-12-05, 7:12 pm

Martin Stoufer wrote ..
> Graham Dumpleton wrote:
>
> I haven't seen any emails. And I'm even on the SVN, python-cvs, and
> mod_python wiki lists. I am more than happy to address peoples issues.


What about the python-dev@httpd.apache.org list. Ie., the mod_python
developers list. This is where any replys to wiki update messages go.
I've seen at least one post from you got to that list, so figured you were
on it.

See:

http://mail-archives.apache.org/mod...dscpl.com.au%3e
http://mail-archives.apache.org/mod...nhosting.com%3e
http://mail-archives.apache.org/mod...nhosting.com%3e
http://mail-archives.apache.org/mod...nhosting.com%3e

I've pushed this back onto that list now that I have got your attention
and changed the subject to match what was used for the discussion
there.

BTW, on session 3.3 page, it should be:

PythonOption mod_python.session.session_type MemorySession

not:

PythonOption mod_python.session.MemorySession

But then, using MemorySession as an example may not be the best.

Graham

Sponsored Links






Free braindumps | Software forum | Database administration forum

Copyright 2003 - 2008 webservertalk.com