NovaBryan/EVE_Dump
Log | Files | 📦 下载最新源码 (.zip) | Refs | README

wsgi.py (13456B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\carbon\common\lib\werkzeug\wsgi.py
      2 import os
      3 import urllib
      4 import urlparse
      5 import posixpath
      6 import mimetypes
      7 from zlib import adler32
      8 from time import time, mktime
      9 from datetime import datetime
     10 from werkzeug._internal import _patch_wrapper
     11 
     12 def responder(f):
     13     return _patch_wrapper(f, lambda *a: f(*a)(*a[-2:]))
     14 
     15 
     16 def get_current_url(environ, root_only = False, strip_querystring = False, host_only = False):
     17     tmp = [environ['wsgi.url_scheme'], '://', get_host(environ)]
     18     cat = tmp.append
     19     if host_only:
     20         return ''.join(tmp) + '/'
     21     cat(urllib.quote(environ.get('SCRIPT_NAME', '').rstrip('/')))
     22     if root_only:
     23         cat('/')
     24     else:
     25         cat(urllib.quote('/' + environ.get('PATH_INFO', '').lstrip('/')))
     26         if not strip_querystring:
     27             qs = environ.get('QUERY_STRING')
     28             if qs:
     29                 cat('?' + qs)
     30     return ''.join(tmp)
     31 
     32 
     33 def get_host(environ):
     34     if 'HTTP_X_FORWARDED_HOST' in environ:
     35         return environ['HTTP_X_FORWARDED_HOST']
     36     if 'HTTP_HOST' in environ:
     37         return environ['HTTP_HOST']
     38     result = environ['SERVER_NAME']
     39     if (environ['wsgi.url_scheme'], environ['SERVER_PORT']) not in (('https', '443'), ('http', '80')):
     40         result += ':' + environ['SERVER_PORT']
     41     return result
     42 
     43 
     44 def pop_path_info(environ):
     45     path = environ.get('PATH_INFO')
     46     if not path:
     47         return None
     48     script_name = environ.get('SCRIPT_NAME', '')
     49     old_path = path
     50     path = path.lstrip('/')
     51     if path != old_path:
     52         script_name += '/' * (len(old_path) - len(path))
     53     if '/' not in path:
     54         environ['PATH_INFO'] = ''
     55         environ['SCRIPT_NAME'] = script_name + path
     56         return path
     57     segment, path = path.split('/', 1)
     58     environ['PATH_INFO'] = '/' + path
     59     environ['SCRIPT_NAME'] = script_name + segment
     60     return segment
     61 
     62 
     63 def peek_path_info(environ):
     64     segments = environ.get('PATH_INFO', '').lstrip('/').split('/', 1)
     65     if segments:
     66         return segments[0]
     67 
     68 
     69 def extract_path_info(environ_or_baseurl, path_or_url, charset = 'utf-8', errors = 'ignore', collapse_http_schemes = True):
     70     from werkzeug.urls import uri_to_iri, url_fix
     71 
     72     def _as_iri(obj):
     73         if not isinstance(obj, unicode):
     74             return uri_to_iri(obj, charset, errors)
     75         return obj
     76 
     77     def _normalize_netloc(scheme, netloc):
     78         parts = netloc.split(u'@', 1)[-1].split(u':', 1)
     79         if len(parts) == 2:
     80             netloc, port = parts
     81             if scheme == u'http' and port == u'80' or scheme == u'https' and port == u'443':
     82                 port = None
     83         else:
     84             netloc = parts[0]
     85             port = None
     86         if port is not None:
     87             netloc += u':' + port
     88         return netloc
     89 
     90     path = _as_iri(path_or_url)
     91     if isinstance(environ_or_baseurl, dict):
     92         environ_or_baseurl = get_current_url(environ_or_baseurl, root_only=True)
     93     base_iri = _as_iri(environ_or_baseurl)
     94     base_scheme, base_netloc, base_path = urlparse.urlsplit(base_iri)[:3]
     95     cur_scheme, cur_netloc, cur_path = urlparse.urlsplit(urlparse.urljoin(base_iri, path))[:3]
     96     base_netloc = _normalize_netloc(base_scheme, base_netloc)
     97     cur_netloc = _normalize_netloc(cur_scheme, cur_netloc)
     98     if collapse_http_schemes:
     99         for scheme in (base_scheme, cur_scheme):
    100             if scheme not in (u'http', u'https'):
    101                 return None
    102 
    103     elif not (base_scheme in (u'http', u'https') and base_scheme == cur_scheme):
    104         return None
    105     if base_netloc != cur_netloc:
    106         return None
    107     base_path = base_path.rstrip(u'/')
    108     if not cur_path.startswith(base_path):
    109         return None
    110     return u'/' + cur_path[len(base_path):].lstrip(u'/')
    111 
    112 
    113 class SharedDataMiddleware(object):
    114 
    115     def __init__(self, app, exports, disallow = None, cache = True, cache_timeout = 43200, fallback_mimetype = 'text/plain'):
    116         self.app = app
    117         self.exports = {}
    118         self.cache = cache
    119         self.cache_timeout = cache_timeout
    120         for key, value in exports.iteritems():
    121             if isinstance(value, tuple):
    122                 loader = self.get_package_loader(*value)
    123             elif isinstance(value, basestring):
    124                 if os.path.isfile(value):
    125                     loader = self.get_file_loader(value)
    126                 else:
    127                     loader = self.get_directory_loader(value)
    128             else:
    129                 raise TypeError('unknown def %r' % value)
    130             self.exports[key] = loader
    131 
    132         if disallow is not None:
    133             from fnmatch import fnmatch
    134             self.is_allowed = lambda x: not fnmatch(x, disallow)
    135         self.fallback_mimetype = fallback_mimetype
    136 
    137     def is_allowed(self, filename):
    138         return True
    139 
    140     def _opener(self, filename):
    141         return lambda : (open(filename, 'rb'), datetime.utcfromtimestamp(os.path.getmtime(filename)), int(os.path.getsize(filename)))
    142 
    143     def get_file_loader(self, filename):
    144         return lambda x: (os.path.basename(filename), self._opener(filename))
    145 
    146     def get_package_loader(self, package, package_path):
    147         from pkg_resources import DefaultProvider, ResourceManager, get_provider
    148         loadtime = datetime.utcnow()
    149         provider = get_provider(package)
    150         manager = ResourceManager()
    151         filesystem_bound = isinstance(provider, DefaultProvider)
    152 
    153         def loader(path):
    154             path = posixpath.join(package_path, path)
    155             if path is None or not provider.has_resource(path):
    156                 return (None, None)
    157             basename = posixpath.basename(path)
    158             if filesystem_bound:
    159                 return (basename, self._opener(provider.get_resource_filename(manager, path)))
    160             return (basename, lambda : (provider.get_resource_stream(manager, path), loadtime, 0))
    161 
    162         return loader
    163 
    164     def get_directory_loader(self, directory):
    165 
    166         def loader(path):
    167             if path is not None:
    168                 path = os.path.join(directory, path)
    169             else:
    170                 path = directory
    171             if os.path.isfile(path):
    172                 return (os.path.basename(path), self._opener(path))
    173             return (None, None)
    174 
    175         return loader
    176 
    177     def generate_etag(self, mtime, file_size, real_filename):
    178         return 'wzsdm-%d-%s-%s' % (mktime(mtime.timetuple()), file_size, adler32(real_filename) & 4294967295L)
    179 
    180     def __call__(self, environ, start_response):
    181         cleaned_path = environ.get('PATH_INFO', '').strip('/')
    182         for sep in (os.sep, os.altsep):
    183             if sep and sep != '/':
    184                 cleaned_path = cleaned_path.replace(sep, '/')
    185 
    186         path = '/'.join([''] + [ x for x in cleaned_path.split('/') if x and x != '..' ])
    187         file_loader = None
    188         for search_path, loader in self.exports.iteritems():
    189             if search_path == path:
    190                 real_filename, file_loader = loader(None)
    191                 if file_loader is not None:
    192                     break
    193             if not search_path.endswith('/'):
    194                 search_path += '/'
    195             if path.startswith(search_path):
    196                 real_filename, file_loader = loader(path[len(search_path):])
    197                 if file_loader is not None:
    198                     break
    199 
    200         if file_loader is None or not self.is_allowed(real_filename):
    201             return self.app(environ, start_response)
    202         guessed_type = mimetypes.guess_type(real_filename)
    203         mime_type = guessed_type[0] or self.fallback_mimetype
    204         f, mtime, file_size = file_loader()
    205         headers = [('Date', http_date())]
    206         if self.cache:
    207             timeout = self.cache_timeout
    208             etag = self.generate_etag(mtime, file_size, real_filename)
    209             headers += [('Etag', '"%s"' % etag), ('Cache-Control', 'max-age=%d, public' % timeout)]
    210             if not is_resource_modified(environ, etag, last_modified=mtime):
    211                 f.close()
    212                 start_response('304 Not Modified', headers)
    213                 return []
    214             headers.append(('Expires', http_date(time() + timeout)))
    215         else:
    216             headers.append(('Cache-Control', 'public'))
    217         headers.extend((('Content-Type', mime_type), ('Content-Length', str(file_size)), ('Last-Modified', http_date(mtime))))
    218         start_response('200 OK', headers)
    219         return wrap_file(environ, f)
    220 
    221 
    222 class DispatcherMiddleware(object):
    223 
    224     def __init__(self, app, mounts = None):
    225         self.app = app
    226         self.mounts = mounts or {}
    227 
    228     def __call__(self, environ, start_response):
    229         script = environ.get('PATH_INFO', '')
    230         path_info = ''
    231         while '/' in script:
    232             if script in self.mounts:
    233                 app = self.mounts[script]
    234                 break
    235             items = script.split('/')
    236             script = '/'.join(items[:-1])
    237             path_info = '/%s%s' % (items[-1], path_info)
    238         else:
    239             app = self.mounts.get(script, self.app)
    240 
    241         original_script_name = environ.get('SCRIPT_NAME', '')
    242         environ['SCRIPT_NAME'] = original_script_name + script
    243         environ['PATH_INFO'] = path_info
    244         return app(environ, start_response)
    245 
    246 
    247 class ClosingIterator(object):
    248 
    249     def __init__(self, iterable, callbacks = None):
    250         iterator = iter(iterable)
    251         self._next = iterator.next
    252         if callbacks is None:
    253             callbacks = []
    254         elif callable(callbacks):
    255             callbacks = [callbacks]
    256         else:
    257             callbacks = list(callbacks)
    258         iterable_close = getattr(iterator, 'close', None)
    259         if iterable_close:
    260             callbacks.insert(0, iterable_close)
    261         self._callbacks = callbacks
    262 
    263     def __iter__(self):
    264         return self
    265 
    266     def next(self):
    267         return self._next()
    268 
    269     def close(self):
    270         for callback in self._callbacks:
    271             callback()
    272 
    273 
    274 def wrap_file(environ, file, buffer_size = 8192):
    275     return environ.get('wsgi.file_wrapper', FileWrapper)(file, buffer_size)
    276 
    277 
    278 class FileWrapper(object):
    279 
    280     def __init__(self, file, buffer_size = 8192):
    281         self.file = file
    282         self.buffer_size = buffer_size
    283 
    284     def close(self):
    285         if hasattr(self.file, 'close'):
    286             self.file.close()
    287 
    288     def __iter__(self):
    289         return self
    290 
    291     def next(self):
    292         data = self.file.read(self.buffer_size)
    293         if data:
    294             return data
    295         raise StopIteration()
    296 
    297 
    298 def make_line_iter(stream, limit = None, buffer_size = 10240):
    299     if not isinstance(stream, LimitedStream):
    300         if limit is None:
    301             raise TypeError('stream not limited and no limit provided.')
    302         stream = LimitedStream(stream, limit)
    303     _read = stream.read
    304     buffer = []
    305     while 1:
    306         if len(buffer) > 1:
    307             yield buffer.pop()
    308             continue
    309         chunks = _read(buffer_size).splitlines(True)
    310         chunks.reverse()
    311         first_chunk = buffer and buffer[0] or ''
    312         if chunks:
    313             first_chunk += chunks.pop()
    314         if not first_chunk:
    315             return
    316         buffer = chunks
    317         yield first_chunk
    318 
    319 
    320 class LimitedStream(object):
    321 
    322     def __init__(self, stream, limit, silent = True):
    323         self._read = stream.read
    324         self._readline = stream.readline
    325         self._pos = 0
    326         self.limit = limit
    327         self.silent = silent
    328         if not silent:
    329             from warnings import warn
    330             warn(DeprecationWarning('non-silent usage of the LimitedStream is deprecated.  If you want to continue to use the stream in non-silent usage override on_exhausted.'), stacklevel=2)
    331 
    332     def __iter__(self):
    333         return self
    334 
    335     @property
    336     def is_exhausted(self):
    337         return self._pos >= self.limit
    338 
    339     def on_exhausted(self):
    340         if self.silent:
    341             return ''
    342         from werkzeug.exceptions import BadRequest
    343         raise BadRequest('input stream exhausted')
    344 
    345     def exhaust(self, chunk_size = 16384):
    346         to_read = self.limit - self._pos
    347         chunk = chunk_size
    348         while to_read > 0:
    349             chunk = min(to_read, chunk)
    350             self.read(chunk)
    351             to_read -= chunk
    352 
    353     def read(self, size = None):
    354         if self._pos >= self.limit:
    355             return self.on_exhausted()
    356         if size is None:
    357             size = self.limit
    358         read = self._read(min(self.limit - self._pos, size))
    359         self._pos += len(read)
    360         return read
    361 
    362     def readline(self, size = None):
    363         if self._pos >= self.limit:
    364             return self.on_exhausted()
    365         if size is None:
    366             size = self.limit - self._pos
    367         else:
    368             size = min(size, self.limit - self._pos)
    369         line = self._readline(size)
    370         self._pos += len(line)
    371         return line
    372 
    373     def readlines(self, size = None):
    374         last_pos = self._pos
    375         result = []
    376         if size is not None:
    377             end = min(self.limit, last_pos + size)
    378         else:
    379             end = self.limit
    380         while 1:
    381             if size is not None:
    382                 size -= last_pos - self._pos
    383             if self._pos >= end:
    384                 break
    385             result.append(self.readline(size))
    386             if size is not None:
    387                 last_pos = self._pos
    388 
    389         return result
    390 
    391     def next(self):
    392         line = self.readline()
    393         if line is None:
    394             raise StopIteration()
    395         return line
    396 
    397 
    398 from werkzeug.utils import http_date
    399 from werkzeug.http import is_resource_modified