PKUªC8h”ã‰ééwsgiutils/SessionServer.pyc;ò >ŽAc@sqdZdkZdkZdkZdkZdkZdkZdkZdkZde fd„ƒYZ d„Z dS(sR SessionServer Copyright (c) 2004 Colin Stewart (http://www.owlfish.com/) All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. If you make any bug fixes or feature enhancements please let me know! A Unix daemon server that provides Session persistence. NsServercBs,tZd„Zd„Zd„Zd„ZRS(NcCsM||_||_ti|dƒ|_tidƒ|_|ii dƒdS(Nscs SessionServersServer init function.( saddrsselfsdbfilesanydbmsopensdbsloggings getLoggerslogsinfo(sselfsaddrsdbfile((s;build/bdist.darwin-8.0.1-x86/egg/wsgiutils/SessionServer.pys__init__)s   cCstidƒ|iƒdS(NsStarting to serve.(sloggingsinfosselfsserve(sself((s;build/bdist.darwin-8.0.1-x86/egg/wsgiutils/SessionServer.pys runServer0s cCsKy?tititiƒ}|i|iƒ|idƒt}Wn5t j o)}|i i dt|ƒƒt}nXxÍ|oÅy|iƒ\}}WnMt j oA}|i idt|ƒƒ|iiƒ|iiƒdSnXy|i|ƒWqzt j o;}y(|i idt|ƒƒ|iƒWqBqBXqzXqzWdS(Nis'Unable to start listening on socket: %ss.Exception occured while waiting for a client: s+Error handling client (%s), closing socket.(ssocketsAF_UNIXs SOCK_STREAMs listenSocketsbindsselfsaddrslistensTruesservings ExceptionseslogscriticalsstrsFalsesaccepts connSocketsconnAddrserrorsdbssyncscloses handleClientsinfo(sselfs listenSocketsservingsesconnAddrs connSocket((s;build/bdist.darwin-8.0.1-x86/egg/wsgiutils/SessionServer.pysserve4s2      c Cs d}xö|oîtid|idƒƒd} |i| ƒ}ti|ƒ}|i ƒ}ti ƒ}|djoW|i ƒ}|i ƒ}|iid|ƒ||i|<|iiƒ|idƒnô|djoƒ|i ƒ}|ii|ƒo?|iid |ƒ|i|}|id ƒ|i|ƒq¼|iid |ƒ|id ƒnd|d jo$|iiƒ|idƒd}n3|iid|ƒ|idƒ|id|ƒ|iƒ}tidt|ƒƒ} |i| ƒ|i|ƒq W|iƒdS(Nis!liisSETsSaving session ID %ssOKsGETsLoading session ID %ssFOUNDsSession ID %s not foundsNOTFOUNDsBYEsUnknown command type: sERROR(sservingsstructsunpacks connSocketsrecvsmsgLensrawmsgsxdrlibsUnpackersmsgs unpack_stringsmsgTypesPackersreplymsgskeysvaluesselfslogsinfosdbssyncs pack_stringshas_keyswarns get_bufferspackslenssendallsclose( sselfs connSocketsservingsrawmsgsreplymsgsvaluesmsgTypeskeysmsgsmsgLen((s;build/bdist.darwin-8.0.1-x86/egg/wsgiutils/SessionServer.pys handleClientNsH                  (s__name__s __module__s__init__s runServersserves handleClient(((s;build/bdist.darwin-8.0.1-x86/egg/wsgiutils/SessionServer.pysServer(s   cCsytitƒWnnXdS(N(sossremoves SOCKET_ADDR(((s;build/bdist.darwin-8.0.1-x86/egg/wsgiutils/SessionServer.pys preStartupys( s__doc__sossloggings threadingsQueuessocketsanydbmsxdrlibsstructsobjectsServers preStartup( s preStartupsanydbmsloggingssocketsxdrlibsServersQueues threadingsossstruct((s;build/bdist.darwin-8.0.1-x86/egg/wsgiutils/SessionServer.pys?sHQPK)ˆf3®EDCwsgiutils/__init__.py__version__ = "0.7" PKTªC8®”òŠg:g:wsgiutils/wsgiAdaptor.pyc;ò PWBc@sÄdZdkZdkZdkZdkZdkZdkZdkZdkZdk Z dk Z dk Z dk Z dk Z deifd„ƒYZdefd„ƒYZdefd„ƒYZdS(sO wsgiAdaptor Copyright (c) 2004 Colin Stewart (http://www.owlfish.com/) All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. If you make any bug fixes or feature enhancements please let me know! Provides a basic web environment within a WSGI server. Ns simpleCookiecBs&tZed„Zd„Zd„ZRS(NcCsS||_tidƒ|_|tj otii ||ƒntii |ƒdS(Ns simpleCookie( s digestKeysselfsloggings getLoggerslogs dataToLoadsNonesCookies BaseCookies__init__(sselfs digestKeys dataToLoad((s9build/bdist.darwin-8.0.1-x86/egg/wsgiutils/wsgiAdaptor.pys__init__%s   cCs¾tii||ƒ\}}|itjo||fSnt i |iƒ}|dd!}|d}|i|ƒ|iƒ|jo||fSn+|iid|iƒ|fƒt|fSdS(sŽ Return the value decoded - note that the documentation is wrong and the return value is actuall a tuple of unquotedvalue, originalvalue ii s1Cookie tampering detected key %s expected key %s!N(sCookies SimpleCookies value_decodesselfsavalues unqoutedvaluesdummys digestKeysNoneshmacsnewscoders expectedKeys realValuesupdates hexdigestslogswarn(sselfsavaluesdummys realValuescoders expectedKeys unqoutedvalue((s9build/bdist.darwin-8.0.1-x86/egg/wsgiutils/wsgiAdaptor.pys value_decode-s    cCsm|itjotii||ƒSnti|iƒ}|i |ƒ|i ƒ|}tii||ƒSdS(s Return the value encoded - note that the documentation is wrong and the return value is actuall a tuple of originalvalue, quotedevalue N( sselfs digestKeysNonesCookies SimpleCookies value_encodesavalueshmacsnewscodersupdates hexdigests valuetostore(sselfsavalues valuetostorescoder((s9build/bdist.darwin-8.0.1-x86/egg/wsgiutils/wsgiAdaptor.pys value_encode?s (s__name__s __module__sNones__init__s value_decodes value_encode(((s9build/bdist.darwin-8.0.1-x86/egg/wsgiutils/wsgiAdaptor.pys simpleCookie$s  sRequestcBs†tZd„Zd„Zd„Zd„Zd„Zd„Zd„Zd„Z d d „Z d „Z d „Z d d „Z ed„ZRS(NcCs@t|_t|_t|_t|_d|_d|_d|_g|_ g|_ |d|_ |i ddƒ|_|dd}|id ƒo||d 7}nr||d 7}|dd jo+|d d jo|d|d 7}qn(|d djo|d|d 7}n|ti|i ddƒƒ7}||_dS(Ns text/plains Application returned no content.s500 Internal Server Errors wsgi.errorss PATH_INFOsswsgi.url_schemes://s HTTP_HOSTs SERVER_NAMEshttpss SERVER_PORTs443s:s80s SCRIPT_NAME(sNonesselfssessionsuserspasswords formFieldss contentTypes contentValuesresponsesauthorisationHeaderssredirectHeaderss environments errorStreamsgets relativePathsurlshas_keysurllibsquotes urlPrefix(sselfs environmentsurl((s9build/bdist.darwin-8.0.1-x86/egg/wsgiutils/wsgiAdaptor.pys__init__Ks,          cCs |iSdS(N(sselfs formFields(sself((s9build/bdist.darwin-8.0.1-x86/egg/wsgiutils/wsgiAdaptor.pys getFormFieldsjscCs |iSdS(N(sselfssession(sself((s9build/bdist.darwin-8.0.1-x86/egg/wsgiutils/wsgiAdaptor.pys getSessionmscCs |iSdS(N(sselfsuser(sself((s9build/bdist.darwin-8.0.1-x86/egg/wsgiutils/wsgiAdaptor.pys getUsernamepscCs |iSdS(N(sselfspassword(sself((s9build/bdist.darwin-8.0.1-x86/egg/wsgiutils/wsgiAdaptor.pys getPasswordsscCs |iSdS(N(sselfs errorStream(sself((s9build/bdist.darwin-8.0.1-x86/egg/wsgiutils/wsgiAdaptor.pysgetErrorStreamvscCs |iSdS(N(sselfs relativePath(sself((s9build/bdist.darwin-8.0.1-x86/egg/wsgiutils/wsgiAdaptor.pysgetRelativePathyscCs |iSdS(N(sselfs urlPrefix(sself((s9build/bdist.darwin-8.0.1-x86/egg/wsgiutils/wsgiAdaptor.pys getURLPrefix|ss text/plaincCs||_||_d|_dS(Ns200 OK(s contentValuesselfs contentTypesresponse(sselfs contentValues contentType((s9build/bdist.darwin-8.0.1-x86/egg/wsgiutils/wsgiAdaptor.pys sendContents  cCs'd|_|iidd|fƒdS(Ns401 UnauthorizedsWWW-AuthenticatesBasic realm="%s"(sselfsresponsesauthorisationHeaderssappendsrealm(sselfsrealm((s9build/bdist.darwin-8.0.1-x86/egg/wsgiutils/wsgiAdaptor.pyssendUnauthorisedBasic„s cCs5d|_|iid|fƒd|_d|_dS(Ns 303 See OthersLocations Loading...s text/plain(sselfsresponsesredirectHeaderssappendsnewDestinations contentValues contentType(sselfsnewDestination((s9build/bdist.darwin-8.0.1-x86/egg/wsgiutils/wsgiAdaptor.pyssendSeeOtherRedirectˆs  cCs||_||_||_dS(N(s responseStrsselfsresponses contentValues contentType(sselfs responseStrs contentValues contentType((s9build/bdist.darwin-8.0.1-x86/egg/wsgiutils/wsgiAdaptor.pys sendResponseŽs  c CsH|tjotiitiƒƒ} ntii|ƒ} ti|ƒ}|i dƒo|d}ntiitii | |ƒƒ}tii | |gƒ| jo d|| f} t| ƒ‚nzt|dƒ}|iƒ}Wdy|iƒWnnXXtii|ƒd}tii|}||_||_d|_dS(sñ Returns a tuple of the file found at path as a string and the guessed content type of the file. path - URL Encoded path that points to a file. rootDir - The root directory the path is relative to. If None is specified then use CWD s/is=Attempt to read file %s which is outside of root directory %ssrNs200 OK(srootDirsNonesosspathsabspathsgetcwdsstartDirsurllibsunquotes decodedPaths startswithsjoinsrealPaths commonprefixsmsgsIOErrorsopenstheFilesreadstheFileContentssclosessplitexts fileExtensionsSimpleHTTPServersSimpleHTTPRequestHandlersextensions_maps contentTypesselfs contentValuesresponse( sselfspathsrootDirs decodedPathsrealPaths contentTypestheFiles fileExtensionstheFileContentssstartDirsmsg((s9build/bdist.darwin-8.0.1-x86/egg/wsgiutils/wsgiAdaptor.pyssendFileForPath“s0 !  (s__name__s __module__s__init__s getFormFieldss getSessions getUsernames getPasswordsgetErrorStreamsgetRelativePaths getURLPrefixs sendContentssendUnauthorisedBasicssendSeeOtherRedirects sendResponsesNonessendFileForPath(((s9build/bdist.darwin-8.0.1-x86/egg/wsgiutils/wsgiAdaptor.pysRequestJs            s wsgiAdaptorcBsGtZd„Zd„Zd„Zd„Zd„Zd„Zd„ZRS(NcCsF||_||_||_tidƒ|_hd|i<|_dS(Ns wsgiAdaptorsbasic( s applicationsselfs cookieKeys sessionClientsloggings getLoggerslogsparseBasicAuthorisations authHandlers(sselfs applications cookieKeys sessionClient((s9build/bdist.darwin-8.0.1-x86/egg/wsgiutils/wsgiAdaptor.pys__init__¸s    cCst|ƒSdS(s: Used by sub-classes to define their own Request objects. N(sRequests environment(sselfs environment((s9build/bdist.darwin-8.0.1-x86/egg/wsgiutils/wsgiAdaptor.pys getRequest¿scCs¼|idƒo¤|iidƒ|d}|idƒ}|| iƒ}||d}|i i |t ƒ}|o|||ƒdSq´|iid|ƒ|iddƒdSndSdS( NsHTTP_AUTHORIZATIONsFound authorization header.s iis)Unsupported authorisation method %s used!s501 Not Implementeds!Unsupported authorisation method.(s environmentshas_keysselfslogsdebugs credentialssfindsauthTypeOffsetslowersauthTypesauthCredentialss authHandlerssgetsNones authHandlersrequestserrors sendResponse(sselfsrequests environmentsauthTypes authHandlersauthCredentialss credentialssauthTypeOffset((s9build/bdist.darwin-8.0.1-x86/egg/wsgiutils/wsgiAdaptor.pyshandleAuthorisationÃs  cCsJ|idƒo |d}t|i|ƒ}nt|idƒ}|SdS(Ns HTTP_COOKIEs(s environmentshas_keys cookieValues simpleCookiesselfs cookieKeyscookies(sselfs environmentscookiess cookieValue((s9build/bdist.darwin-8.0.1-x86/egg/wsgiutils/wsgiAdaptor.pys getCookiesØs  cCsiti|ƒ}|idƒ}|d|!}||d}||_ ||_|i i d||fƒdS(Ns:iis:Received via basic authorisation username: %s password: %s( sbase64s decodestringsauthCredentialssuserpasssfindsuserpassOffsetsuserNamespasswordsrequestsusersselfslogsinfo(sselfsrequestsauthCredentialssuserNamesuserpassOffsetsuserpassspassword((s9build/bdist.darwin-8.0.1-x86/egg/wsgiutils/wsgiAdaptor.pysparseBasicAuthorisationâs   cCs#|i|ƒ}|i||ƒo|i||tƒSn|i|ƒ}|i i |ƒ|_ t id|dd|ƒ|_y|ii|ƒWnRtj oF}|iidt|ƒƒ|iddƒ|i|||ƒSnX|i tj o|i i|i ƒn|i|||ƒSdS(Nsfps wsgi.inputsenvirons)Application experienced unhandled error: s500 Internal Server ErrorsInternal application error(sselfs getRequests environmentsrequestshandleAuthorisationsrenderToClientsstart_responsesNones getCookiesscookiess sessionClients getSessionssessionscgis FieldStorages formFieldss applicationsrequestHandlers Exceptionseslogscriticalsstrs sendResponses saveSession(sselfs environmentsstart_responsesesrequestscookies((s9build/bdist.darwin-8.0.1-x86/egg/wsgiutils/wsgiAdaptor.pyswsgiHookëscCsý|idjo |i}n$|idjo |i}ng}|id|ifƒ|idtt|i ƒƒfƒ|t j o4x1|i ƒD]}|id|iƒfƒq’Wn||i|ƒt|i gƒS||i|ƒt|i gƒSdS(Ns401 Unauthorizeds 303 See Others Content-typesContent-lengths Set-Cookie(srequestsresponsesauthorisationHeaderssheaderssredirectHeaderssappends contentTypesstrslens contentValuescookiessNonesvaluesscookies OutputStringsstart_responsesiter(sselfsstart_responsesrequestscookiessheadersscookie((s9build/bdist.darwin-8.0.1-x86/egg/wsgiutils/wsgiAdaptor.pysrenderToClients  "  !( s__name__s __module__s__init__s getRequestshandleAuthorisations getCookiessparseBasicAuthorisationswsgiHooksrenderToClient(((s9build/bdist.darwin-8.0.1-x86/egg/wsgiutils/wsgiAdaptor.pys wsgiAdaptor·s    (s__doc__sCookieshmacsbase64ssocketsxdrlibsstructspicklescgisurllibsossos.pathsSimpleHTTPServersloggings SimpleCookies simpleCookiesobjectsRequests wsgiAdaptor(scgis wsgiAdaptorsloggingsstructsSimpleHTTPServersossbase64sRequestsxdrlibsurllibsCookies simpleCookiespickleshmacssocket((s9build/bdist.darwin-8.0.1-x86/egg/wsgiutils/wsgiAdaptor.pys?s l &mPK\yO2ÕéÉ))wsgiutils/wsgiAdaptor.py""" wsgiAdaptor Copyright (c) 2004 Colin Stewart (http://www.owlfish.com/) All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. If you make any bug fixes or feature enhancements please let me know! Provides a basic web environment within a WSGI server. """ import Cookie, hmac, base64, socket, xdrlib, struct, pickle, cgi, urllib, os, os.path, SimpleHTTPServer import logging class simpleCookie (Cookie.SimpleCookie): def __init__ (self, digestKey, dataToLoad = None): self.digestKey = digestKey self.log = logging.getLogger ("simpleCookie") if (dataToLoad is not None): Cookie.BaseCookie.__init__ (self, dataToLoad) else: Cookie.BaseCookie.__init__ (self) def value_decode (self, avalue): """ Return the value decoded - note that the documentation is wrong and the return value is actuall a tuple of unquotedvalue, originalvalue """ unqoutedvalue, dummy = Cookie.SimpleCookie.value_decode (self, avalue) if (self.digestKey is None): return unqoutedvalue, dummy coder = hmac.new(self.digestKey) expectedKey = unqoutedvalue [0:32] realValue = unqoutedvalue [32:] coder.update (realValue) if (coder.hexdigest() == expectedKey): # Correctly encoded! return realValue, avalue else: self.log.warn ("Cookie tampering detected key %s expected key %s!" % (coder.hexdigest(), expectedKey)) return None, avalue def value_encode (self, avalue): """ Return the value encoded - note that the documentation is wrong and the return value is actuall a tuple of originalvalue, quotedevalue """ if (self.digestKey is None): return Cookie.SimpleCookie.value_encode (self, avalue) coder = hmac.new(self.digestKey) coder.update (avalue) valuetostore = coder.hexdigest() + avalue return Cookie.SimpleCookie.value_encode (self, valuetostore) class Request (object): def __init__ (self, environment): self.session = None self.user = None self.password = None self.formFields = None self.contentType = 'text/plain' self.contentValue = "Application returned no content." self.response = "500 Internal Server Error" self.authorisationHeaders = [] self.redirectHeaders = [] self.errorStream = environment ['wsgi.errors'] self.relativePath = environment.get ('PATH_INFO', "") # Re-construct the URL prefix. url = environment ['wsgi.url_scheme'] + '://' if environment.has_key ('HTTP_HOST'): url += environment ['HTTP_HOST'] else: url += environment ['SERVER_NAME'] if environment ['wsgi.url_scheme'] == 'https': if environment ['SERVER_PORT'] != '443': url += ':' + environment ['SERVER_PORT'] else: if environment ['SERVER_PORT'] != '80': url += ':' + environment ['SERVER_PORT'] url += urllib.quote(environment.get('SCRIPT_NAME','')) self.urlPrefix = url def getFormFields (self): return self.formFields def getSession (self): return self.session def getUsername (self): return self.user def getPassword (self): return self.password def getErrorStream (self): return self.errorStream def getRelativePath (self): return self.relativePath def getURLPrefix (self): return self.urlPrefix def sendContent (self, contentValue, contentType = "text/plain"): self.contentValue = contentValue self.contentType = contentType self.response = "200 OK" def sendUnauthorisedBasic (self, realm): self.response = "401 Unauthorized" self.authorisationHeaders.append (('WWW-Authenticate','Basic realm="%s"' % realm)) def sendSeeOtherRedirect (self, newDestination): self.response = "303 See Other" self.redirectHeaders.append (('Location', newDestination)) self.contentValue = "Loading..." self.contentType = "text/plain" def sendResponse (self, responseStr, contentValue, contentType = "text/plain"): self.response = responseStr self.contentValue = contentValue self.contentType = contentType def sendFileForPath (self, path, rootDir = None): """ Returns a tuple of the file found at path as a string and the guessed content type of the file. path - URL Encoded path that points to a file. rootDir - The root directory the path is relative to. If None is specified then use CWD """ if (rootDir is None): startDir = os.path.abspath (os.getcwd ()) else: startDir = os.path.abspath (rootDir) decodedPath = urllib.unquote (path) if (decodedPath.startswith ('/')): decodedPath = decodedPath [1:] # Build the path and collapse any indirection (../) realPath = os.path.abspath (os.path.join (startDir, decodedPath)) # Check that the path is really underneath the root directory if (os.path.commonprefix ([startDir, realPath]) != startDir): msg = "Attempt to read file %s which is outside of root directory %s" % (realPath, startDir) raise IOError (msg) # Read the file and return it try: theFile = open (realPath, 'r') theFileContents = theFile.read() finally: try: theFile.close() except: pass # Guess the content type. fileExtension = os.path.splitext (realPath)[1] contentType = SimpleHTTPServer.SimpleHTTPRequestHandler.extensions_map [fileExtension] self.contentValue = theFileContents self.contentType = contentType self.response = "200 OK" class wsgiAdaptor (object): def __init__ (self, application, cookieKey, sessionClient): self.application = application self.cookieKey = cookieKey self.sessionClient = sessionClient self.log = logging.getLogger ("wsgiAdaptor") self.authHandlers = {'basic': self.parseBasicAuthorisation} def getRequest (self, environment): """ Used by sub-classes to define their own Request objects. """ return Request (environment) def handleAuthorisation (self, request, environment): # Find authorisation headers and handle them, updating the request object. # If a response is to be immediately sent to the user then return true, otherwise false # Look for authorised users. if (environment.has_key ('HTTP_AUTHORIZATION')): self.log.debug ("Found authorization header.") credentials = environment ['HTTP_AUTHORIZATION'] authTypeOffset = credentials.find (' ') authType = credentials [:authTypeOffset].lower() authCredentials = credentials [authTypeOffset + 1:] authHandler = self.authHandlers.get (authType, None) if (authHandler): authHandler (request, authCredentials) return 0 else: self.log.error ("Unsupported authorisation method %s used!" % authType) # Internal application error. request.sendResponse ("501 Not Implemented", "Unsupported authorisation method.") return 1 return 0 def getCookies (self, environment): # Do we have any cookies? if (environment.has_key ('HTTP_COOKIE')): # Yes we have cookies! cookieValue = environment ['HTTP_COOKIE'] cookies = simpleCookie (self.cookieKey, cookieValue) else: cookies = simpleCookie (self.cookieKey, "") return cookies def parseBasicAuthorisation (self, request, authCredentials): userpass = base64.decodestring (authCredentials) userpassOffset = userpass.find (':') userName = userpass [0:userpassOffset] password = userpass [userpassOffset + 1:] request.user = userName request.password = password self.log.info ("Received via basic authorisation username: %s password: %s" % (userName, password)) def wsgiHook (self, environment, start_response): request = self.getRequest(environment) if (self.handleAuthorisation (request, environment)): return self.renderToClient (start_response, request, None) cookies = self.getCookies (environment) # Get our session request.session = self.sessionClient.getSession (cookies) # And the form parameters request.formFields = cgi.FieldStorage (fp=environment ['wsgi.input'], environ=environment) try: self.application.requestHandler (request) except Exception, e: self.log.critical ("Application experienced unhandled error: " + str (e)) request.sendResponse ("500 Internal Server Error", "Internal application error") return self.renderToClient (start_response, request, cookies) if (request.session is not None): # Persist the session self.sessionClient.saveSession (request.session) return self.renderToClient (start_response, request, cookies) def renderToClient (self, start_response, request, cookies): # Get all the headers if (request.response == "401 Unauthorized"): headers = request.authorisationHeaders elif (request.response == "303 See Other"): headers = request.redirectHeaders else: headers = [] headers.append (('Content-type', request.contentType)) headers.append (('Content-length', str (len (request.contentValue)))) if (cookies is not None): # Add the cookies for cookie in cookies.values(): headers.append (('Set-Cookie', cookie.OutputString())) # Finally start the transaction with wsgi start_response (request.response, headers) # Now return an iterator for the output return iter ([request.contentValue]) # Finally start the transaction with wsgi start_response (request.response, headers) # Now return an iterator for the output return iter ([request.contentValue]) PKUªC8NŸ§ëÄ#Ä#wsgiutils/wsgiServer.pyc;ò /}nCc@s¢dZdkZdkZdkZdkZdkZdkZdkZdkZdk Z dk Z dZ dei fd„ƒYZ deieifd„ƒYZdS(s; wsgiServer Copyright (c) 2004 Colin Stewart (http://www.owlfish.com/) All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. If you make any bug fixes or feature enhancements please let me know! A basic multi-threaded WSGI server. NsÓ Server Error

Server Error

A server error has occurred. Please contact the system administrator for more information. s WSGIHandlercBsStZd„Zd„Zd„Zd„Zd„Zd„Zed„Z d„Z RS( NcGsdS(N((sselfsargs((s8build/bdist.darwin-8.0.1-x86/egg/wsgiutils/wsgiServer.pys log_message3scGsdS(N((sselfsargs((s8build/bdist.darwin-8.0.1-x86/egg/wsgiutils/wsgiServer.pys log_request6sc Csçtid|iƒ\}}} }}}x¨|ii D]š\}} | i |ƒo~| t |ƒ}t |ƒdjo#|i dƒ od|}q—n|idƒo|d }n|}| |||fSq5q5WttttfSdS(Nshttp://dummyhost%sis/iÿÿÿÿ(surlparsesselfspathsprotocolshosts parameterssquerysfragmentsserverswsgiApplicationssappPathsapps startswithslenspathInfosendswiths scriptNamesNone( sselfsprotocols parameterssfragmentspathInfos scriptNameshostsappPathsqueryspathsapp((s8build/bdist.darwin-8.0.1-x86/egg/wsgiutils/wsgiServer.pysgetApp9s( cCsw|iƒ\}}}}| o=|iioti i |ƒdSn|i ddƒdSn|i ||||ƒdS(Ni”sApplication not found.( sselfsgetAppsapps scriptNamespathInfosquerysservers serveFilessSimpleHTTPServersSimpleHTTPRequestHandlersdo_GETs send_errors runWSGIApp(sselfspathInfos scriptNamesquerysapp((s8build/bdist.darwin-8.0.1-x86/egg/wsgiutils/wsgiServer.pysdo_GETLs cCsR|iƒ\}}}}| o|iddƒdSn|i||||ƒdS(Ni”sApplication not found.(sselfsgetAppsapps scriptNamespathInfosquerys send_errors runWSGIApp(sselfspathInfos scriptNamesappsquery((s8build/bdist.darwin-8.0.1-x86/egg/wsgiutils/wsgiServer.pysdo_POSTXs c Csêtid||fƒhdddf<dd<d|i<dti<d d<d d<d d<d |i<d |<d|<d|<d|i i ddƒ<d|i i ddƒ<d|i d<d|i id<dt|i idƒ<d|i<} x=|i iƒD],\} }|| d| iddƒiƒtZdZdd„Zd„Zd„Zd„Zd„ZRS(s‚ The session server client is a multi-thread safe factory class which generates Session objects for use in a web application. icCsS||_||_||_tidƒ|_ti ƒ|_ t |_ |i ƒdS(NsSessionServerClient(ssocketLocationsselfssessionLifeSpanslifeSpans cookieNamesloggings getLoggerslogs threadingsLocks socketLocksNonessessionServerSocketsconnectToServer(sselfssocketLocations cookieNamessessionLifeSpan((s;build/bdist.darwin-8.0.1-x86/egg/wsgiutils/SessionClient.pys__init__ls    cCs8|iiƒyT|itj o@|iidƒ|i}t|_|iƒ|ii dƒnWn/t j o#}|ii dt |ƒƒnXyY|iid|iƒtititiƒ|_|ii|iƒ|iidƒWn8t j o,}|iidt |ƒƒt|_nX|iiƒdS(Ns&Found old socket, attempting to close.sClose succeddeds6Error attempting to close old socket (%s) carrying on.sCAttempting to connect to session server listening on unix socket %ss)Connection to session server established!s'Unable to connect to session server: %s(sselfs socketLocksacquiressessionServerSocketsNoneslogsinfosoldSocksclosesdebugs ExceptionseswarnsstrssocketLocationssocketsAF_UNIXs SOCK_STREAMsconnectserrorsrelease(sselfsesoldSock((s;build/bdist.darwin-8.0.1-x86/egg/wsgiutils/SessionClient.pysconnectToServerus&    c Csît}|i|iƒo(||ii}|iid|ƒn|iid|iƒ|tjo$t ƒ}|||i|ii%d t |ƒƒt ƒ}|||i}|iiƒ|iidt|ƒƒ|iƒdSnXti|ƒ}|i ƒ}|iid|ƒ|d jo|iid ƒn|iid ƒtd ƒ‚dS( NsSETs!lsSending SET message to server.sWaiting for response.iisGError communicating with the session server (%s), trying to re-connect.sResponse is message type: %ssOKsSession saved OK.sError saving session!sError saving session.("sxdrlibsPackersmsgs pack_stringstimessessions lastAccesseds getSessionIDscPicklesdumpss get_buffersstructspackslensmsgLensselfs socketLocksacquireslogsinfossessionServerSocketssendallsunpacksrecvsrawmsgsreleases ExceptionseserrorsstrsconnectToServersUnpackers unpack_stringsmsgType(sselfssessionsesrawmsgsmsgTypesmsgsmsgLen((s;build/bdist.darwin-8.0.1-x86/egg/wsgiutils/SessionClient.pys saveSessionÇs8    "     cCsFtiƒ}|idƒ|iƒ}tidt|ƒƒ}y¸|i i ƒ|i i dƒ|ii|ƒ|ii|ƒ|i i dƒtid|iidƒƒd}|ii|ƒ}|i i dƒ|iiƒt|_|i iƒWnJtj o>}|i iƒ|i idt|ƒƒ|iƒdSnXdS( NsBYEs!lsSending BYE message to server.sWaiting for response.iisClosing socket connection.sGError communicating with the session server (%s), trying to re-connect.(sxdrlibsPackersmsgs pack_strings get_buffersstructspackslensmsgLensselfs socketLocksacquireslogsinfossessionServerSocketssendallsunpacksrecvsrawmsgsclosesNonesreleases ExceptionseserrorsstrsconnectToServer(sselfsesrawmsgsmsgsmsgLen((s;build/bdist.darwin-8.0.1-x86/egg/wsgiutils/SessionClient.pys closeClientës*    "    (s__name__s __module__s__doc__s__init__sconnectToServers getSessions saveSessions closeClient(((s;build/bdist.darwin-8.0.1-x86/egg/wsgiutils/SessionClient.pysSessionServerClienths   < $(s__doc__ssocketsxdrlibsstructscPicklesrandomstimesanydbms threadingsloggingsdictsSessionsgetNewSessionIDsobjectsLocalSessionClientsSessionServerClient( scPicklesanydbmsloggingsstructsrandomsxdrlibsSessionServerClients threadingsSessionstimesLocalSessionClientsgetNewSessionIDssocket((s;build/bdist.darwin-8.0.1-x86/egg/wsgiutils/SessionClient.pys?s6    3PKSg1Ó"ƒƒwsgiutils/SessionServer.py""" SessionServer Copyright (c) 2004 Colin Stewart (http://www.owlfish.com/) All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. If you make any bug fixes or feature enhancements please let me know! A Unix daemon server that provides Session persistence. """ import os, logging, threading, Queue, socket, anydbm, xdrlib, struct # Wire protocol is based on XDR messages. Each message is precedded by a 4 byte length in network byte order. # Client can issue a message of two strings, GET, KEY # OR three strings: SET, KEY, DATA # Server responds with an XDR message of FOUND, DATA or NOTFOUND # For set operation return will be OK or ERROR class Server (object): def __init__ (self, addr, dbfile): self.addr = addr self.dbfile = dbfile self.db = anydbm.open (dbfile, 'c') self.log = logging.getLogger ("SessionServer") self.log.info ("Server init function.") def runServer (self): logging.info ("Starting to serve.") self.serve() def serve (self): try: listenSocket = socket.socket (socket.AF_UNIX, socket.SOCK_STREAM) listenSocket.bind (self.addr) listenSocket.listen(2) serving = True except Exception, e: self.log.critical ("Unable to start listening on socket: %s" % str (e)) serving = False while (serving): try: connSocket, connAddr = listenSocket.accept() except Exception, e: self.log.error ("Exception occured while waiting for a client: " + str (e)) self.db.sync() self.db.close() return try: self.handleClient (connSocket) except Exception, e: try: self.log.info ("Error handling client (%s), closing socket." % str (e)) connSocket.close() except: pass def handleClient (self, connSocket): # Repeated handle incoming messages until the socket goes away. serving = 1 while (serving): # Read the message length msgLen = struct.unpack ('!l', connSocket.recv (4))[0] rawmsg = connSocket.recv (msgLen) msg = xdrlib.Unpacker (rawmsg) msgType = msg.unpack_string() replymsg = xdrlib.Packer() if (msgType == "SET"): key = msg.unpack_string() value = msg.unpack_string() self.log.info ("Saving session ID %s" % key) self.db [key] = value self.db.sync() replymsg.pack_string ("OK") elif (msgType == "GET"): key = msg.unpack_string() if (self.db.has_key (key)): self.log.info ("Loading session ID %s" % key) value = self.db [key] replymsg.pack_string ("FOUND") replymsg.pack_string (value) else: self.log.info ("Session ID %s not found" % key) replymsg.pack_string ("NOTFOUND") elif (msgType == "BYE"): self.db.sync() replymsg.pack_string ("OK") serving = 0 else: self.log.warn ("Unknown command type: " + msgType) replymsg.pack_string ("ERROR") replymsg.pack_string ("Unknown command type: " + msgType) replymsg = replymsg.get_buffer() msgLen = struct.pack ('!l', len (replymsg)) connSocket.sendall (msgLen) connSocket.sendall (replymsg) connSocket.close() def preStartup (): try: os.remove (SOCKET_ADDR) except: # No such file, that's OK. pass PK)ˆf3|BнXXwsgiutils/wsgiServer.py""" wsgiServer Copyright (c) 2004 Colin Stewart (http://www.owlfish.com/) All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. If you make any bug fixes or feature enhancements please let me know! A basic multi-threaded WSGI server. """ import SimpleHTTPServer, SocketServer, BaseHTTPServer, urlparse import sys, logging, socket, errno import traceback, StringIO SERVER_ERROR = """\ Server Error

Server Error

A server error has occurred. Please contact the system administrator for more information. """ class WSGIHandler (SimpleHTTPServer.SimpleHTTPRequestHandler): def log_message (self, *args): pass def log_request (self, *args): pass def getApp (self): protocol, host, path, parameters, query, fragment = urlparse.urlparse ('http://dummyhost%s' % self.path) # Find any application we might have for appPath, app in self.server.wsgiApplications: if (path.startswith (appPath)): # We found the application to use - work out the scriptName and pathInfo pathInfo = path [len (appPath):] if (len (pathInfo) > 0): if (not pathInfo.startswith ('/')): pathInfo = '/' + pathInfo if (appPath.endswith ('/')): scriptName = appPath[:-1] else: scriptName = appPath # Return all this return app, scriptName, pathInfo, query return None, None, None, None def do_GET (self): app, scriptName, pathInfo, query = self.getApp () if (not app): if (self.server.serveFiles): # Not a request for an application, just a file. SimpleHTTPServer.SimpleHTTPRequestHandler.do_GET (self) return self.send_error (404, 'Application not found.') return self.runWSGIApp (app, scriptName, pathInfo, query) def do_POST (self): app, scriptName, pathInfo, query = self.getApp () if (not app): # We don't have an application corresponding to this path! self.send_error (404, 'Application not found.') return self.runWSGIApp (app, scriptName, pathInfo, query) def runWSGIApp (self, application, scriptName, pathInfo, query): logging.info ("Running application with script name %s path %s" % (scriptName, pathInfo)) env = {'wsgi.version': (1,0) ,'wsgi.url_scheme': 'http' ,'wsgi.input': self.rfile ,'wsgi.errors': sys.stderr ,'wsgi.multithread': 1 ,'wsgi.multiprocess': 0 ,'wsgi.run_once': 0 ,'REQUEST_METHOD': self.command ,'SCRIPT_NAME': scriptName ,'PATH_INFO': pathInfo ,'QUERY_STRING': query ,'CONTENT_TYPE': self.headers.get ('Content-Type', '') ,'CONTENT_LENGTH': self.headers.get ('Content-Length', '') ,'REMOTE_ADDR': self.client_address[0] ,'SERVER_NAME': self.server.server_address [0] ,'SERVER_PORT': str (self.server.server_address [1]) ,'SERVER_PROTOCOL': self.request_version } for httpHeader, httpValue in self.headers.items(): env ['HTTP_%s' % httpHeader.replace ('-', '_').upper()] = httpValue # Setup the state self.wsgiSentHeaders = 0 self.wsgiHeaders = [] try: # We have there environment, now invoke the application result = application (env, self.wsgiStartResponse) try: try: for data in result: if data: self.wsgiWriteData (data) finally: if hasattr(result, 'close'): result.close() except socket.error, socketErr: # Catch common network errors and suppress them if (socketErr.args[0] in (errno.ECONNABORTED, errno.EPIPE)): logging.debug ("Network error caught: (%s) %s" % (str (socketErr.args[0]), socketErr.args[1])) # For common network errors we just return return except socket.timeout, socketTimeout: # Socket time-out logging.debug ("Socket timeout") return except: errorMsg = StringIO.StringIO() traceback.print_exc(file=errorMsg) logging.error (errorMsg.getvalue()) if not self.wsgiSentHeaders: self.wsgiStartResponse('500 Server Error', [('Content-type', 'text/html')]) self.wsgiWriteData(SERVER_ERROR) if (not self.wsgiSentHeaders): # We must write out something! self.wsgiWriteData (" ") return def wsgiStartResponse (self, response_status, response_headers, exc_info=None): if (self.wsgiSentHeaders): raise Exception ("Headers already sent and start_response called again!") # Should really take a copy to avoid changes in the application.... self.wsgiHeaders = (response_status, response_headers) return self.wsgiWriteData def wsgiWriteData (self, data): if (not self.wsgiSentHeaders): status, headers = self.wsgiHeaders # Need to send header prior to data statusCode = status [:status.find (' ')] statusMsg = status [status.find (' ') + 1:] self.send_response (int (statusCode), statusMsg) for header, value in headers: self.send_header (header, value) self.end_headers() self.wsgiSentHeaders = 1 # Send the data self.wfile.write (data) class WSGIServer (SocketServer.ThreadingMixIn, BaseHTTPServer.HTTPServer): def __init__ (self, serverAddress, wsgiApplications, serveFiles=1): BaseHTTPServer.HTTPServer.__init__ (self, serverAddress, WSGIHandler) appList = [] for urlPath, wsgiApp in wsgiApplications.items(): appList.append ((urlPath, wsgiApp)) self.wsgiApplications = appList self.serveFiles = serveFiles self.serverShuttingDown = 0 PK««o1Ú¢ø%ø%wsgiutils/SessionClient.py""" SessionClient Copyright (c) 2004 Colin Stewart (http://www.owlfish.com/) All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. If you make any bug fixes or feature enhancements please let me know! Clients that provide Session services. """ import socket, xdrlib, struct, cPickle, random, time import anydbm import threading import logging class Session (dict): def __init__ (self, sessionID): dict.__init__ (self) self.sessionID = sessionID self.lastAccessed = time.time() def getLastAccessed (self): return self.lastAccessed def getSessionID (self): return self.sessionID def getNewSessionID (): return str (random.randint (0, 99000000000)) + str (time.time()) class LocalSessionClient (object): def __init__ (self, dbFileLocation, cookieName, sessionLifeSpan = 3600): self.lifeSpan = sessionLifeSpan self.cookieName = cookieName self.log = logging.getLogger ("LocalSessionClient") self.dbLock = threading.Lock() self.db = anydbm.open (dbFileLocation, 'c') def getSession (self, cookies): cookieValue = None if (cookies.has_key (self.cookieName)): cookieValue = cookies [self.cookieName].value self.log.info ("Found session ID %s" % cookieValue) else: self.log.info ("No %s cookie found." % self.cookieName) # Nothing to load, no session present. if (cookieValue is None): sessID = getNewSessionID () cookies [self.cookieName] = sessID return Session (sessID) self.dbLock.acquire() if (self.db.has_key (cookieValue)): pickledSessionData = self.db [cookieValue] self.dbLock.release() else: self.dbLock.release() self.log.warn ("Session for ID %s was not found!" % str (cookieValue)) sessID = getNewSessionID () cookies [self.cookieName] = sessID return Session(sessID) self.log.info ("Session for ID %s found in db." % str (cookieValue)) sessionData = cPickle.loads (pickledSessionData) if ((time.time() - sessionData.getLastAccessed()) > self.lifeSpan): self.log.info ("Session has expired - cleaning up old data.") sessionData.clear() return sessionData def saveSession (self, session): self.dbLock.acquire() session.lastAccessed = time.time() self.db [session.getSessionID()] = cPickle.dumps (session) self.db.sync() self.dbLock.release() def closeClient (self): self.db.sync() self.db.close() self.db = None class SessionServerClient (object): """ The session server client is a multi-thread safe factory class which generates Session objects for use in a web application. """ def __init__ (self, socketLocation, cookieName, sessionLifeSpan = 3600): self.socketLocation = socketLocation self.lifeSpan = sessionLifeSpan self.cookieName = cookieName self.log = logging.getLogger ("SessionServerClient") self.socketLock = threading.Lock() self.sessionServerSocket = None self.connectToServer() def connectToServer (self): self.socketLock.acquire() try: if (self.sessionServerSocket is not None): self.log.info ("Found old socket, attempting to close.") oldSock = self.sessionServerSocket self.sessionServerSocket = None oldSock.close() self.log.debug ("Close succedded") except Exception, e: self.log.warn ("Error attempting to close old socket (%s) carrying on." % str (e)) try: self.log.info ("Attempting to connect to session server listening on unix socket %s" % self.socketLocation) self.sessionServerSocket = socket.socket (socket.AF_UNIX, socket.SOCK_STREAM) self.sessionServerSocket.connect (self.socketLocation) self.log.info ("Connection to session server established!") except Exception, e: self.log.error ("Unable to connect to session server: %s" % str (e)) self.sessionServerSocket = None self.socketLock.release() def getSession (self, cookies): cookieValue = None if (cookies.has_key (self.cookieName)): cookieValue = cookies [self.cookieName].value self.log.info ("Found session ID %s" % cookieValue) else: self.log.info ("No %s cookie found." % self.cookieName) # Nothing to load, no session present. if (cookieValue is None): sessID = getNewSessionID () cookies [self.cookieName] = sessID return Session (sessID) msg = xdrlib.Packer() msg.pack_string ("GET") msg.pack_string (cookieValue) msg = msg.get_buffer() msgLen = struct.pack ('!l', len (msg)) # Must get the lock at this stage! try: self.socketLock.acquire() self.log.info ("Sending GET message to server.") self.sessionServerSocket.sendall (msgLen) self.sessionServerSocket.sendall (msg) # Get the response self.log.info ("Waiting for response.") msgLen = struct.unpack ('!l', self.sessionServerSocket.recv (4))[0] rawmsg = self.sessionServerSocket.recv (msgLen) # Can now release the lock self.socketLock.release() except Exception, e: # Something went wrong talking to the session server. self.socketLock.release() self.log.error ("Error communicating with the session server (%s), trying to re-connect." % str (e)) self.connectToServer() # Return a new session with the old session ID return Session(cookieValue) msg = xdrlib.Unpacker (rawmsg) msgType = msg.unpack_string() self.log.info ("Response is message type: %s" % msgType) if (msgType == 'NOTFOUND'): self.log.warn ("Session for ID %s was not found!" % str (cookieValue)) sessID = getNewSessionID () cookies [self.cookieName] = sessID return Session(sessID) elif (msgType == 'FOUND'): self.log.info ("Session for ID %s found in server." % str (cookieValue)) pickledSessionData = msg.unpack_string() # The pickled object # Now de-pickle the list of name-value pairs. sessionData = cPickle.loads (pickledSessionData) if ((time.time() - sessionData.getLastAccessed()) > self.lifeSpan): self.log.info ("Session has expired - cleaning up old data.") sessionData.clear() return sessionData else: self.log.error ("Unsupported message command respones from session server: " + str (msgType)) raise Exception ("Unsupported message command respones from session server: " + str (msgType)) def saveSession (self, session): msg = xdrlib.Packer() msg.pack_string ("SET") session.lastAccessed = time.time() msg.pack_string (session.getSessionID()) msg.pack_string (cPickle.dumps (session)) msg = msg.get_buffer() msgLen = struct.pack ('!l', len (msg)) # Must get the lock at this stage! try: self.socketLock.acquire() self.log.info ("Sending SET message to server.") self.sessionServerSocket.sendall (msgLen) self.sessionServerSocket.sendall (msg) # Get the response self.log.info ("Waiting for response.") msgLen = struct.unpack ('!l', self.sessionServerSocket.recv (4))[0] rawmsg = self.sessionServerSocket.recv (msgLen) # Can now release the lock self.socketLock.release() except Exception, e: # Something went wrong talking to the session server. self.socketLock.release() self.log.error ("Error communicating with the session server (%s), trying to re-connect." % str (e)) self.connectToServer() return msg = xdrlib.Unpacker (rawmsg) msgType = msg.unpack_string() self.log.info ("Response is message type: %s" % msgType) if (msgType == 'OK'): self.log.info ("Session saved OK.") else: self.log.error ("Error saving session!") raise Exception ("Error saving session.") def closeClient (self): msg = xdrlib.Packer() msg.pack_string ("BYE") msg = msg.get_buffer() msgLen = struct.pack ('!l', len (msg)) # Must get the lock at this stage! try: self.socketLock.acquire() self.log.info ("Sending BYE message to server.") self.sessionServerSocket.sendall (msgLen) self.sessionServerSocket.sendall (msg) # Get the response self.log.info ("Waiting for response.") msgLen = struct.unpack ('!l', self.sessionServerSocket.recv (4))[0] rawmsg = self.sessionServerSocket.recv (msgLen) self.log.info ("Closing socket connection.") self.sessionServerSocket.close() self.sessionServerSocket = None # Can now release the lock self.socketLock.release() except Exception, e: # Something went wrong talking to the session server. self.socketLock.release() self.log.error ("Error communicating with the session server (%s), trying to re-connect." % str (e)) self.connectToServer() return PKSªC8{ßK´´wsgiutils/__init__.pyc;ò /}nCc@s dZdS(s0.7N(s __version__(s __version__((s6build/bdist.darwin-8.0.1-x86/egg/wsgiutils/__init__.pys?sPKYªC8“×2EGG-INFO/zip-safe PKMªC8ÿ _99EGG-INFO/SOURCES.txtREADME.txt setup.py lib/WSGIUtils.egg-info/PKG-INFO lib/WSGIUtils.egg-info/SOURCES.txt lib/WSGIUtils.egg-info/dependency_links.txt lib/WSGIUtils.egg-info/top_level.txt lib/wsgiutils/SessionClient.py lib/wsgiutils/SessionServer.py lib/wsgiutils/__init__.py lib/wsgiutils/wsgiAdaptor.py lib/wsgiutils/wsgiServer.py PKMªC8“×2EGG-INFO/dependency_links.txt PKMªC8F}+!::EGG-INFO/PKG-INFOMetadata-Version: 1.0 Name: WSGIUtils Version: 0.7 Summary: WSGI Utils are a collection of useful libraries for use in a WSGI environnment. Home-page: http://www.owlfish.com/software/wsgiutils/index.html Author: Colin Stewart Author-email: colin@owlfish.com License: UNKNOWN Description: UNKNOWN Platform: UNKNOWN PKMªC8ˆ:¨N EGG-INFO/top_level.txtwsgiutils PKUªC8h”ã‰éé¤wsgiutils/SessionServer.pycPK)ˆf3®EDC¤"wsgiutils/__init__.pyPKTªC8®”òŠg:g:¤iwsgiutils/wsgiAdaptor.pycPK\yO2ÕéÉ))¤Qwsgiutils/wsgiAdaptor.pyPKUªC8NŸ§ëÄ#Ä#¤[zwsgiutils/wsgiServer.pycPKVªC8o âº11¤Užwsgiutils/SessionClient.pycPKSg1Ó"ƒƒ¤Ðwsgiutils/SessionServer.pyPK)ˆf3|BнXX¤Ùáwsgiutils/wsgiServer.pyPK««o1Ú¢ø%ø%¤füwsgiutils/SessionClient.pyPKSªC8{ßK´´¤–"wsgiutils/__init__.pycPKYªC8“×2¤~#EGG-INFO/zip-safePKMªC8ÿ _99¤®#EGG-INFO/SOURCES.txtPKMªC8“×2¤%EGG-INFO/dependency_links.txtPKMªC8F}+!::¤U%EGG-INFO/PKG-INFOPKMªC8ˆ:¨N ¤¾&EGG-INFO/top_level.txtPKü&