pso.session
Version: | $Revision: 1.7 $ |
Last Changed: | 3-13-2002 |
Author: | thanos vassilakis |
Company: | Script Foundry Inc. |
Document URL: | http://sourceforge.net/docman/display_doc.php?docid=10175&group_id=49265 |
Contact: | thanos@0x01.com |
Feed-back: | pso-development@lists.sourceforge.net |
Copyright: | thanos vassliakis 2001,2002 |
Contributions: | Ming Huang and Vadim Shaykevich. |
$Id: session-cgi.html,v 1.7 2003/01/24 15:21:47 thanos Exp $ |
Introduction
System Requirements
Real Quick Example - 95% of the Time
What's Going On
More Control - 5% of the Time
- Setting the service id
- Forcing the session id.
- Setting when a session expires.
- Reverting the current session to its previous state.
- Explicitly saving the current session.
- Storing the session files in another path.
- Storing the session data in a database.
- Doing things without cookies.
- Setting the session cookies path and domain
- What else can you do with
pso
?
Session classes
Installation
Installation Example
pso.session
to add easy session
handling to a CGI
script. Python Service Objects
is
a open source Internet service development system. The pso system allows you
to develop platform and server independent cgi scripts that can later be promoted
to NSAPI or modpython request handlers, often without any changes.
Real Quick Example - 95% of the Time
#!/usr/bin python2.2 def testHandler(): print "content-type: text/html" print print "hello world" if __name__ == '__main__': testHandler()Now let's change it to handle sessions:
#!/usr/bin/env python2.2 from pso.service import ServiceHandler def testHandler(serviceRequest): serviceRequest.pso().send_http_headers() try: serviceRequest.pso().session['reloads'] +=1 except: serviceRequest.pso().session['reloads'] =1 print "Hello World! ~ You reloaded: %(reloads)d times ~ Try Reload !" % serviceRequest.pso().session if __name__ == '__main__': ServiceHandler().run(testHandler)The above example was very quick. A lot of default values were used and many assumption were made, yet it shows you how painless it is to add and use session handling.
Test: http://www.0x01.com/~thanos/pso/tests/session/cgi/quick.py
What's Going On
ServiceHandler
is a boot strap. It creates a ServiceRequest
that is the bridge between the pso service interface and the actual underlining server handler. The session object is created, and added to the service request object. This is then passed to testHandler(serviceRequest)
as serviceRequest
. serviceRequest.pso()
is a proxy call to this service request. serviceRequest.pso().send_http_headers()
prints the content-type
, and, just as important, the cookie header set with the session id. The algorithm for getting the session is carried out by pso.session.ServiceHandler.getSession
and is essentially this:
os.environ
. Default to the value the request handler module's name.
HTTP_COOKIE
entry in the os.environ
.
serviceRequest.pos().headers_out['cookie-set']
the value serviceId=sessionId, for example: serviceRequest.pso().setCookie('MI6Service','007')
.
serviceRequest.pso()
is finalized.
SetEnv PSOServiceId 'Your_Service_Id'
<directory>
block.
SetEnv 'Your_Service_Id' 'Your_Session_Id'
<directory>
block.
SetEnv PSOSessionExpire 900 # 15 minutesYou can use simple expressions
SetEnv PSOSessionExpire "15*60" # 15 minutesYou can also set the sessions to expire on a specific date:
SetEnv PSOSessionExpire "Mon, 15 Apr 2001 19:00:00 GMT" # 15 minutesFor more on this format see RFC2068 section 3.3.1 [also RCF822 and RCF1123] If a date is not give all values are seconds relative to the present. You can also control the session's life span in your code:
serviceRequest.session.expire()
serviceRequest.session.expire(0)
test: http://www.0x01.com/~thanos/pso/tests/session/cgi/expire.py
serviceRequest.session.expire(15*60) # or SetEnv PSOSessionExpire "60*15" etc. twoDays = 60*60*48 serviceRequest.session.expire(date = time()+twoDays)
import time serviceRequest.session.expire("Mon, 15 APR 2001 19:00:00", "%a, %d %b %Y %H:%M:%S")
serviceRequest.session.revert()
serviceRequest.session.save()
SetEnv PSOSessionFileLoader_Path /tmp/path0/ # remember the trailing '/'to the .htaccess file or to the relevant apache httpd.conf
<directory>
block.
test: http://www.0x01.com/~thanos/pso/tests/session/cgi/path0.py
pso.session.CookeFileImpl
overloading the attribute CookieFileImpl.PATH
and then pass it to the service handler.
# file: path1.py # #!/usr/bin/env python2.2 from pso.service import ServiceHandler from pso import session class MyFileImpl(session.CookieFileImpl): PATH="/tmp/path1/" . . . if __name__ == '__main__': # Now change from: # ServiceHandler().run(test) #to: ServiceHandler()Run(test, sessionImpl=MyFileImpl)
test: http://www.0x01.com/~thanos/pso/tests/session/cgi/oopath/path1.py
# file: path2.py # #!/usr/bin/env python2.2 from pso.service import ServiceHandler from pso import session class MyFileImpl(session.CookieFileImpl): def getPath(self, reqHandler): """ you must return the full session file path excluding name. It must be valid, and the handler must have the authority to create or write to the given directory. """ return "/tmp/path2/" . . . # Again remember __main__ to change: if __name__ == '__main__': ServiceHandler()Run(testHandler, sessionImpl=MyFileImpl)
test: http://www.0x01.com/~thanos/pso/tests/session/cgi/oopath/path2.py
SessionImpl
. The code below is a bit simplistic,
but illustrates the basic idea, and it works!
#file: mysql/mysqltest.py # #!/usr/bin/env python2.2 from pso.service import ServiceHandler from pso import session import pickle import base64 from time import time import MySQL class MySQLLoader: dbconn = MySQL.connect("localhost", "test") dbconn.query('use test') def load(self, reqHandler): " must return the saved session obj or None. " result = self.dbconn.query("SELECT sessionObj FROM session WHERE sessionId='%s';" % self.getSessionId(reqHandler)) rows = result.fetchrows() if rows: sessionData = rows[0][0] if sessionData: return pickle.loads(base64.decodestring(sessionData)) return session def save(self, reqHandler, session): serviceId = self.getServiceId(reqHandler) sessionId = self.getSessionId(reqHandler) sessionStr = base64.encodestring(pickle.dumps(session,1)) res = self.dbconn.query("UPDATE session SET sessionObj='%s', serviceId='%s' WHERE sessionId='%s';" % (sessionStr, serviceId, sessionId)) if res.affectedrows() == 0: self.dbconn.query("INSERT INTO session (serviceId,sessionId, sessionObj) values ('%s','%s','%s')" % (serviceId, sessionId, sessionStr)) def newSessionId(self, reqHandler): "returns a new id" try: self.dbconn.query("LOCK TABLES session") result = self.dbconn.query("SELECT count(sessionId) FROM session;") rows = result.fetchrows() if rows: int(rows[0][0]) finally: self.dbconn.query("UNLOCK TABLES session") return 0 class MySQLImpl(session.CookieSession, MySQLLoader, session.SessionImpl): pass . . . if __name__ == '__main__': ServiceHandler()Run(testHandler, sessionImpl=MySQLImpl)
test: http://www.0x01.com/~thanos/pso/tests/session/cgi/oopath/mysql.py
pso.service.ServiceRequest.mkurl
has been implemented.
PSOCookieSession_Comment
is equivalent to Comment
PSOCookieSession_Domain
is equivalent to Domain
PSOCookieSession_Max-Age
is equivalent to Max-Age
PSOCookieSession_Path
is equivalent to Path
PSOCookieSession_Secure
is equivalent to Secure
PSOCookieSession_Version
is equivalent to Version
PSOCookieSession_expires
is equivalent to expires?... used by netscape et al.
expires
. expire
takes a string date such as "Mon, 12 Nov 2002 13:04:56 GMT", as defines in RFC2068 section 3.3.1 [also RCF822 and RCF1123]
pso
pso
system you can write one request handler that can be used as a cgi, as a script or invoked as a mod_python handler without modification.
serviceRequest.pso()
returns a bridge to the various
request handler implementations. It tries to simplify many typical
web service actions, and abstract them from the server content delivery
system. Methods are offered covering the following areas:
pso
documentation.
If we take our original quick example:
#!/usr/bin/env python2.2
from pso.service import ServiceHandler
def testHandler(serviceRequest):
try:
serviceRequest.pso().session['reloads'] +=1
except:
serviceRequest.pso().session['reloads'] =1
print "Hello World! ~ You reloaded: %(reloads)d times ~ Try Reload !" % serviceRequest.pso().session
if __name__ == '__main__':
ServiceHandler()Run(testHandler)
Some simple changes can make it run as mod_python or as a cgi
#!/usr/bin python2.2 from pso.service import ServiceHandler, OK def handler(serviceRequest): serviceRequest.pso().send_http_header() try: serviceRequest.pso().session['visits'] +=1 except: serviceRequest.pso().session['visits'] =1 print "Hello World! ~ Your visit number: %(visits)d ~ Try Reload !" % serviceRequest.pso()Session) print "session: %s" % serviceRequest.pso().session.__dict__ return OK if __name__ =='__main__': ServiceHandler()Run(handler)The real differences are:
__main__
is not run.
OK
.
sys.stdout
is not available.
This is abstarcted by serviceRequest.pso().write
pso.session
.
Installation:
pso
should be installed using Distutils which comes standard with python 1.6.
and up
$ mkdir ~/public_html/psotest
$ wget http://www.0x01.com/~thanos/pso/dist/current.tgz or for MS lovers: [ http://www.0x01.com/~thanos/pso/dist/current.exe] $ tar zvfx current.tgz
$ cd pso-XX/ $ python2.1 setup.py install --install-purelib=~/public_html/testpso
#.htaccess for testing pso using CGI # # Options ExecCGI directs apache to allow cgi's to be run from this directory. # AddHandler cgi-script .py treat any .py file as a script #SetEnv PSOServiceId MyPSOTest names session cookie as MyPSOtest Options ExecCGI Indexes AddHandler cgi-script .cgi SetEnv PSOServiceId MyPSOTest
#!/usr/bin/env python2.1 # from pso.service import ServiceHandler def testHandler(serviceRequest): print "hello world" if __name__ == '__main__': ServiceHandler().run(testHandler)Now we will set the file permissions, and do the link:
$ chmod a+x test.py $ ln test.py test.cgiand try it from the command line, should give you this:
python:~/public_html/testpso# ./test.cgi set-cookie: SESSION_ID=@60123.0SESSION_ID; content-type: text/html hello world python:~/public_html/testpso#Now lets try it using a browser: http://www.yourhost.com/~yourid/testpso/test.cgi
pso
directory somewhere in the python PATH or to the directory of your request handler.