PK–jÇ4pçï0KKEGG-INFO/PKG-INFOMetadata-Version: 1.0 Name: wsgiref Version: 0.1 Summary: WSGI (PEP 333) Reference Library Home-page: http://cheeseshop.python.org/pypi/wsgiref Author: Phillip J. Eby Author-email: web-sig@python.org License: PSF or ZPL Description: This is a standalone release of the ``wsgiref`` library to be included in Python 2.5. For the standalone version's documentation, see: HTML http://peak.telecommunity.com/wsgiref_docs/ PDF http://peak.telecommunity.com/wsgiref.pdf Platform: UNKNOWN PK–jÇ4k# WWEGG-INFO/SOURCES.txtREADME.txt setup.cfg setup.py test_wsgiref.py docs/libwsgiref.tex docs/ref.tex ez_setup/README.txt ez_setup/__init__.py wsgiref/__init__.py wsgiref/handlers.py wsgiref/headers.py wsgiref/simple_server.py wsgiref/util.py wsgiref/validate.py wsgiref.egg-info/PKG-INFO wsgiref.egg-info/SOURCES.txt wsgiref.egg-info/top_level.txt PK–jÇ4kã¼ÃEGG-INFO/top_level.txtwsgiref PK–jÇ4EGG-INFO/zip-safePKV†Æ4fg‹Kì<ì<wsgiref/handlers.py"""Base classes for server/gateway implementations""" from types import StringType from util import FileWrapper, guess_scheme, is_hop_by_hop from headers import Headers import sys, os, time __all__ = ['BaseHandler', 'SimpleHandler', 'BaseCGIHandler', 'CGIHandler'] try: dict except NameError: def dict(items): d = {} for k,v in items: d[k] = v return d try: True False except NameError: True = not None False = not True # Weekday and month names for HTTP date/time formatting; always English! _weekdayname = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"] _monthname = [None, # Dummy so we can use 1-based month numbers "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"] def format_date_time(timestamp): year, month, day, hh, mm, ss, wd, y, z = time.gmtime(timestamp) return "%s, %02d %3s %4d %02d:%02d:%02d GMT" % ( _weekdayname[wd], day, _monthname[month], year, hh, mm, ss ) class BaseHandler: """Manage the invocation of a WSGI application""" # Configuration parameters; can override per-subclass or per-instance wsgi_version = (1,0) wsgi_multithread = True wsgi_multiprocess = True wsgi_run_once = False origin_server = True # We are transmitting direct to client http_version = "1.0" # Version that should be used for response server_software = None # String name of server software, if any # os_environ is used to supply configuration from the OS environment: # by default it's a copy of 'os.environ' as of import time, but you can # override this in e.g. your __init__ method. os_environ = dict(os.environ.items()) # Collaborator classes wsgi_file_wrapper = FileWrapper # set to None to disable headers_class = Headers # must be a Headers-like class # Error handling (also per-subclass or per-instance) traceback_limit = None # Print entire traceback to self.get_stderr() error_status = "500 Dude, this is whack!" error_headers = [('Content-Type','text/plain')] error_body = "A server error occurred. Please contact the administrator." # State variables (don't mess with these) status = result = None headers_sent = False headers = None bytes_sent = 0 def run(self, application): """Invoke the application""" # Note to self: don't move the close()! Asynchronous servers shouldn't # call close() from finish_response(), so if you close() anywhere but # the double-error branch here, you'll break asynchronous servers by # prematurely closing. Async servers must return from 'run()' without # closing if there might still be output to iterate over. try: self.setup_environ() self.result = application(self.environ, self.start_response) self.finish_response() except: try: self.handle_error() except: # If we get an error handling an error, just give up already! self.close() raise # ...and let the actual server figure it out. def setup_environ(self): """Set up the environment for one request""" env = self.environ = self.os_environ.copy() self.add_cgi_vars() env['wsgi.input'] = self.get_stdin() env['wsgi.errors'] = self.get_stderr() env['wsgi.version'] = self.wsgi_version env['wsgi.run_once'] = self.wsgi_run_once env['wsgi.url_scheme'] = self.get_scheme() env['wsgi.multithread'] = self.wsgi_multithread env['wsgi.multiprocess'] = self.wsgi_multiprocess if self.wsgi_file_wrapper is not None: env['wsgi.file_wrapper'] = self.wsgi_file_wrapper if self.origin_server and self.server_software: env.setdefault('SERVER_SOFTWARE',self.server_software) def finish_response(self): """Send any iterable data, then close self and the iterable Subclasses intended for use in asynchronous servers will want to redefine this method, such that it sets up callbacks in the event loop to iterate over the data, and to call 'self.close()' once the response is finished. """ if not self.result_is_file() or not self.sendfile(): for data in self.result: self.write(data) self.finish_content() self.close() def get_scheme(self): """Return the URL scheme being used""" return guess_scheme(self.environ) def set_content_length(self): """Compute Content-Length or switch to chunked encoding if possible""" try: blocks = len(self.result) except (TypeError,AttributeError,NotImplementedError): pass else: if blocks==1: self.headers['Content-Length'] = str(self.bytes_sent) return # XXX Try for chunked encoding if origin server and client is 1.1 def cleanup_headers(self): """Make any necessary header changes or defaults Subclasses can extend this to add other defaults. """ if not self.headers.has_key('Content-Length'): self.set_content_length() def start_response(self, status, headers,exc_info=None): """'start_response()' callable as specified by PEP 333""" if exc_info: try: if self.headers_sent: # Re-raise original exception if headers sent raise exc_info[0], exc_info[1], exc_info[2] finally: exc_info = None # avoid dangling circular ref elif self.headers is not None: raise AssertionError("Headers already set!") assert type(status) is StringType,"Status must be a string" assert len(status)>=4,"Status must be at least 4 characters" assert int(status[:3]),"Status message must begin w/3-digit code" assert status[3]==" ", "Status message must have a space after code" if __debug__: for name,val in headers: assert type(name) is StringType,"Header names must be strings" assert type(val) is StringType,"Header values must be strings" assert not is_hop_by_hop(name),"Hop-by-hop headers not allowed" self.status = status self.headers = self.headers_class(headers) return self.write def send_preamble(self): """Transmit version/status/date/server, via self._write()""" if self.origin_server: if self.client_is_modern(): self._write('HTTP/%s %s\r\n' % (self.http_version,self.status)) if not self.headers.has_key('Date'): self._write( 'Date: %s\r\n' % format_date_time(time.time()) ) if self.server_software and not self.headers.has_key('Server'): self._write('Server: %s\r\n' % self.server_software) else: self._write('Status: %s\r\n' % self.status) def write(self, data): """'write()' callable as specified by PEP 333""" assert type(data) is StringType,"write() argument must be string" if not self.status: raise AssertionError("write() before start_response()") elif not self.headers_sent: # Before the first output, send the stored headers self.bytes_sent = len(data) # make sure we know content-length self.send_headers() else: self.bytes_sent += len(data) # XXX check Content-Length and truncate if too many bytes written? self._write(data) self._flush() def sendfile(self): """Platform-specific file transmission Override this method in subclasses to support platform-specific file transmission. It is only called if the application's return iterable ('self.result') is an instance of 'self.wsgi_file_wrapper'. This method should return a true value if it was able to actually transmit the wrapped file-like object using a platform-specific approach. It should return a false value if normal iteration should be used instead. An exception can be raised to indicate that transmission was attempted, but failed. NOTE: this method should call 'self.send_headers()' if 'self.headers_sent' is false and it is going to attempt direct transmission of the file. """ return False # No platform-specific transmission by default def finish_content(self): """Ensure headers and content have both been sent""" if not self.headers_sent: self.headers['Content-Length'] = "0" self.send_headers() else: pass # XXX check if content-length was too short? def close(self): """Close the iterable (if needed) and reset all instance vars Subclasses may want to also drop the client connection. """ try: if hasattr(self.result,'close'): self.result.close() finally: self.result = self.headers = self.status = self.environ = None self.bytes_sent = 0; self.headers_sent = False def send_headers(self): """Transmit headers to the client, via self._write()""" self.cleanup_headers() self.headers_sent = True if not self.origin_server or self.client_is_modern(): self.send_preamble() self._write(str(self.headers)) def result_is_file(self): """True if 'self.result' is an instance of 'self.wsgi_file_wrapper'""" wrapper = self.wsgi_file_wrapper return wrapper is not None and isinstance(self.result,wrapper) def client_is_modern(self): """True if client can accept status and headers""" return self.environ['SERVER_PROTOCOL'].upper() != 'HTTP/0.9' def log_exception(self,exc_info): """Log the 'exc_info' tuple in the server log Subclasses may override to retarget the output or change its format. """ try: from traceback import print_exception stderr = self.get_stderr() print_exception( exc_info[0], exc_info[1], exc_info[2], self.traceback_limit, stderr ) stderr.flush() finally: exc_info = None def handle_error(self): """Log current error, and send error output to client if possible""" self.log_exception(sys.exc_info()) if not self.headers_sent: self.result = self.error_output(self.environ, self.start_response) self.finish_response() # XXX else: attempt advanced recovery techniques for HTML or text? def error_output(self, environ, start_response): """WSGI mini-app to create error output By default, this just uses the 'error_status', 'error_headers', and 'error_body' attributes to generate an output page. It can be overridden in a subclass to dynamically generate diagnostics, choose an appropriate message for the user's preferred language, etc. Note, however, that it's not recommended from a security perspective to spit out diagnostics to any old user; ideally, you should have to do something special to enable diagnostic output, which is why we don't include any here! """ start_response(self.error_status,self.error_headers[:],sys.exc_info()) return [self.error_body] # Pure abstract methods; *must* be overridden in subclasses def _write(self,data): """Override in subclass to buffer data for send to client It's okay if this method actually transmits the data; BaseHandler just separates write and flush operations for greater efficiency when the underlying system actually has such a distinction. """ raise NotImplementedError def _flush(self): """Override in subclass to force sending of recent '_write()' calls It's okay if this method is a no-op (i.e., if '_write()' actually sends the data. """ raise NotImplementedError def get_stdin(self): """Override in subclass to return suitable 'wsgi.input'""" raise NotImplementedError def get_stderr(self): """Override in subclass to return suitable 'wsgi.errors'""" raise NotImplementedError def add_cgi_vars(self): """Override in subclass to insert CGI variables in 'self.environ'""" raise NotImplementedError class SimpleHandler(BaseHandler): """Handler that's just initialized with streams, environment, etc. This handler subclass is intended for synchronous HTTP/1.0 origin servers, and handles sending the entire response output, given the correct inputs. Usage:: handler = SimpleHandler( inp,out,err,env, multithread=False, multiprocess=True ) handler.run(app)""" def __init__(self,stdin,stdout,stderr,environ, multithread=True, multiprocess=False ): self.stdin = stdin self.stdout = stdout self.stderr = stderr self.base_env = environ self.wsgi_multithread = multithread self.wsgi_multiprocess = multiprocess def get_stdin(self): return self.stdin def get_stderr(self): return self.stderr def add_cgi_vars(self): self.environ.update(self.base_env) def _write(self,data): self.stdout.write(data) self._write = self.stdout.write def _flush(self): self.stdout.flush() self._flush = self.stdout.flush class BaseCGIHandler(SimpleHandler): """CGI-like systems using input/output/error streams and environ mapping Usage:: handler = BaseCGIHandler(inp,out,err,env) handler.run(app) This handler class is useful for gateway protocols like ReadyExec and FastCGI, that have usable input/output/error streams and an environment mapping. It's also the base class for CGIHandler, which just uses sys.stdin, os.environ, and so on. The constructor also takes keyword arguments 'multithread' and 'multiprocess' (defaulting to 'True' and 'False' respectively) to control the configuration sent to the application. It sets 'origin_server' to False (to enable CGI-like output), and assumes that 'wsgi.run_once' is False. """ origin_server = False class CGIHandler(BaseCGIHandler): """CGI-based invocation via sys.stdin/stdout/stderr and os.environ Usage:: CGIHandler().run(app) The difference between this class and BaseCGIHandler is that it always uses 'wsgi.run_once' of 'True', 'wsgi.multithread' of 'False', and 'wsgi.multiprocess' of 'True'. It does not take any initialization parameters, but always uses 'sys.stdin', 'os.environ', and friends. If you need to override any of these parameters, use BaseCGIHandler instead. """ wsgi_run_once = True def __init__(self): BaseCGIHandler.__init__( self, sys.stdin, sys.stdout, sys.stderr, dict(os.environ.items()), multithread=False, multiprocess=True ) PK–jÇ4~I/’ L Lwsgiref/handlers.pyc;ò ¤ê…Dc @sgdZdklZdklZlZlZdklZdk Z dk Z dk Z ddddgZ ye Wnej od „Z nXy eeWn!ej oe Ze ZnXd d d d dddgZeddddddddddddg Zd„Zdfd„ƒYZdefd„ƒYZdefd „ƒYZdefd!„ƒYZdS("s/Base classes for server/gateway implementations(s StringType(s FileWrappers guess_schemes is_hop_by_hop(sHeadersNs BaseHandlers SimpleHandlersBaseCGIHandlers CGIHandlercCs/h}x|D]\}}|||Send any iterable data, then close self and the iterable Subclasses intended for use in asynchronous servers will want to redefine this method, such that it sets up callbacks in the event loop to iterate over the data, and to call 'self.close()' once the response is finished. N(sselfsresult_is_filessendfilesresultsdataswritesfinish_contentsclose(sselfsdata((s)build\bdist.win32\egg\wsgiref\handlers.pysfinish_response|s cCst|iƒSdS(s Return the URL scheme being usedN(s guess_schemesselfsenviron(sself((s)build\bdist.win32\egg\wsgiref\handlers.pys get_scheme‹scCsayt|iƒ}Wntttfj on-X|djot|iƒ|i d|i ot|ƒ|_|i ƒn|it|ƒ7_|i |ƒ|i ƒdS(s*'write()' callable as specified by PEP 333swrite() argument must be stringswrite() before start_response()N( stypesdatas StringTypesAssertionErrorsselfsstatuss headers_sentslens bytes_sents send_headerss_writes_flush(sselfsdata((s)build\bdist.win32\egg\wsgiref\handlers.pyswriteÎs   cCstSdS(sPlatform-specific file transmission Override this method in subclasses to support platform-specific file transmission. It is only called if the application's return iterable ('self.result') is an instance of 'self.wsgi_file_wrapper'. This method should return a true value if it was able to actually transmit the wrapped file-like object using a platform-specific approach. It should return a false value if normal iteration should be used instead. An exception can be raised to indicate that transmission was attempted, but failed. NOTE: this method should call 'self.send_headers()' if 'self.headers_sent' is false and it is going to attempt direct transmission of the file. N(sFalse(sself((s)build\bdist.win32\egg\wsgiref\handlers.pyssendfileâscCs*|i od|id<|iƒndS(s.Ensure headers and content have both been sents0sContent-LengthN(sselfs headers_sentsheaderss send_headers(sself((s)build\bdist.win32\egg\wsgiref\handlers.pysfinish_content÷s   cCs`z(t|idƒo|iiƒnWdt|_|_|_|_d|_t |_ XdS(s„Close the iterable (if needed) and reset all instance vars Subclasses may want to also drop the client connection. scloseNi( shasattrsselfsresultsclosesNonesheaderssstatussenvirons bytes_sentsFalses headers_sent(sself((s)build\bdist.win32\egg\wsgiref\handlers.pyscloseÿscCsS|iƒt|_|i p |iƒo$|iƒ|it|i ƒƒndS(s1Transmit headers to the client, via self._write()N( sselfscleanup_headerssTrues headers_sents origin_serversclient_is_moderns send_preambles_writesstrsheaders(sself((s)build\bdist.win32\egg\wsgiref\handlers.pys send_headers s    cCs*|i}|tj ot|i|ƒSdS(s@True if 'self.result' is an instance of 'self.wsgi_file_wrapper'N(sselfswsgi_file_wrapperswrappersNones isinstancesresult(sselfswrapper((s)build\bdist.win32\egg\wsgiref\handlers.pysresult_is_files cCs|idiƒdjSdS(s,True if client can accept status and headerssSERVER_PROTOCOLsHTTP/0.9N(sselfsenvironsupper(sself((s)build\bdist.win32\egg\wsgiref\handlers.pysclient_is_modernscCsZzLdkl}|iƒ}||d|d|d|i|ƒ|iƒWdt}XdS(sLog the 'exc_info' tuple in the server log Subclasses may override to retarget the output or change its format. (sprint_exceptioniiiN( s tracebacksprint_exceptionsselfs get_stderrsstderrsexc_infostraceback_limitsflushsNone(sselfsexc_infosprint_exceptionsstderr((s)build\bdist.win32\egg\wsgiref\handlers.pys log_exception s   cCsK|itiƒƒ|i o)|i|i|iƒ|_|i ƒndS(s>Log current error, and send error output to client if possibleN( sselfs log_exceptionssyssexc_infos headers_sents error_outputsenvironsstart_responsesresultsfinish_response(sself((s)build\bdist.win32\egg\wsgiref\handlers.pys handle_error0s  cCs+||i|itiƒƒ|igSdS(sZWSGI mini-app to create error output By default, this just uses the 'error_status', 'error_headers', and 'error_body' attributes to generate an output page. It can be overridden in a subclass to dynamically generate diagnostics, choose an appropriate message for the user's preferred language, etc. Note, however, that it's not recommended from a security perspective to spit out diagnostics to any old user; ideally, you should have to do something special to enable diagnostic output, which is why we don't include any here! N(sstart_responsesselfs error_statuss error_headersssyssexc_infos error_body(sselfsenvironsstart_response((s)build\bdist.win32\egg\wsgiref\handlers.pys error_output8s cCs t‚dS(sOverride in subclass to buffer data for send to client It's okay if this method actually transmits the data; BaseHandler just separates write and flush operations for greater efficiency when the underlying system actually has such a distinction. N(sNotImplementedError(sselfsdata((s)build\bdist.win32\egg\wsgiref\handlers.pys_writeKscCs t‚dS(s¬Override in subclass to force sending of recent '_write()' calls It's okay if this method is a no-op (i.e., if '_write()' actually sends the data. N(sNotImplementedError(sself((s)build\bdist.win32\egg\wsgiref\handlers.pys_flushTscCs t‚dS(s4Override in subclass to return suitable 'wsgi.input'N(sNotImplementedError(sself((s)build\bdist.win32\egg\wsgiref\handlers.pys get_stdin\scCs t‚dS(s5Override in subclass to return suitable 'wsgi.errors'N(sNotImplementedError(sself((s)build\bdist.win32\egg\wsgiref\handlers.pys get_stderr`scCs t‚dS(s>Override in subclass to insert CGI variables in 'self.environ'N(sNotImplementedError(sself((s)build\bdist.win32\egg\wsgiref\handlers.pys add_cgi_varsds(6s__name__s __module__s__doc__s wsgi_versionsTrueswsgi_multithreadswsgi_multiprocesssFalses wsgi_run_onces origin_servers http_versionsNonesserver_softwaresdictsossenvironsitemss os_environs FileWrapperswsgi_file_wrappersHeaderss headers_classstraceback_limits error_statuss error_headerss error_bodysstatussresults headers_sentsheaderss bytes_sentsruns setup_environsfinish_responses get_schemesset_content_lengthscleanup_headerssstart_responses send_preambleswritessendfilesfinish_contentscloses send_headerssresult_is_filesclient_is_moderns log_exceptions handle_errors error_outputs_writes_flushs get_stdins get_stderrs add_cgi_vars(((s)build\bdist.win32\egg\wsgiref\handlers.pys BaseHandler*sT                     cBsJtZdZeed„Zd„Zd„Zd„Zd„Z d„Z RS(sqHandler that's just initialized with streams, environment, etc. This handler subclass is intended for synchronous HTTP/1.0 origin servers, and handles sending the entire response output, given the correct inputs. Usage:: handler = SimpleHandler( inp,out,err,env, multithread=False, multiprocess=True ) handler.run(app)cCs:||_||_||_||_||_||_ dS(N( sstdinsselfsstdoutsstderrsenvironsbase_envs multithreadswsgi_multithreads multiprocessswsgi_multiprocess(sselfsstdinsstdoutsstderrsenvirons multithreads multiprocess((s)build\bdist.win32\egg\wsgiref\handlers.pys__init__s      cCs |iSdS(N(sselfsstdin(sself((s)build\bdist.win32\egg\wsgiref\handlers.pys get_stdin‰scCs |iSdS(N(sselfsstderr(sself((s)build\bdist.win32\egg\wsgiref\handlers.pys get_stderrŒscCs|ii|iƒdS(N(sselfsenvironsupdatesbase_env(sself((s)build\bdist.win32\egg\wsgiref\handlers.pys add_cgi_varsscCs#|ii|ƒ|ii|_dS(N(sselfsstdoutswritesdatas_write(sselfsdata((s)build\bdist.win32\egg\wsgiref\handlers.pys_write’scCs |iiƒ|ii|_dS(N(sselfsstdoutsflushs_flush(sself((s)build\bdist.win32\egg\wsgiref\handlers.pys_flush–s ( s__name__s __module__s__doc__sTruesFalses__init__s get_stdins get_stderrs add_cgi_varss_writes_flush(((s)build\bdist.win32\egg\wsgiref\handlers.pys SimpleHandlerrs     cBstZdZeZRS(sÚCGI-like systems using input/output/error streams and environ mapping Usage:: handler = BaseCGIHandler(inp,out,err,env) handler.run(app) This handler class is useful for gateway protocols like ReadyExec and FastCGI, that have usable input/output/error streams and an environment mapping. It's also the base class for CGIHandler, which just uses sys.stdin, os.environ, and so on. The constructor also takes keyword arguments 'multithread' and 'multiprocess' (defaulting to 'True' and 'False' respectively) to control the configuration sent to the application. It sets 'origin_server' to False (to enable CGI-like output), and assumes that 'wsgi.run_once' is False. (s__name__s __module__s__doc__sFalses origin_server(((s)build\bdist.win32\egg\wsgiref\handlers.pysBaseCGIHandler›s cBstZdZeZd„ZRS(séCGI-based invocation via sys.stdin/stdout/stderr and os.environ Usage:: CGIHandler().run(app) The difference between this class and BaseCGIHandler is that it always uses 'wsgi.run_once' of 'True', 'wsgi.multithread' of 'False', and 'wsgi.multiprocess' of 'True'. It does not take any initialization parameters, but always uses 'sys.stdin', 'os.environ', and friends. If you need to override any of these parameters, use BaseCGIHandler instead. c CsAti|titititti i ƒƒdt dt ƒdS(Ns multithreads multiprocess( sBaseCGIHandlers__init__sselfssyssstdinsstdoutsstderrsdictsossenvironsitemssFalsesTrue(sself((s)build\bdist.win32\egg\wsgiref\handlers.pys__init__×s-(s__name__s __module__s__doc__sTrues wsgi_run_onces__init__(((s)build\bdist.win32\egg\wsgiref\handlers.pys CGIHandlerÄs (s__doc__stypess StringTypesutils FileWrappers guess_schemes is_hop_by_hopsheaderssHeadersssyssosstimes__all__sdicts NameErrorsTruesFalsesNones _weekdaynames _monthnamesformat_date_times BaseHandlers SimpleHandlersBaseCGIHandlers CGIHandler(s _monthnames StringTypes SimpleHandlersFalses _weekdaynames__all__s is_hop_by_hopsTrues BaseHandlers guess_schemesBaseCGIHandlers FileWrappersHeadersssysstimesdictsossformat_date_times CGIHandler((s)build\bdist.win32\egg\wsgiref\handlers.pys?s.   - ÿI))PK¬mÅ4rQååwsgiref/headers.py"""Manage HTTP Response Headers Much of this module is red-handedly pilfered from email.Message in the stdlib, so portions are Copyright (C) 2001,2002 Python Software Foundation, and were written by Barry Warsaw. """ from types import ListType, TupleType # Regular expression that matches `special' characters in parameters, the # existance of which force quoting of the parameter value. import re tspecials = re.compile(r'[ \(\)<>@,;:\\"/\[\]\?=]') def _formatparam(param, value=None, quote=1): """Convenience function to format and return a key=value pair. This will quote the value if needed or if quote is true. """ if value is not None and len(value) > 0: if quote or tspecials.search(value): value = value.replace('\\', '\\\\').replace('"', r'\"') return '%s="%s"' % (param, value) else: return '%s=%s' % (param, value) else: return param class Headers: """Manage a collection of HTTP response headers""" def __init__(self,headers): if type(headers) is not ListType: raise TypeError("Headers must be a list of name/value tuples") self._headers = headers def __len__(self): """Return the total number of headers, including duplicates.""" return len(self._headers) def __setitem__(self, name, val): """Set the value of a header.""" del self[name] self._headers.append((name, val)) def __delitem__(self,name): """Delete all occurrences of a header, if present. Does *not* raise an exception if the header is missing. """ name = name.lower() self._headers[:] = [kv for kv in self._headers if kv[0].lower()<>name] def __getitem__(self,name): """Get the first header value for 'name' Return None if the header is missing instead of raising an exception. Note that if the header appeared multiple times, the first exactly which occurrance gets returned is undefined. Use getall() to get all the values matching a header field name. """ return self.get(name) def has_key(self, name): """Return true if the message contains the header.""" return self.get(name) is not None __contains__ = has_key def get_all(self, name): """Return a list of all the values for the named field. These will be sorted in the order they appeared in the original header list or were added to this instance, and may contain duplicates. Any fields deleted and re-inserted are always appended to the header list. If no fields exist with the given name, returns an empty list. """ name = name.lower() return [kv[1] for kv in self._headers if kv[0].lower()==name] def get(self,name,default=None): """Get the first header value for 'name', or return 'default'""" name = name.lower() for k,v in self._headers: if k.lower()==name: return v return default def keys(self): """Return a list of all the header field names. These will be sorted in the order they appeared in the original header list, or were added to this instance, and may contain duplicates. Any fields deleted and re-inserted are always appended to the header list. """ return [k for k, v in self._headers] def values(self): """Return a list of all header values. These will be sorted in the order they appeared in the original header list, or were added to this instance, and may contain duplicates. Any fields deleted and re-inserted are always appended to the header list. """ return [v for k, v in self._headers] def items(self): """Get all the header fields and values. These will be sorted in the order they were in the original header list, or were added to this instance, and may contain duplicates. Any fields deleted and re-inserted are always appended to the header list. """ return self._headers[:] def __repr__(self): return "Headers(%s)" % `self._headers` def __str__(self): """str() returns the formatted headers, complete with end line, suitable for direct HTTP transmission.""" return '\r\n'.join(["%s: %s" % kv for kv in self._headers]+['','']) def setdefault(self,name,value): """Return first matching header value for 'name', or 'value' If there is no header named 'name', add a new header with name 'name' and value 'value'.""" result = self.get(name) if result is None: self._headers.append((name,value)) return value else: return result def add_header(self, _name, _value, **_params): """Extended header setting. _name is the header field to add. keyword arguments can be used to set additional parameters for the header field, with underscores converted to dashes. Normally the parameter will be added as key="value" unless value is None, in which case only the key will be added. Example: h.add_header('content-disposition', 'attachment', filename='bud.gif') Note that unlike the corresponding 'email.Message' method, this does *not* handle '(charset, language, value)' tuples: all values must be strings or None. """ parts = [] if _value is not None: parts.append(_value) for k, v in _params.items(): if v is None: parts.append(k.replace('_', '-')) else: parts.append(_formatparam(k.replace('_', '-'), v)) self._headers.append((_name, "; ".join(parts))) PK–jÇ4"S”o""wsgiref/headers.pyc;ò µm„Dc@sWdZdklZlZdkZeidƒZedd„Zdfd„ƒYZ dS(sÓManage HTTP Response Headers Much of this module is red-handedly pilfered from email.Message in the stdlib, so portions are Copyright (C) 2001,2002 Python Software Foundation, and were written by Barry Warsaw. (sListTypes TupleTypeNs[ \(\)<>@,;:\\"/\[\]\?=]icCs|tj ot|ƒdjoY|p ti|ƒo0|iddƒiddƒ}d||fSq}d||fSn|SdS( s~Convenience function to format and return a key=value pair. This will quote the value if needed or if quote is true. is\s\\s"s\"s%s="%s"s%s=%sN(svaluesNoneslensquotes tspecialsssearchsreplacesparam(sparamsvaluesquote((s(build\bdist.win32\egg\wsgiref\headers.pys _formatparams sHeaderscBsžtZdZd„Zd„Zd„Zd„Zd„Zd„ZeZ d„Z e d„Z d „Z d „Zd „Zd „Zd „Zd„Zd„ZRS(s,Manage a collection of HTTP response headerscCs0t|ƒtj otdƒ‚n||_dS(Ns+Headers must be a list of name/value tuples(stypesheaderssListTypes TypeErrorsselfs_headers(sselfsheaders((s(build\bdist.win32\egg\wsgiref\headers.pys__init__.scCst|iƒSdS(s9Return the total number of headers, including duplicates.N(slensselfs_headers(sself((s(build\bdist.win32\egg\wsgiref\headers.pys__len__3scCs!||=|ii||fƒdS(sSet the value of a header.N(sselfsnames_headerssappendsval(sselfsnamesval((s(build\bdist.win32\egg\wsgiref\headers.pys __setitem__7scCsY|iƒ}gi}|iD]+}|diƒ|jo||ƒqq~|i(dS(syDelete all occurrences of a header, if present. Does *not* raise an exception if the header is missing. iN(snameslowersappends_[1]sselfs_headersskv(sselfsnames_[1]skv((s(build\bdist.win32\egg\wsgiref\headers.pys __delitem__<s cCs|i|ƒSdS(sHGet the first header value for 'name' Return None if the header is missing instead of raising an exception. Note that if the header appeared multiple times, the first exactly which occurrance gets returned is undefined. Use getall() to get all the values matching a header field name. N(sselfsgetsname(sselfsname((s(build\bdist.win32\egg\wsgiref\headers.pys __getitem__DscCs|i|ƒtj SdS(s/Return true if the message contains the header.N(sselfsgetsnamesNone(sselfsname((s(build\bdist.win32\egg\wsgiref\headers.pyshas_keySscCsW|iƒ}gi}|iD]/}|diƒ|jo||dƒqq~SdS(sqReturn a list of all the values for the named field. These will be sorted in the order they appeared in the original header list or were added to this instance, and may contain duplicates. Any fields deleted and re-inserted are always appended to the header list. If no fields exist with the given name, returns an empty list. iiN(snameslowersappends_[1]sselfs_headersskv(sselfsnames_[1]skv((s(build\bdist.win32\egg\wsgiref\headers.pysget_allZs cCsI|iƒ}x2|iD]'\}}|iƒ|jo|SqqW|SdS(s:Get the first header value for 'name', or return 'default'N(snameslowersselfs_headerssksvsdefault(sselfsnamesdefaultsksv((s(build\bdist.win32\egg\wsgiref\headers.pysgetfs   cCs2gi}|iD]\}}||ƒq~SdS(s*Return a list of all the header field names. These will be sorted in the order they appeared in the original header list, or were added to this instance, and may contain duplicates. Any fields deleted and re-inserted are always appended to the header list. N(sappends_[1]sselfs_headerssksv(sselfs_[1]sksv((s(build\bdist.win32\egg\wsgiref\headers.pyskeysoscCs2gi}|iD]\}}||ƒq~SdS(s!Return a list of all header values. These will be sorted in the order they appeared in the original header list, or were added to this instance, and may contain duplicates. Any fields deleted and re-inserted are always appended to the header list. N(sappends_[1]sselfs_headerssksv(sselfs_[1]sksv((s(build\bdist.win32\egg\wsgiref\headers.pysvalues|scCs |iSdS(sGet all the header fields and values. These will be sorted in the order they were in the original header list, or were added to this instance, and may contain duplicates. Any fields deleted and re-inserted are always appended to the header list. N(sselfs_headers(sself((s(build\bdist.win32\egg\wsgiref\headers.pysitems†scCsd|i SdS(Ns Headers(%s)(sselfs_headers(sself((s(build\bdist.win32\egg\wsgiref\headers.pys__repr__scCsCdigi}|iD]}|d|ƒq~ddgƒSdS(skstr() returns the formatted headers, complete with end line, suitable for direct HTTP transmission.s s%s: %ssN(sjoinsappends_[1]sselfs_headersskv(sselfs_[1]skv((s(build\bdist.win32\egg\wsgiref\headers.pys__str__“scCsB|i|ƒ}|tjo|ii||fƒ|Sn|SdS(s£Return first matching header value for 'name', or 'value' If there is no header named 'name', add a new header with name 'name' and value 'value'.N(sselfsgetsnamesresultsNones_headerssappendsvalue(sselfsnamesvaluesresult((s(build\bdist.win32\egg\wsgiref\headers.pys setdefault˜s  cKs°g}|tj o|i|ƒnxf|iƒD]X\}}|tjo|i|iddƒƒq1|it |iddƒ|ƒƒq1W|i i|di |ƒfƒdS(sfExtended header setting. _name is the header field to add. keyword arguments can be used to set additional parameters for the header field, with underscores converted to dashes. Normally the parameter will be added as key="value" unless value is None, in which case only the key will be added. Example: h.add_header('content-disposition', 'attachment', filename='bud.gif') Note that unlike the corresponding 'email.Message' method, this does *not* handle '(charset, language, value)' tuples: all values must be strings or None. s_s-s; N(spartss_valuesNonesappends_paramssitemssksvsreplaces _formatparamsselfs_headerss_namesjoin(sselfs_names_values_paramsspartssvsk((s(build\bdist.win32\egg\wsgiref\headers.pys add_header¥s   &(s__name__s __module__s__doc__s__init__s__len__s __setitem__s __delitem__s __getitem__shas_keys __contains__sget_allsNonesgetskeyssvaluessitemss__repr__s__str__s setdefaults add_header(((s(build\bdist.win32\egg\wsgiref\headers.pysHeaders*s"          ( s__doc__stypessListTypes TupleTypesrescompiles tspecialssNones _formatparamsHeaders(sHeaderssres tspecialssListTypes TupleTypes _formatparam((s(build\bdist.win32\egg\wsgiref\headers.pys?s  PK‚sÅ4¡ÖÓÓwsgiref/simple_server.py"""BaseHTTPServer that implements the Python WSGI protocol (PEP 333, rev 1.21) This is both an example of how WSGI can be implemented, and a basis for running simple web applications on a local machine, such as might be done when testing or debugging an application. It has not been reviewed for security issues, however, and we strongly recommend that you use a "real" web server for production use. For example usage, see the 'if __name__=="__main__"' block at the end of the module. See also the BaseHTTPServer module docs for other API information. """ from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer import urllib, sys from wsgiref.handlers import SimpleHandler __version__ = "0.1" __all__ = ['WSGIServer', 'WSGIRequestHandler', 'demo_app', 'make_server'] server_version = "WSGIServer/" + __version__ sys_version = "Python/" + sys.version.split()[0] software_version = server_version + ' ' + sys_version class ServerHandler(SimpleHandler): server_software = software_version def close(self): try: self.request_handler.log_request( self.status.split(' ',1)[0], self.bytes_sent ) finally: SimpleHandler.close(self) class WSGIServer(HTTPServer): """BaseHTTPServer that implements the Python WSGI protocol""" application = None def server_bind(self): """Override server_bind to store the server name.""" HTTPServer.server_bind(self) self.setup_environ() def setup_environ(self): # Set up base environment env = self.base_environ = {} env['SERVER_NAME'] = self.server_name env['GATEWAY_INTERFACE'] = 'CGI/1.1' env['SERVER_PORT'] = str(self.server_port) env['REMOTE_HOST']='' env['CONTENT_LENGTH']='' env['SCRIPT_NAME'] = '' def get_app(self): return self.application def set_app(self,application): self.application = application class WSGIRequestHandler(BaseHTTPRequestHandler): server_version = "WSGIServer/" + __version__ def get_environ(self): env = self.server.base_environ.copy() env['SERVER_PROTOCOL'] = self.request_version env['REQUEST_METHOD'] = self.command if '?' in self.path: path,query = self.path.split('?',1) else: path,query = self.path,'' env['PATH_INFO'] = urllib.unquote(path) env['QUERY_STRING'] = query host = self.address_string() if host != self.client_address[0]: env['REMOTE_HOST'] = host env['REMOTE_ADDR'] = self.client_address[0] if self.headers.typeheader is None: env['CONTENT_TYPE'] = self.headers.type else: env['CONTENT_TYPE'] = self.headers.typeheader length = self.headers.getheader('content-length') if length: env['CONTENT_LENGTH'] = length for h in self.headers.headers: k,v = h.split(':',1) k=k.replace('-','_').upper(); v=v.strip() if k in env: continue # skip content length, type,etc. if 'HTTP_'+k in env: env['HTTP_'+k] += ','+v # comma-separate multiple headers else: env['HTTP_'+k] = v return env def get_stderr(self): return sys.stderr def handle(self): """Handle a single HTTP request""" self.raw_requestline = self.rfile.readline() if not self.parse_request(): # An error code has been sent, just exit return handler = ServerHandler( self.rfile, self.wfile, self.get_stderr(), self.get_environ() ) handler.request_handler = self # backpointer for logging handler.run(self.server.get_app()) def demo_app(environ,start_response): from StringIO import StringIO stdout = StringIO() print >>stdout, "Hello world!" print >>stdout h = environ.items(); h.sort() for k,v in h: print >>stdout, k,'=',`v` start_response("200 OK", [('Content-Type','text/plain')]) return [stdout.getvalue()] def make_server( host, port, app, server_class=WSGIServer, handler_class=WSGIRequestHandler ): """Create a new WSGI server listening on `host` and `port` for `app`""" server = server_class((host, port), handler_class) server.set_app(app) return server if __name__ == '__main__': server_address = ('', 8000) httpd = make_server('', 8000, demo_app) sa = httpd.socket.getsockname() print "Serving HTTP on", sa[0], "port", sa[1], "..." import webbrowser webbrowser.open('http://localhost:8000/xyz?abc') httpd.handle_request() # serve one request, then exit PK–jÇ4ît—†WWwsgiref/simple_server.pyc;ò µw„Dc@sXdZdklZlZdkZdkZdklZdZddddgZ d eZ d ei i ƒd Z e d e Zd efd„ƒYZdefd„ƒYZdefd„ƒYZd„Zeed„ZedjonddfZeddeƒZeiiƒZdGed GdGedGdGHdkZeidƒeiƒndS(s*BaseHTTPServer that implements the Python WSGI protocol (PEP 333, rev 1.21) This is both an example of how WSGI can be implemented, and a basis for running simple web applications on a local machine, such as might be done when testing or debugging an application. It has not been reviewed for security issues, however, and we strongly recommend that you use a "real" web server for production use. For example usage, see the 'if __name__=="__main__"' block at the end of the module. See also the BaseHTTPServer module docs for other API information. (sBaseHTTPRequestHandlers HTTPServerN(s SimpleHandlers0.1s WSGIServersWSGIRequestHandlersdemo_apps make_servers WSGIServer/sPython/is s ServerHandlercBstZeZd„ZRS(NcCsBz-|ii|iiddƒd|iƒWdti|ƒXdS(Ns ii(sselfsrequest_handlers log_requestsstatusssplits bytes_sents SimpleHandlersclose(sself((s.build\bdist.win32\egg\wsgiref\simple_server.pyscloses-(s__name__s __module__ssoftware_versionsserver_softwaresclose(((s.build\bdist.win32\egg\wsgiref\simple_server.pys ServerHandlerscBs8tZdZeZd„Zd„Zd„Zd„ZRS(s7BaseHTTPServer that implements the Python WSGI protocolcCsti|ƒ|iƒdS(s.Override server_bind to store the server name.N(s HTTPServers server_bindsselfs setup_environ(sself((s.build\bdist.win32\egg\wsgiref\simple_server.pys server_bind0s cCsYh}|_|i|d'.'] name = path_parts[1] del path_parts[1] script_name = environ.get('SCRIPT_NAME','') script_name = posixpath.normpath(script_name+'/'+name) if script_name.endswith('/'): script_name = script_name[:-1] if not name and not script_name.endswith('/'): script_name += '/' environ['SCRIPT_NAME'] = script_name environ['PATH_INFO'] = '/'.join(path_parts) # Special case: '/.' on PATH_INFO doesn't get stripped, # because we don't strip the last element of PATH_INFO # if there's only one path part left. Instead of fixing this # above, we fix it here so that PATH_INFO gets normalized to # an empty string in the environ. if name=='.': name = None return name def setup_testing_defaults(environ): """Update 'environ' with trivial defaults for testing purposes This adds various parameters required for WSGI, including HTTP_HOST, SERVER_NAME, SERVER_PORT, REQUEST_METHOD, SCRIPT_NAME, PATH_INFO, and all of the wsgi.* variables. It only supplies default values, and does not replace any existing settings for these variables. This routine is intended to make it easier for unit tests of WSGI servers and applications to set up dummy environments. It should *not* be used by actual WSGI servers or applications, since the data is fake! """ environ.setdefault('SERVER_NAME','127.0.0.1') environ.setdefault('SERVER_PROTOCOL','HTTP/1.0') environ.setdefault('HTTP_HOST',environ['SERVER_NAME']) environ.setdefault('REQUEST_METHOD','GET') if 'SCRIPT_NAME' not in environ and 'PATH_INFO' not in environ: environ.setdefault('SCRIPT_NAME','') environ.setdefault('PATH_INFO','/') environ.setdefault('wsgi.version', (1,0)) environ.setdefault('wsgi.run_once', 0) environ.setdefault('wsgi.multithread', 0) environ.setdefault('wsgi.multiprocess', 0) from StringIO import StringIO environ.setdefault('wsgi.input', StringIO("")) environ.setdefault('wsgi.errors', StringIO()) environ.setdefault('wsgi.url_scheme',guess_scheme(environ)) if environ['wsgi.url_scheme']=='http': environ.setdefault('SERVER_PORT', '80') elif environ['wsgi.url_scheme']=='https': environ.setdefault('SERVER_PORT', '443') _hoppish = { 'connection':1, 'keep-alive':1, 'proxy-authenticate':1, 'proxy-authorization':1, 'te':1, 'trailers':1, 'transfer-encoding':1, 'upgrade':1 }.has_key def is_hop_by_hop(header_name): """Return true if 'header_name' is an HTTP/1.1 "Hop-by-Hop" header""" return _hoppish(header_name.lower()) PK–jÇ4Cðœ…[[wsgiref/util.pyc;ò ›„Dc@sÈdZdkZddddddgZdfd„ƒYZd „Zd „Zd d „Zd „Zd„Zhdd <dd <dd <dd <dd <dd <dd <dd  100). * That the headers is a list (not a subclass, not another kind of sequence). * That the items of the headers are tuples of strings. * That there is no 'status' header (that is used in CGI, but not in WSGI). * That the headers don't contain newlines or colons, end in _ or -, or contain characters codes below 037. * That Content-Type is given if there is content (CGI often has a default content type, but WSGI does not). * That no Content-Type is given when there is no content (@@: is this too restrictive?) * That the exc_info argument to start_response is a tuple or None. * That all calls to the writer are with strings, and no other methods on the writer are accessed. * That wsgi.input is used properly: - .read() is called with zero or one argument - That it returns a string - That readline, readlines, and __iter__ return strings - That .close() is not called - No other methods are provided * That wsgi.errors is used properly: - .write() and .writelines() is called with a string - That .close() is not called, and no other methods are provided. * The response iterator: - That it is not a string (it should be a list of a single string; a string will work, but perform horribly). - That .next() returns a string - That the iterator is not iterated over until start_response has been called (that can signal either a server or application error). - That .close() is called (doesn't raise exception, only prints to sys.stderr, because we only know it isn't called when the object is garbage collected). """ __all__ = ['validator'] import re import sys from types import DictType, StringType, TupleType, ListType import warnings header_re = re.compile(r'^[a-zA-Z][a-zA-Z0-9\-_]*$') bad_header_value_re = re.compile(r'[\000-\037]') class WSGIWarning(Warning): """ Raised in response to WSGI-spec-related warnings """ def validator(application): """ When applied between a WSGI server and a WSGI application, this middleware will check for WSGI compliancy on a number of levels. This middleware does not modify the request or response in any way, but will throw an AssertionError if anything seems off (except for a failure to close the application iterator, which will be printed to stderr -- there's no way to throw an exception at that point). """ def lint_app(*args, **kw): assert len(args) == 2, "Two arguments required" assert not kw, "No keyword arguments allowed" environ, start_response = args check_environ(environ) # We use this to check if the application returns without # calling start_response: start_response_started = [] def start_response_wrapper(*args, **kw): assert len(args) == 2 or len(args) == 3, ( "Invalid number of arguments: %s" % args) assert not kw, "No keyword arguments allowed" status = args[0] headers = args[1] if len(args) == 3: exc_info = args[2] else: exc_info = None check_status(status) check_headers(headers) check_content_type(status, headers) check_exc_info(exc_info) start_response_started.append(None) return WriteWrapper(start_response(*args)) environ['wsgi.input'] = InputWrapper(environ['wsgi.input']) environ['wsgi.errors'] = ErrorWrapper(environ['wsgi.errors']) iterator = application(environ, start_response_wrapper) assert iterator is not None and iterator != False, ( "The application must return an iterator, if only an empty list") check_iterator(iterator) return IteratorWrapper(iterator, start_response_started) return lint_app class InputWrapper: def __init__(self, wsgi_input): self.input = wsgi_input def read(self, *args): assert len(args) <= 1 v = self.input.read(*args) assert type(v) is type("") return v def readline(self): v = self.input.readline() assert type(v) is type("") return v def readlines(self, *args): assert len(args) <= 1 lines = self.input.readlines(*args) assert type(lines) is type([]) for line in lines: assert type(line) is type("") return lines def __iter__(self): while 1: line = self.readline() if not line: return yield line def close(self): assert 0, "input.close() must not be called" class ErrorWrapper: def __init__(self, wsgi_errors): self.errors = wsgi_errors def write(self, s): assert type(s) is type("") self.errors.write(s) def flush(self): self.errors.flush() def writelines(self, seq): for line in seq: self.write(line) def close(self): assert 0, "errors.close() must not be called" class WriteWrapper: def __init__(self, wsgi_writer): self.writer = wsgi_writer def __call__(self, s): assert type(s) is type("") self.writer(s) class PartialIteratorWrapper: def __init__(self, wsgi_iterator): self.iterator = wsgi_iterator def __iter__(self): # We want to make sure __iter__ is called return IteratorWrapper(self.iterator) class IteratorWrapper: def __init__(self, wsgi_iterator, check_start_response): self.original_iterator = wsgi_iterator self.iterator = iter(wsgi_iterator) self.closed = False self.check_start_response = check_start_response def __iter__(self): return self def next(self): assert not self.closed, ( "Iterator read after closed") v = self.iterator.next() if self.check_start_response is not None: assert self.check_start_response, ( "The application returns and we started iterating over its body, but start_response has not yet been called") self.check_start_response = None return v def close(self): self.closed = True if hasattr(self.original_iterator, 'close'): self.original_iterator.close() def __del__(self): if not self.closed: sys.stderr.write( "Iterator garbage collected without being closed") assert self.closed, ( "Iterator garbage collected without being closed") def check_environ(environ): assert type(environ) is DictType, ( "Environment is not of the right type: %r (environment: %r)" % (type(environ), environ)) for key in ['REQUEST_METHOD', 'SERVER_NAME', 'SERVER_PORT', 'wsgi.version', 'wsgi.input', 'wsgi.errors', 'wsgi.multithread', 'wsgi.multiprocess', 'wsgi.run_once']: assert key in environ, ( "Environment missing required key: %r" % key) for key in ['HTTP_CONTENT_TYPE', 'HTTP_CONTENT_LENGTH']: assert key not in environ, ( "Environment should not have the key: %s " "(use %s instead)" % (key, key[5:])) if 'QUERY_STRING' not in environ: warnings.warn( 'QUERY_STRING is not in the WSGI environment; the cgi ' 'module will use sys.argv when this variable is missing, ' 'so application errors are more likely', WSGIWarning) for key in environ.keys(): if '.' in key: # Extension, we don't care about its type continue assert type(environ[key]) is StringType, ( "Environmental variable %s is not a string: %r (value: %r)" % (type(environ[key]), environ[key])) assert type(environ['wsgi.version']) is TupleType, ( "wsgi.version should be a tuple (%r)" % environ['wsgi.version']) assert environ['wsgi.url_scheme'] in ('http', 'https'), ( "wsgi.url_scheme unknown: %r" % environ['wsgi.url_scheme']) check_input(environ['wsgi.input']) check_errors(environ['wsgi.errors']) # @@: these need filling out: if environ['REQUEST_METHOD'] not in ( 'GET', 'HEAD', 'POST', 'OPTIONS','PUT','DELETE','TRACE'): warnings.warn( "Unknown REQUEST_METHOD: %r" % environ['REQUEST_METHOD'], WSGIWarning) assert (not environ.get('SCRIPT_NAME') or environ['SCRIPT_NAME'].startswith('/')), ( "SCRIPT_NAME doesn't start with /: %r" % environ['SCRIPT_NAME']) assert (not environ.get('PATH_INFO') or environ['PATH_INFO'].startswith('/')), ( "PATH_INFO doesn't start with /: %r" % environ['PATH_INFO']) if environ.get('CONTENT_LENGTH'): assert int(environ['CONTENT_LENGTH']) >= 0, ( "Invalid CONTENT_LENGTH: %r" % environ['CONTENT_LENGTH']) if not environ.get('SCRIPT_NAME'): assert environ.has_key('PATH_INFO'), ( "One of SCRIPT_NAME or PATH_INFO are required (PATH_INFO " "should at least be '/' if SCRIPT_NAME is empty)") assert environ.get('SCRIPT_NAME') != '/', ( "SCRIPT_NAME cannot be '/'; it should instead be '', and " "PATH_INFO should be '/'") def check_input(wsgi_input): for attr in ['read', 'readline', 'readlines', '__iter__']: assert hasattr(wsgi_input, attr), ( "wsgi.input (%r) doesn't have the attribute %s" % (wsgi_input, attr)) def check_errors(wsgi_errors): for attr in ['flush', 'write', 'writelines']: assert hasattr(wsgi_errors, attr), ( "wsgi.errors (%r) doesn't have the attribute %s" % (wsgi_errors, attr)) def check_status(status): assert type(status) is StringType, ( "Status must be a string (not %r)" % status) # Implicitly check that we can turn it into an integer: status_code = status.split(None, 1)[0] assert len(status_code) == 3, ( "Status codes must be three characters: %r" % status_code) status_int = int(status_code) assert status_int >= 100, "Status code is invalid: %r" % status_int if len(status) < 4 or status[3] != ' ': warnings.warn( "The status string (%r) should be a three-digit integer " "followed by a single space and a status explanation" % status, WSGIWarning) def check_headers(headers): assert type(headers) is ListType, ( "Headers (%r) must be of type list: %r" % (headers, type(headers))) header_names = {} for item in headers: assert type(item) is TupleType, ( "Individual headers (%r) must be of type tuple: %r" % (item, type(item))) assert len(item) == 2 name, value = item assert name.lower() != 'status', ( "The Status header cannot be used; it conflicts with CGI " "script, and HTTP status is not given through headers " "(value: %r)." % value) header_names[name.lower()] = None assert '\n' not in name and ':' not in name, ( "Header names may not contain ':' or '\\n': %r" % name) assert header_re.search(name), "Bad header name: %r" % name assert not name.endswith('-') and not name.endswith('_'), ( "Names may not end in '-' or '_': %r" % name) assert not bad_header_value_re.search(value), ( "Bad header value: %r (bad char: %r)" % (value, bad_header_value_re.search(value).group(0))) def check_content_type(status, headers): code = int(status.split(None, 1)[0]) # @@: need one more person to verify this interpretation of RFC 2616 # http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html NO_MESSAGE_BODY = (204, 304) for name, value in headers: if name.lower() == 'content-type': if code not in NO_MESSAGE_BODY: return assert 0, (("Content-Type header found in a %s response, " "which must not return content.") % code) if code not in NO_MESSAGE_BODY: assert 0, "No Content-Type header found in headers (%s)" % headers def check_exc_info(exc_info): assert exc_info is None or type(exc_info) is type(()), ( "exc_info (%r) is not a tuple: %r" % (exc_info, type(exc_info))) # More exc_info checks? def check_iterator(iterator): # Technically a string is legal, which is why it's a really bad # idea, because it may cause the response to be returned # character-by-character assert not isinstance(iterator, str), ( "You should not return a string as your application iterator, " "instead return a single-item list containing that string.") PK–jÇ4-¸ñÎMÎMwsgiref/validate.pyc;ò ÍÒ„Dc@s1dZdgZdkZdkZdklZlZlZlZdk Z ei dƒZ ei dƒZ de fd„ƒYZd„Zd fd „ƒYZd fd „ƒYZd fd„ƒYZdfd„ƒYZdfd„ƒYZd„Zd„Zd„Zd„Zd„Zd„Zd„Zd„ZdS(s" Middleware to check for obedience to the WSGI specification. Some of the things this checks: * Signature of the application and start_response (including that keyword arguments are not used). * Environment checks: - Environment is a dictionary (and not a subclass). - That all the required keys are in the environment: REQUEST_METHOD, SERVER_NAME, SERVER_PORT, wsgi.version, wsgi.input, wsgi.errors, wsgi.multithread, wsgi.multiprocess, wsgi.run_once - That HTTP_CONTENT_TYPE and HTTP_CONTENT_LENGTH are not in the environment (these headers should appear as CONTENT_LENGTH and CONTENT_TYPE). - Warns if QUERY_STRING is missing, as the cgi module acts unpredictably in that case. - That CGI-style variables (that don't contain a .) have (non-unicode) string values - That wsgi.version is a tuple - That wsgi.url_scheme is 'http' or 'https' (@@: is this too restrictive?) - Warns if the REQUEST_METHOD is not known (@@: probably too restrictive). - That SCRIPT_NAME and PATH_INFO are empty or start with / - That at least one of SCRIPT_NAME or PATH_INFO are set. - That CONTENT_LENGTH is a positive integer. - That SCRIPT_NAME is not '/' (it should be '', and PATH_INFO should be '/'). - That wsgi.input has the methods read, readline, readlines, and __iter__ - That wsgi.errors has the methods flush, write, writelines * The status is a string, contains a space, starts with an integer, and that integer is in range (> 100). * That the headers is a list (not a subclass, not another kind of sequence). * That the items of the headers are tuples of strings. * That there is no 'status' header (that is used in CGI, but not in WSGI). * That the headers don't contain newlines or colons, end in _ or -, or contain characters codes below 037. * That Content-Type is given if there is content (CGI often has a default content type, but WSGI does not). * That no Content-Type is given when there is no content (@@: is this too restrictive?) * That the exc_info argument to start_response is a tuple or None. * That all calls to the writer are with strings, and no other methods on the writer are accessed. * That wsgi.input is used properly: - .read() is called with zero or one argument - That it returns a string - That readline, readlines, and __iter__ return strings - That .close() is not called - No other methods are provided * That wsgi.errors is used properly: - .write() and .writelines() is called with a string - That .close() is not called, and no other methods are provided. * The response iterator: - That it is not a string (it should be a list of a single string; a string will work, but perform horribly). - That .next() returns a string - That the iterator is not iterated over until start_response has been called (that can signal either a server or application error). - That .close() is called (doesn't raise exception, only prints to sys.stderr, because we only know it isn't called when the object is garbage collected). s validatorN(sDictTypes StringTypes TupleTypesListTypes^[a-zA-Z][a-zA-Z0-9\-_]*$s [\000-\037]s WSGIWarningcBstZdZRS(s: Raised in response to WSGI-spec-related warnings (s__name__s __module__s__doc__(((s)build\bdist.win32\egg\wsgiref\validate.pys WSGIWarningzs cs‡d†}|SdS(s® When applied between a WSGI server and a WSGI application, this middleware will check for WSGI compliancy on a number of levels. This middleware does not modify the request or response in any way, but will throw an AssertionError if anything seems off (except for a failure to close the application iterator, which will be printed to stderr -- there's no way to throw an exception at that point). csÐt|ƒdjp td‚| p td‚|\}‰t|ƒg‰‡‡d†}t |dƒ|dThe application must return an iterator, if only an empty list(slensargssAssertionErrorskwsenvironsstart_responses check_environsstart_response_startedsstart_response_wrappers InputWrappers ErrorWrappers applicationsiteratorsNonesFalsescheck_iteratorsIteratorWrapper(sargsskwsiteratorsstart_responsesstart_response_wrappersenvironsstart_response_started(s application(sstart_responsesstart_response_starteds)build\bdist.win32\egg\wsgiref\validate.pyslint_app‹s  $ N(slint_app(s applicationslint_app((s applications)build\bdist.win32\egg\wsgiref\validate.pys validators  )s InputWrappercBs>tZd„Zd„Zd„Zd„Zd„Zd„ZRS(NcCs ||_dS(N(s wsgi_inputsselfsinput(sselfs wsgi_input((s)build\bdist.win32\egg\wsgiref\validate.pys__init__¸scGsTt|ƒdjpt‚|ii|Œ}t|ƒtdƒjpt‚|SdS(Nis(slensargssAssertionErrorsselfsinputsreadsvstype(sselfsargssv((s)build\bdist.win32\egg\wsgiref\validate.pysread»s cCs7|iiƒ}t|ƒtdƒjpt‚|SdS(Ns(sselfsinputsreadlinesvstypesAssertionError(sselfsv((s)build\bdist.win32\egg\wsgiref\validate.pysreadlineÁs cGs…t|ƒdjpt‚|ii|Œ}t|ƒtgƒjpt‚x.|D]&}t|ƒtdƒjpt‚qSW|SdS(Nis( slensargssAssertionErrorsselfsinputs readlinesslinesstypesline(sselfsargsslinessline((s)build\bdist.win32\egg\wsgiref\validate.pys readlinesÆs $ccs3x,no$|iƒ}| odSn|Vq WdS(Ni(sselfsreadlinesline(sselfsline((s)build\bdist.win32\egg\wsgiref\validate.pys__iter__Îs  cCsdp td‚dS(Nis input.close() must not be called(sAssertionError(sself((s)build\bdist.win32\egg\wsgiref\validate.pyscloseÕs(s__name__s __module__s__init__sreadsreadlines readliness__iter__sclose(((s)build\bdist.win32\egg\wsgiref\validate.pys InputWrapper¶s      s ErrorWrappercBs5tZd„Zd„Zd„Zd„Zd„ZRS(NcCs ||_dS(N(s wsgi_errorssselfserrors(sselfs wsgi_errors((s)build\bdist.win32\egg\wsgiref\validate.pys__init__ÚscCs4t|ƒtdƒjpt‚|ii|ƒdS(Ns(stypesssAssertionErrorsselfserrorsswrite(sselfss((s)build\bdist.win32\egg\wsgiref\validate.pyswriteÝs cCs|iiƒdS(N(sselfserrorssflush(sself((s)build\bdist.win32\egg\wsgiref\validate.pysflusháscCs"x|D]}|i|ƒqWdS(N(sseqslinesselfswrite(sselfsseqsline((s)build\bdist.win32\egg\wsgiref\validate.pys writelinesäscCsdp td‚dS(Nis!errors.close() must not be called(sAssertionError(sself((s)build\bdist.win32\egg\wsgiref\validate.pyscloseès(s__name__s __module__s__init__swritesflushs writelinessclose(((s)build\bdist.win32\egg\wsgiref\validate.pys ErrorWrapperØs     s WriteWrappercBstZd„Zd„ZRS(NcCs ||_dS(N(s wsgi_writersselfswriter(sselfs wsgi_writer((s)build\bdist.win32\egg\wsgiref\validate.pys__init__íscCs1t|ƒtdƒjpt‚|i|ƒdS(Ns(stypesssAssertionErrorsselfswriter(sselfss((s)build\bdist.win32\egg\wsgiref\validate.pys__call__ðs (s__name__s __module__s__init__s__call__(((s)build\bdist.win32\egg\wsgiref\validate.pys WriteWrapperës sPartialIteratorWrappercBstZd„Zd„ZRS(NcCs ||_dS(N(s wsgi_iteratorsselfsiterator(sselfs wsgi_iterator((s)build\bdist.win32\egg\wsgiref\validate.pys__init__öscCst|iƒSdS(N(sIteratorWrappersselfsiterator(sself((s)build\bdist.win32\egg\wsgiref\validate.pys__iter__ùs(s__name__s __module__s__init__s__iter__(((s)build\bdist.win32\egg\wsgiref\validate.pysPartialIteratorWrapperôs sIteratorWrappercBs5tZd„Zd„Zd„Zd„Zd„ZRS(NcCs.||_t|ƒ|_t|_||_dS(N(s wsgi_iteratorsselfsoriginal_iteratorsitersiteratorsFalsesclosedscheck_start_response(sselfs wsgi_iteratorscheck_start_response((s)build\bdist.win32\egg\wsgiref\validate.pys__init__ÿs  cCs|SdS(N(sself(sself((s)build\bdist.win32\egg\wsgiref\validate.pys__iter__scCs]|i p td‚|iiƒ}|itj o!|ip td‚t|_n|SdS(NsIterator read after closedsjThe application returns and we started iterating over its body, but start_response has not yet been called(sselfsclosedsAssertionErrorsiteratorsnextsvscheck_start_responsesNone(sselfsv((s)build\bdist.win32\egg\wsgiref\validate.pysnexts  cCs1t|_t|idƒo|iiƒndS(Nsclose(sTruesselfsclosedshasattrsoriginal_iteratorsclose(sself((s)build\bdist.win32\egg\wsgiref\validate.pyscloses cCs7|i otiidƒn|ip td‚dS(Ns/Iterator garbage collected without being closed(sselfsclosedssyssstderrswritesAssertionError(sself((s)build\bdist.win32\egg\wsgiref\validate.pys__del__s (s__name__s __module__s__init__s__iter__snextscloses__del__(((s)build\bdist.win32\egg\wsgiref\validate.pysIteratorWrapperýs    c Csãt|ƒtjptdt|ƒ|f‚xDdddddddd d g D]!}||jptd |‚qOWx9d d gD]+}||jptd||df‚qWd|jotidtƒnxa|iƒD]S}d|joqÞnt||ƒt jp"tdt||ƒ||f‚qÞWt|dƒt jptd|d‚|dddfjptd|d‚t |dƒt |dƒ|ddddddddfjotid |dtƒn|i d!ƒ p|d!id"ƒptd#|d!‚|i d$ƒ p|d$id"ƒptd%|d$‚|i d&ƒo-t|d&ƒd'jptd(|d&‚n|i d!ƒ o|id$ƒp td)‚n|i d!ƒd"jp td*‚dS(+Ns:Environment is not of the right type: %r (environment: %r)sREQUEST_METHODs SERVER_NAMEs SERVER_PORTs wsgi.versions wsgi.inputs wsgi.errorsswsgi.multithreadswsgi.multiprocesss wsgi.run_onces$Environment missing required key: %rsHTTP_CONTENT_TYPEsHTTP_CONTENT_LENGTHs8Environment should not have the key: %s (use %s instead)is QUERY_STRINGs’QUERY_STRING is not in the WSGI environment; the cgi module will use sys.argv when this variable is missing, so application errors are more likelys.s9Environmental variable %s is not a string: %r (value: %r)s#wsgi.version should be a tuple (%r)swsgi.url_schemeshttpshttpsswsgi.url_scheme unknown: %rsGETsHEADsPOSTsOPTIONSsPUTsDELETEsTRACEsUnknown REQUEST_METHOD: %rs SCRIPT_NAMEs/s$SCRIPT_NAME doesn't start with /: %rs PATH_INFOs"PATH_INFO doesn't start with /: %rsCONTENT_LENGTHisInvalid CONTENT_LENGTH: %rsgOne of SCRIPT_NAME or PATH_INFO are required (PATH_INFO should at least be '/' if SCRIPT_NAME is empty)sOSCRIPT_NAME cannot be '/'; it should instead be '', and PATH_INFO should be '/'(stypesenvironsDictTypesAssertionErrorskeyswarningsswarns WSGIWarningskeyss StringTypes TupleTypes check_inputs check_errorssgets startswithsintshas_key(senvironskey((s)build\bdist.win32\egg\wsgiref\validate.pys check_environs:-" )     =))& 77-cCsEx>ddddgD]*}t||ƒptd||f‚qWdS(Nsreadsreadlines readliness__iter__s-wsgi.input (%r) doesn't have the attribute %s(sattrshasattrs wsgi_inputsAssertionError(s wsgi_inputsattr((s)build\bdist.win32\egg\wsgiref\validate.pys check_input_scCsBx;dddgD]*}t||ƒptd||f‚qWdS(Nsflushswrites writeliness.wsgi.errors (%r) doesn't have the attribute %s(sattrshasattrs wsgi_errorssAssertionError(s wsgi_errorssattr((s)build\bdist.win32\egg\wsgiref\validate.pys check_errorsescCs¿t|ƒtjptd|‚|itdƒd}t|ƒdjptd|‚t|ƒ}|djptd|‚t|ƒdjp|dd jot i d |t ƒndS( Ns Status must be a string (not %r)iiis)Status codes must be three characters: %ridsStatus code is invalid: %ris sjThe status string (%r) should be a three-digit integer followed by a single space and a status explanation( stypesstatuss StringTypesAssertionErrorssplitsNones status_codeslensints status_intswarningsswarns WSGIWarning(sstatuss status_codes status_int((s)build\bdist.win32\egg\wsgiref\validate.pys check_statusks!! $ cCsyt|ƒtjptd|t|ƒf‚h}x?|D]7}t|ƒtjptd|t|ƒf‚t|ƒdjpt‚|\}}|i ƒdjptd|‚t ||i ƒ