Edit File by line
/home/barbar84/public_h.../wp-conte.../plugins/sujqvwi/ShExBy/shex_roo.../lib64/python2..../wsgiref
File: handlers.py
"""Base classes for server/gateway implementations"""
[0] Fix | Delete
[1] Fix | Delete
from types import StringType
[2] Fix | Delete
from util import FileWrapper, guess_scheme, is_hop_by_hop
[3] Fix | Delete
from headers import Headers
[4] Fix | Delete
[5] Fix | Delete
import sys, os, time
[6] Fix | Delete
[7] Fix | Delete
__all__ = ['BaseHandler', 'SimpleHandler', 'BaseCGIHandler', 'CGIHandler']
[8] Fix | Delete
[9] Fix | Delete
try:
[10] Fix | Delete
dict
[11] Fix | Delete
except NameError:
[12] Fix | Delete
def dict(items):
[13] Fix | Delete
d = {}
[14] Fix | Delete
for k,v in items:
[15] Fix | Delete
d[k] = v
[16] Fix | Delete
return d
[17] Fix | Delete
[18] Fix | Delete
# Uncomment for 2.2 compatibility.
[19] Fix | Delete
#try:
[20] Fix | Delete
# True
[21] Fix | Delete
# False
[22] Fix | Delete
#except NameError:
[23] Fix | Delete
# True = not None
[24] Fix | Delete
# False = not True
[25] Fix | Delete
[26] Fix | Delete
[27] Fix | Delete
# Weekday and month names for HTTP date/time formatting; always English!
[28] Fix | Delete
_weekdayname = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
[29] Fix | Delete
_monthname = [None, # Dummy so we can use 1-based month numbers
[30] Fix | Delete
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
[31] Fix | Delete
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
[32] Fix | Delete
[33] Fix | Delete
def format_date_time(timestamp):
[34] Fix | Delete
year, month, day, hh, mm, ss, wd, y, z = time.gmtime(timestamp)
[35] Fix | Delete
return "%s, %02d %3s %4d %02d:%02d:%02d GMT" % (
[36] Fix | Delete
_weekdayname[wd], day, _monthname[month], year, hh, mm, ss
[37] Fix | Delete
)
[38] Fix | Delete
[39] Fix | Delete
[40] Fix | Delete
class BaseHandler:
[41] Fix | Delete
"""Manage the invocation of a WSGI application"""
[42] Fix | Delete
[43] Fix | Delete
# Configuration parameters; can override per-subclass or per-instance
[44] Fix | Delete
wsgi_version = (1,0)
[45] Fix | Delete
wsgi_multithread = True
[46] Fix | Delete
wsgi_multiprocess = True
[47] Fix | Delete
wsgi_run_once = False
[48] Fix | Delete
[49] Fix | Delete
origin_server = True # We are transmitting direct to client
[50] Fix | Delete
http_version = "1.0" # Version that should be used for response
[51] Fix | Delete
server_software = None # String name of server software, if any
[52] Fix | Delete
[53] Fix | Delete
# os_environ is used to supply configuration from the OS environment:
[54] Fix | Delete
# by default it's a copy of 'os.environ' as of import time, but you can
[55] Fix | Delete
# override this in e.g. your __init__ method.
[56] Fix | Delete
os_environ = dict(os.environ.items())
[57] Fix | Delete
[58] Fix | Delete
# Collaborator classes
[59] Fix | Delete
wsgi_file_wrapper = FileWrapper # set to None to disable
[60] Fix | Delete
headers_class = Headers # must be a Headers-like class
[61] Fix | Delete
[62] Fix | Delete
# Error handling (also per-subclass or per-instance)
[63] Fix | Delete
traceback_limit = None # Print entire traceback to self.get_stderr()
[64] Fix | Delete
error_status = "500 Internal Server Error"
[65] Fix | Delete
error_headers = [('Content-Type','text/plain')]
[66] Fix | Delete
error_body = "A server error occurred. Please contact the administrator."
[67] Fix | Delete
[68] Fix | Delete
# State variables (don't mess with these)
[69] Fix | Delete
status = result = None
[70] Fix | Delete
headers_sent = False
[71] Fix | Delete
headers = None
[72] Fix | Delete
bytes_sent = 0
[73] Fix | Delete
[74] Fix | Delete
def run(self, application):
[75] Fix | Delete
"""Invoke the application"""
[76] Fix | Delete
# Note to self: don't move the close()! Asynchronous servers shouldn't
[77] Fix | Delete
# call close() from finish_response(), so if you close() anywhere but
[78] Fix | Delete
# the double-error branch here, you'll break asynchronous servers by
[79] Fix | Delete
# prematurely closing. Async servers must return from 'run()' without
[80] Fix | Delete
# closing if there might still be output to iterate over.
[81] Fix | Delete
try:
[82] Fix | Delete
self.setup_environ()
[83] Fix | Delete
self.result = application(self.environ, self.start_response)
[84] Fix | Delete
self.finish_response()
[85] Fix | Delete
except:
[86] Fix | Delete
try:
[87] Fix | Delete
self.handle_error()
[88] Fix | Delete
except:
[89] Fix | Delete
# If we get an error handling an error, just give up already!
[90] Fix | Delete
self.close()
[91] Fix | Delete
raise # ...and let the actual server figure it out.
[92] Fix | Delete
[93] Fix | Delete
[94] Fix | Delete
def setup_environ(self):
[95] Fix | Delete
"""Set up the environment for one request"""
[96] Fix | Delete
[97] Fix | Delete
env = self.environ = self.os_environ.copy()
[98] Fix | Delete
self.add_cgi_vars()
[99] Fix | Delete
[100] Fix | Delete
env['wsgi.input'] = self.get_stdin()
[101] Fix | Delete
env['wsgi.errors'] = self.get_stderr()
[102] Fix | Delete
env['wsgi.version'] = self.wsgi_version
[103] Fix | Delete
env['wsgi.run_once'] = self.wsgi_run_once
[104] Fix | Delete
env['wsgi.url_scheme'] = self.get_scheme()
[105] Fix | Delete
env['wsgi.multithread'] = self.wsgi_multithread
[106] Fix | Delete
env['wsgi.multiprocess'] = self.wsgi_multiprocess
[107] Fix | Delete
[108] Fix | Delete
if self.wsgi_file_wrapper is not None:
[109] Fix | Delete
env['wsgi.file_wrapper'] = self.wsgi_file_wrapper
[110] Fix | Delete
[111] Fix | Delete
if self.origin_server and self.server_software:
[112] Fix | Delete
env.setdefault('SERVER_SOFTWARE',self.server_software)
[113] Fix | Delete
[114] Fix | Delete
[115] Fix | Delete
def finish_response(self):
[116] Fix | Delete
"""Send any iterable data, then close self and the iterable
[117] Fix | Delete
[118] Fix | Delete
Subclasses intended for use in asynchronous servers will
[119] Fix | Delete
want to redefine this method, such that it sets up callbacks
[120] Fix | Delete
in the event loop to iterate over the data, and to call
[121] Fix | Delete
'self.close()' once the response is finished.
[122] Fix | Delete
"""
[123] Fix | Delete
try:
[124] Fix | Delete
if not self.result_is_file() or not self.sendfile():
[125] Fix | Delete
for data in self.result:
[126] Fix | Delete
self.write(data)
[127] Fix | Delete
self.finish_content()
[128] Fix | Delete
finally:
[129] Fix | Delete
self.close()
[130] Fix | Delete
[131] Fix | Delete
[132] Fix | Delete
def get_scheme(self):
[133] Fix | Delete
"""Return the URL scheme being used"""
[134] Fix | Delete
return guess_scheme(self.environ)
[135] Fix | Delete
[136] Fix | Delete
[137] Fix | Delete
def set_content_length(self):
[138] Fix | Delete
"""Compute Content-Length or switch to chunked encoding if possible"""
[139] Fix | Delete
try:
[140] Fix | Delete
blocks = len(self.result)
[141] Fix | Delete
except (TypeError,AttributeError,NotImplementedError):
[142] Fix | Delete
pass
[143] Fix | Delete
else:
[144] Fix | Delete
if blocks==1:
[145] Fix | Delete
self.headers['Content-Length'] = str(self.bytes_sent)
[146] Fix | Delete
return
[147] Fix | Delete
# XXX Try for chunked encoding if origin server and client is 1.1
[148] Fix | Delete
[149] Fix | Delete
[150] Fix | Delete
def cleanup_headers(self):
[151] Fix | Delete
"""Make any necessary header changes or defaults
[152] Fix | Delete
[153] Fix | Delete
Subclasses can extend this to add other defaults.
[154] Fix | Delete
"""
[155] Fix | Delete
if 'Content-Length' not in self.headers:
[156] Fix | Delete
self.set_content_length()
[157] Fix | Delete
[158] Fix | Delete
def start_response(self, status, headers,exc_info=None):
[159] Fix | Delete
"""'start_response()' callable as specified by PEP 333"""
[160] Fix | Delete
[161] Fix | Delete
if exc_info:
[162] Fix | Delete
try:
[163] Fix | Delete
if self.headers_sent:
[164] Fix | Delete
# Re-raise original exception if headers sent
[165] Fix | Delete
raise exc_info[0], exc_info[1], exc_info[2]
[166] Fix | Delete
finally:
[167] Fix | Delete
exc_info = None # avoid dangling circular ref
[168] Fix | Delete
elif self.headers is not None:
[169] Fix | Delete
raise AssertionError("Headers already set!")
[170] Fix | Delete
[171] Fix | Delete
assert type(status) is StringType,"Status must be a string"
[172] Fix | Delete
assert len(status)>=4,"Status must be at least 4 characters"
[173] Fix | Delete
assert int(status[:3]),"Status message must begin w/3-digit code"
[174] Fix | Delete
assert status[3]==" ", "Status message must have a space after code"
[175] Fix | Delete
if __debug__:
[176] Fix | Delete
for name,val in headers:
[177] Fix | Delete
assert type(name) is StringType,"Header names must be strings"
[178] Fix | Delete
assert type(val) is StringType,"Header values must be strings"
[179] Fix | Delete
assert not is_hop_by_hop(name),"Hop-by-hop headers not allowed"
[180] Fix | Delete
self.status = status
[181] Fix | Delete
self.headers = self.headers_class(headers)
[182] Fix | Delete
return self.write
[183] Fix | Delete
[184] Fix | Delete
[185] Fix | Delete
def send_preamble(self):
[186] Fix | Delete
"""Transmit version/status/date/server, via self._write()"""
[187] Fix | Delete
if self.origin_server:
[188] Fix | Delete
if self.client_is_modern():
[189] Fix | Delete
self._write('HTTP/%s %s\r\n' % (self.http_version,self.status))
[190] Fix | Delete
if 'Date' not in self.headers:
[191] Fix | Delete
self._write(
[192] Fix | Delete
'Date: %s\r\n' % format_date_time(time.time())
[193] Fix | Delete
)
[194] Fix | Delete
if self.server_software and 'Server' not in self.headers:
[195] Fix | Delete
self._write('Server: %s\r\n' % self.server_software)
[196] Fix | Delete
else:
[197] Fix | Delete
self._write('Status: %s\r\n' % self.status)
[198] Fix | Delete
[199] Fix | Delete
def write(self, data):
[200] Fix | Delete
"""'write()' callable as specified by PEP 333"""
[201] Fix | Delete
[202] Fix | Delete
assert type(data) is StringType,"write() argument must be string"
[203] Fix | Delete
[204] Fix | Delete
if not self.status:
[205] Fix | Delete
raise AssertionError("write() before start_response()")
[206] Fix | Delete
[207] Fix | Delete
elif not self.headers_sent:
[208] Fix | Delete
# Before the first output, send the stored headers
[209] Fix | Delete
self.bytes_sent = len(data) # make sure we know content-length
[210] Fix | Delete
self.send_headers()
[211] Fix | Delete
else:
[212] Fix | Delete
self.bytes_sent += len(data)
[213] Fix | Delete
[214] Fix | Delete
# XXX check Content-Length and truncate if too many bytes written?
[215] Fix | Delete
self._write(data)
[216] Fix | Delete
self._flush()
[217] Fix | Delete
[218] Fix | Delete
[219] Fix | Delete
def sendfile(self):
[220] Fix | Delete
"""Platform-specific file transmission
[221] Fix | Delete
[222] Fix | Delete
Override this method in subclasses to support platform-specific
[223] Fix | Delete
file transmission. It is only called if the application's
[224] Fix | Delete
return iterable ('self.result') is an instance of
[225] Fix | Delete
'self.wsgi_file_wrapper'.
[226] Fix | Delete
[227] Fix | Delete
This method should return a true value if it was able to actually
[228] Fix | Delete
transmit the wrapped file-like object using a platform-specific
[229] Fix | Delete
approach. It should return a false value if normal iteration
[230] Fix | Delete
should be used instead. An exception can be raised to indicate
[231] Fix | Delete
that transmission was attempted, but failed.
[232] Fix | Delete
[233] Fix | Delete
NOTE: this method should call 'self.send_headers()' if
[234] Fix | Delete
'self.headers_sent' is false and it is going to attempt direct
[235] Fix | Delete
transmission of the file.
[236] Fix | Delete
"""
[237] Fix | Delete
return False # No platform-specific transmission by default
[238] Fix | Delete
[239] Fix | Delete
[240] Fix | Delete
def finish_content(self):
[241] Fix | Delete
"""Ensure headers and content have both been sent"""
[242] Fix | Delete
if not self.headers_sent:
[243] Fix | Delete
# Only zero Content-Length if not set by the application (so
[244] Fix | Delete
# that HEAD requests can be satisfied properly, see #3839)
[245] Fix | Delete
self.headers.setdefault('Content-Length', "0")
[246] Fix | Delete
self.send_headers()
[247] Fix | Delete
else:
[248] Fix | Delete
pass # XXX check if content-length was too short?
[249] Fix | Delete
[250] Fix | Delete
def close(self):
[251] Fix | Delete
"""Close the iterable (if needed) and reset all instance vars
[252] Fix | Delete
[253] Fix | Delete
Subclasses may want to also drop the client connection.
[254] Fix | Delete
"""
[255] Fix | Delete
try:
[256] Fix | Delete
if hasattr(self.result,'close'):
[257] Fix | Delete
self.result.close()
[258] Fix | Delete
finally:
[259] Fix | Delete
self.result = self.headers = self.status = self.environ = None
[260] Fix | Delete
self.bytes_sent = 0; self.headers_sent = False
[261] Fix | Delete
[262] Fix | Delete
[263] Fix | Delete
def send_headers(self):
[264] Fix | Delete
"""Transmit headers to the client, via self._write()"""
[265] Fix | Delete
self.cleanup_headers()
[266] Fix | Delete
self.headers_sent = True
[267] Fix | Delete
if not self.origin_server or self.client_is_modern():
[268] Fix | Delete
self.send_preamble()
[269] Fix | Delete
self._write(str(self.headers))
[270] Fix | Delete
[271] Fix | Delete
[272] Fix | Delete
def result_is_file(self):
[273] Fix | Delete
"""True if 'self.result' is an instance of 'self.wsgi_file_wrapper'"""
[274] Fix | Delete
wrapper = self.wsgi_file_wrapper
[275] Fix | Delete
return wrapper is not None and isinstance(self.result,wrapper)
[276] Fix | Delete
[277] Fix | Delete
[278] Fix | Delete
def client_is_modern(self):
[279] Fix | Delete
"""True if client can accept status and headers"""
[280] Fix | Delete
return self.environ['SERVER_PROTOCOL'].upper() != 'HTTP/0.9'
[281] Fix | Delete
[282] Fix | Delete
[283] Fix | Delete
def log_exception(self,exc_info):
[284] Fix | Delete
"""Log the 'exc_info' tuple in the server log
[285] Fix | Delete
[286] Fix | Delete
Subclasses may override to retarget the output or change its format.
[287] Fix | Delete
"""
[288] Fix | Delete
try:
[289] Fix | Delete
from traceback import print_exception
[290] Fix | Delete
stderr = self.get_stderr()
[291] Fix | Delete
print_exception(
[292] Fix | Delete
exc_info[0], exc_info[1], exc_info[2],
[293] Fix | Delete
self.traceback_limit, stderr
[294] Fix | Delete
)
[295] Fix | Delete
stderr.flush()
[296] Fix | Delete
finally:
[297] Fix | Delete
exc_info = None
[298] Fix | Delete
[299] Fix | Delete
def handle_error(self):
[300] Fix | Delete
"""Log current error, and send error output to client if possible"""
[301] Fix | Delete
self.log_exception(sys.exc_info())
[302] Fix | Delete
if not self.headers_sent:
[303] Fix | Delete
self.result = self.error_output(self.environ, self.start_response)
[304] Fix | Delete
self.finish_response()
[305] Fix | Delete
# XXX else: attempt advanced recovery techniques for HTML or text?
[306] Fix | Delete
[307] Fix | Delete
def error_output(self, environ, start_response):
[308] Fix | Delete
"""WSGI mini-app to create error output
[309] Fix | Delete
[310] Fix | Delete
By default, this just uses the 'error_status', 'error_headers',
[311] Fix | Delete
and 'error_body' attributes to generate an output page. It can
[312] Fix | Delete
be overridden in a subclass to dynamically generate diagnostics,
[313] Fix | Delete
choose an appropriate message for the user's preferred language, etc.
[314] Fix | Delete
[315] Fix | Delete
Note, however, that it's not recommended from a security perspective to
[316] Fix | Delete
spit out diagnostics to any old user; ideally, you should have to do
[317] Fix | Delete
something special to enable diagnostic output, which is why we don't
[318] Fix | Delete
include any here!
[319] Fix | Delete
"""
[320] Fix | Delete
start_response(self.error_status,self.error_headers[:],sys.exc_info())
[321] Fix | Delete
return [self.error_body]
[322] Fix | Delete
[323] Fix | Delete
[324] Fix | Delete
# Pure abstract methods; *must* be overridden in subclasses
[325] Fix | Delete
[326] Fix | Delete
def _write(self,data):
[327] Fix | Delete
"""Override in subclass to buffer data for send to client
[328] Fix | Delete
[329] Fix | Delete
It's okay if this method actually transmits the data; BaseHandler
[330] Fix | Delete
just separates write and flush operations for greater efficiency
[331] Fix | Delete
when the underlying system actually has such a distinction.
[332] Fix | Delete
"""
[333] Fix | Delete
raise NotImplementedError
[334] Fix | Delete
[335] Fix | Delete
def _flush(self):
[336] Fix | Delete
"""Override in subclass to force sending of recent '_write()' calls
[337] Fix | Delete
[338] Fix | Delete
It's okay if this method is a no-op (i.e., if '_write()' actually
[339] Fix | Delete
sends the data.
[340] Fix | Delete
"""
[341] Fix | Delete
raise NotImplementedError
[342] Fix | Delete
[343] Fix | Delete
def get_stdin(self):
[344] Fix | Delete
"""Override in subclass to return suitable 'wsgi.input'"""
[345] Fix | Delete
raise NotImplementedError
[346] Fix | Delete
[347] Fix | Delete
def get_stderr(self):
[348] Fix | Delete
"""Override in subclass to return suitable 'wsgi.errors'"""
[349] Fix | Delete
raise NotImplementedError
[350] Fix | Delete
[351] Fix | Delete
def add_cgi_vars(self):
[352] Fix | Delete
"""Override in subclass to insert CGI variables in 'self.environ'"""
[353] Fix | Delete
raise NotImplementedError
[354] Fix | Delete
[355] Fix | Delete
[356] Fix | Delete
class SimpleHandler(BaseHandler):
[357] Fix | Delete
"""Handler that's just initialized with streams, environment, etc.
[358] Fix | Delete
[359] Fix | Delete
This handler subclass is intended for synchronous HTTP/1.0 origin servers,
[360] Fix | Delete
and handles sending the entire response output, given the correct inputs.
[361] Fix | Delete
[362] Fix | Delete
Usage::
[363] Fix | Delete
[364] Fix | Delete
handler = SimpleHandler(
[365] Fix | Delete
inp,out,err,env, multithread=False, multiprocess=True
[366] Fix | Delete
)
[367] Fix | Delete
handler.run(app)"""
[368] Fix | Delete
[369] Fix | Delete
def __init__(self,stdin,stdout,stderr,environ,
[370] Fix | Delete
multithread=True, multiprocess=False
[371] Fix | Delete
):
[372] Fix | Delete
self.stdin = stdin
[373] Fix | Delete
self.stdout = stdout
[374] Fix | Delete
self.stderr = stderr
[375] Fix | Delete
self.base_env = environ
[376] Fix | Delete
self.wsgi_multithread = multithread
[377] Fix | Delete
self.wsgi_multiprocess = multiprocess
[378] Fix | Delete
[379] Fix | Delete
def get_stdin(self):
[380] Fix | Delete
return self.stdin
[381] Fix | Delete
[382] Fix | Delete
def get_stderr(self):
[383] Fix | Delete
return self.stderr
[384] Fix | Delete
[385] Fix | Delete
def add_cgi_vars(self):
[386] Fix | Delete
self.environ.update(self.base_env)
[387] Fix | Delete
[388] Fix | Delete
def _write(self,data):
[389] Fix | Delete
self.stdout.write(data)
[390] Fix | Delete
self._write = self.stdout.write
[391] Fix | Delete
[392] Fix | Delete
def _flush(self):
[393] Fix | Delete
self.stdout.flush()
[394] Fix | Delete
self._flush = self.stdout.flush
[395] Fix | Delete
[396] Fix | Delete
[397] Fix | Delete
class BaseCGIHandler(SimpleHandler):
[398] Fix | Delete
[399] Fix | Delete
"""CGI-like systems using input/output/error streams and environ mapping
[400] Fix | Delete
[401] Fix | Delete
Usage::
[402] Fix | Delete
[403] Fix | Delete
handler = BaseCGIHandler(inp,out,err,env)
[404] Fix | Delete
handler.run(app)
[405] Fix | Delete
[406] Fix | Delete
This handler class is useful for gateway protocols like ReadyExec and
[407] Fix | Delete
FastCGI, that have usable input/output/error streams and an environment
[408] Fix | Delete
mapping. It's also the base class for CGIHandler, which just uses
[409] Fix | Delete
sys.stdin, os.environ, and so on.
[410] Fix | Delete
[411] Fix | Delete
The constructor also takes keyword arguments 'multithread' and
[412] Fix | Delete
'multiprocess' (defaulting to 'True' and 'False' respectively) to control
[413] Fix | Delete
the configuration sent to the application. It sets 'origin_server' to
[414] Fix | Delete
False (to enable CGI-like output), and assumes that 'wsgi.run_once' is
[415] Fix | Delete
False.
[416] Fix | Delete
"""
[417] Fix | Delete
[418] Fix | Delete
origin_server = False
[419] Fix | Delete
[420] Fix | Delete
[421] Fix | Delete
class CGIHandler(BaseCGIHandler):
[422] Fix | Delete
[423] Fix | Delete
"""CGI-based invocation via sys.stdin/stdout/stderr and os.environ
[424] Fix | Delete
[425] Fix | Delete
Usage::
[426] Fix | Delete
[427] Fix | Delete
CGIHandler().run(app)
[428] Fix | Delete
[429] Fix | Delete
The difference between this class and BaseCGIHandler is that it always
[430] Fix | Delete
uses 'wsgi.run_once' of 'True', 'wsgi.multithread' of 'False', and
[431] Fix | Delete
'wsgi.multiprocess' of 'True'. It does not take any initialization
[432] Fix | Delete
parameters, but always uses 'sys.stdin', 'os.environ', and friends.
[433] Fix | Delete
[434] Fix | Delete
If you need to override any of these parameters, use BaseCGIHandler
[435] Fix | Delete
instead.
[436] Fix | Delete
"""
[437] Fix | Delete
[438] Fix | Delete
wsgi_run_once = True
[439] Fix | Delete
# Do not allow os.environ to leak between requests in Google App Engine
[440] Fix | Delete
# and other multi-run CGI use cases. This is not easily testable.
[441] Fix | Delete
# See http://bugs.python.org/issue7250
[442] Fix | Delete
os_environ = {}
[443] Fix | Delete
[444] Fix | Delete
def __init__(self):
[445] Fix | Delete
BaseCGIHandler.__init__(
[446] Fix | Delete
self, sys.stdin, sys.stdout, sys.stderr, dict(os.environ.items()),
[447] Fix | Delete
multithread=False, multiprocess=True
[448] Fix | Delete
)
[449] Fix | Delete
[450] Fix | Delete
It is recommended that you Edit text format, this type of Fix handles quite a lot in one request
Function