"""A WSGI application interface (see PEP 333)."""importsysimportcherrypyfromcherrypyimport_cpwsgiserverfromcherrypy._cperrorimportformat_exc,bare_errorfromcherrypy.libimporthttpheaderNames={'HTTP_CGI_AUTHORIZATION':'Authorization','CONTENT_LENGTH':'Content-Length','CONTENT_TYPE':'Content-Type','REMOTE_HOST':'Remote-Host','REMOTE_ADDR':'Remote-Addr',}deftranslate_headers(environ):"""Translate CGI-environ header names to HTTP header names."""forcgiNameinenviron:# We assume all incoming header keys are uppercase already.ifcgiNameinheaderNames:yieldheaderNames[cgiName],environ[cgiName]elifcgiName[:5]=="HTTP_":# Hackish attempt at recovering original header names.translatedHeader=cgiName[5:].replace("_","-")yieldtranslatedHeader,environ[cgiName]def_wsgi_callable(environ,start_response,app=None):request=Nonetry:env=environ.getlocal=http.Host('',int(env('SERVER_PORT',80)),env('SERVER_NAME',''))remote=http.Host(env('REMOTE_ADDR',''),int(env('REMOTE_PORT',-1)),env('REMOTE_HOST',''))request=cherrypy.engine.request(local,remote,env('wsgi.url_scheme'))# LOGON_USER is served by IIS, and is the name of the# user after having been mapped to a local account.# Both IIS and Apache set REMOTE_USER, when possible.request.login=env('LOGON_USER')orenv('REMOTE_USER')orNonerequest.multithread=environ['wsgi.multithread']request.multiprocess=environ['wsgi.multiprocess']request.wsgi_environ=environifapp:request.app=apppath=environ.get('SCRIPT_NAME','')+environ.get('PATH_INFO','')response=request.run(environ['REQUEST_METHOD'],path,environ.get('QUERY_STRING'),environ.get('SERVER_PROTOCOL'),translate_headers(environ),environ['wsgi.input'])s,h,b=response.status,response.header_list,response.bodyexc=Noneexcept(KeyboardInterrupt,SystemExit),ex:try:ifrequest:request.close()except:cherrypy.log(traceback=True)request=Noneraiseexexcept:ifcherrypy.config.get("throw_errors",False):raisetb=format_exc()cherrypy.log(tb)ifnotcherrypy.config.get("show_tracebacks",False):tb=""s,h,b=bare_error(tb)exc=sys.exc_info()try:start_response(s,h,exc)forchunkinb:# WSGI requires all data to be of type "str". This coercion should# not take any time at all if chunk is already of type "str".# If it's unicode, it could be a big performance hit (x ~500).ifnotisinstance(chunk,str):chunk=chunk.encode("ISO-8859-1")yieldchunkifrequest:request.close()request=Noneexcept(KeyboardInterrupt,SystemExit),ex:try:ifrequest:request.close()except:cherrypy.log(traceback=True)request=Noneraiseexexcept:cherrypy.log(traceback=True)try:ifrequest:request.close()except:cherrypy.log(traceback=True)request=Nones,h,b=bare_error()# CherryPy test suite expects bare_error body to be output,# so don't call start_response (which, according to PEP 333,# may raise its own error at that point).forchunkinb:ifnotisinstance(chunk,str):chunk=chunk.encode("ISO-8859-1")yieldchunkdefwsgiApp(environ,start_response):"""The WSGI 'application object' for CherryPy. Use this as the same WSGI callable for all your CP apps. """return_wsgi_callable(environ,start_response)defmake_app(app):"""Factory for making separate WSGI 'application objects' for each CP app. Example: # 'app' will be a CherryPy application object app = cherrypy.tree.mount(Root(), "/", localconf) # 'wsgi_app' will be a WSGI application wsgi_app = _cpwsgi.make_app(app) """defsingle_app(environ,start_response):return_wsgi_callable(environ,start_response,app)returnsingle_app# Server components #classCPHTTPRequest(_cpwsgiserver.HTTPRequest):def__init__(self,socket,addr,server):_cpwsgiserver.HTTPRequest.__init__(self,socket,addr,server)mhs=int(cherrypy.config.get('server.max_request_header_size',500*1024))ifmhs>0:self.rfile=http.SizeCheckWrapper(self.rfile,mhs)defparse_request(self):try:_cpwsgiserver.HTTPRequest.parse_request(self)excepthttp.MaxSizeExceeded:msg="Request Entity Too Large"self.wfile.write("%s 413 %s\r\n"%(self.server.protocol,msg))self.wfile.write("Content-Length: %s\r\n\r\n"%len(msg))self.wfile.write(msg)self.wfile.flush()self.ready=Falsecherrypy.log(traceback=True)else:ifself.ready:# Request header is parsedscript_name=self.environ.get('SCRIPT_NAME','')path_info=self.environ.get('PATH_INFO','')path=(script_name+path_info)ifpath=="*":path="global"ifisinstance(self.rfile,http.SizeCheckWrapper):# Unwrap the rfileself.rfile=self.rfile.rfileself.environ["wsgi.input"]=self.rfileclassWSGIServer(_cpwsgiserver.CherryPyWSGIServer):"""Wrapper for _cpwsgiserver.CherryPyWSGIServer. _cpwsgiserver has been designed to not reference CherryPy in any way, so that it can be used in other frameworks and applications. Therefore, we wrap it here, so we can set our own mount points from cherrypy.tree. """RequestHandlerClass=CPHTTPRequestdef__init__(self):conf=cherrypy.config.getsockFile=conf('server.socket_file')ifsockFile:bind_addr=sockFileelse:bind_addr=(conf('server.socket_host'),conf('server.socket_port'))apps=[(base,wsgiApp)forbaseincherrypy.tree.apps]s=_cpwsgiserver.CherryPyWSGIServers.__init__(self,bind_addr,apps,conf('server.thread_pool'),conf('server.socket_host'),request_queue_size=conf('server.socket_queue_size'),timeout=conf('server.socket_timeout'),)s.protocol=conf('server.protocol_version','HTTP/1.0')