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

static.py (9032B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\carbon\common\lib\cherrypy\lib\static.py
      2 import logging
      3 import mimetypes
      4 mimetypes.init()
      5 mimetypes.types_map['.dwg'] = 'image/x-dwg'
      6 mimetypes.types_map['.ico'] = 'image/x-icon'
      7 mimetypes.types_map['.bz2'] = 'application/x-bzip2'
      8 mimetypes.types_map['.gz'] = 'application/x-gzip'
      9 import os
     10 import re
     11 import stat
     12 import time
     13 import cherrypy
     14 from cherrypy._cpcompat import ntob, unquote
     15 from cherrypy.lib import cptools, httputil, file_generator_limited
     16 
     17 def serve_file(path, content_type = None, disposition = None, name = None, debug = False):
     18     response = cherrypy.serving.response
     19     if not os.path.isabs(path):
     20         msg = "'%s' is not an absolute path." % path
     21         if debug:
     22             cherrypy.log(msg, 'TOOLS.STATICFILE')
     23         raise ValueError(msg)
     24     try:
     25         st = os.stat(path)
     26     except OSError:
     27         if debug:
     28             cherrypy.log('os.stat(%r) failed' % path, 'TOOLS.STATIC')
     29         raise cherrypy.NotFound()
     30 
     31     if stat.S_ISDIR(st.st_mode):
     32         if debug:
     33             cherrypy.log('%r is a directory' % path, 'TOOLS.STATIC')
     34         raise cherrypy.NotFound()
     35     response.headers['Last-Modified'] = httputil.HTTPDate(st.st_mtime)
     36     cptools.validate_since()
     37     if content_type is None:
     38         ext = ''
     39         i = path.rfind('.')
     40         if i != -1:
     41             ext = path[i:].lower()
     42         content_type = mimetypes.types_map.get(ext, None)
     43     if content_type is not None:
     44         response.headers['Content-Type'] = content_type
     45     if debug:
     46         cherrypy.log('Content-Type: %r' % content_type, 'TOOLS.STATIC')
     47     cd = None
     48     if disposition is not None:
     49         if name is None:
     50             name = os.path.basename(path)
     51         cd = '%s; filename="%s"' % (disposition, name)
     52         response.headers['Content-Disposition'] = cd
     53     if debug:
     54         cherrypy.log('Content-Disposition: %r' % cd, 'TOOLS.STATIC')
     55     content_length = st.st_size
     56     fileobj = open(path, 'rb')
     57     return _serve_fileobj(fileobj, content_type, content_length, debug=debug)
     58 
     59 
     60 def serve_fileobj(fileobj, content_type = None, disposition = None, name = None, debug = False):
     61     response = cherrypy.serving.response
     62     try:
     63         st = os.fstat(fileobj.fileno())
     64     except AttributeError:
     65         if debug:
     66             cherrypy.log('os has no fstat attribute', 'TOOLS.STATIC')
     67         content_length = None
     68     else:
     69         response.headers['Last-Modified'] = httputil.HTTPDate(st.st_mtime)
     70         cptools.validate_since()
     71         content_length = st.st_size
     72 
     73     if content_type is not None:
     74         response.headers['Content-Type'] = content_type
     75     if debug:
     76         cherrypy.log('Content-Type: %r' % content_type, 'TOOLS.STATIC')
     77     cd = None
     78     if disposition is not None:
     79         if name is None:
     80             cd = disposition
     81         else:
     82             cd = '%s; filename="%s"' % (disposition, name)
     83         response.headers['Content-Disposition'] = cd
     84     if debug:
     85         cherrypy.log('Content-Disposition: %r' % cd, 'TOOLS.STATIC')
     86     return _serve_fileobj(fileobj, content_type, content_length, debug=debug)
     87 
     88 
     89 def _serve_fileobj(fileobj, content_type, content_length, debug = False):
     90     response = cherrypy.serving.response
     91     request = cherrypy.serving.request
     92     if request.protocol >= (1, 1):
     93         response.headers['Accept-Ranges'] = 'bytes'
     94         r = httputil.get_ranges(request.headers.get('Range'), content_length)
     95         if r == []:
     96             response.headers['Content-Range'] = 'bytes */%s' % content_length
     97             message = 'Invalid Range (first-byte-pos greater than Content-Length)'
     98             if debug:
     99                 cherrypy.log(message, 'TOOLS.STATIC')
    100             raise cherrypy.HTTPError(416, message)
    101         if r:
    102             if len(r) == 1:
    103                 start, stop = r[0]
    104                 if stop > content_length:
    105                     stop = content_length
    106                 r_len = stop - start
    107                 if debug:
    108                     cherrypy.log('Single part; start: %r, stop: %r' % (start, stop), 'TOOLS.STATIC')
    109                 response.status = '206 Partial Content'
    110                 response.headers['Content-Range'] = 'bytes %s-%s/%s' % (start, stop - 1, content_length)
    111                 response.headers['Content-Length'] = r_len
    112                 fileobj.seek(start)
    113                 response.body = file_generator_limited(fileobj, r_len)
    114             else:
    115                 response.status = '206 Partial Content'
    116                 from mimetools import choose_boundary
    117                 boundary = choose_boundary()
    118                 ct = 'multipart/byteranges; boundary=%s' % boundary
    119                 response.headers['Content-Type'] = ct
    120                 if 'Content-Length' in response.headers:
    121                     del response.headers['Content-Length']
    122 
    123                 def file_ranges():
    124                     yield ntob('\r\n')
    125                     for start, stop in r:
    126                         if debug:
    127                             cherrypy.log('Multipart; start: %r, stop: %r' % (start, stop), 'TOOLS.STATIC')
    128                         yield ntob('--' + boundary, 'ascii')
    129                         yield ntob('\r\nContent-type: %s' % content_type, 'ascii')
    130                         yield ntob('\r\nContent-range: bytes %s-%s/%s\r\n\r\n' % (start, stop - 1, content_length), 'ascii')
    131                         fileobj.seek(start)
    132                         for chunk in file_generator_limited(fileobj, stop - start):
    133                             yield chunk
    134 
    135                         yield ntob('\r\n')
    136 
    137                     yield ntob('--' + boundary + '--', 'ascii')
    138                     yield ntob('\r\n')
    139 
    140                 response.body = file_ranges()
    141             return response.body
    142         if debug:
    143             cherrypy.log('No byteranges requested', 'TOOLS.STATIC')
    144     response.headers['Content-Length'] = content_length
    145     response.body = fileobj
    146     return response.body
    147 
    148 
    149 def serve_download(path, name = None):
    150     return serve_file(path, 'application/x-download', 'attachment', name)
    151 
    152 
    153 def _attempt(filename, content_types, debug = False):
    154     if debug:
    155         cherrypy.log('Attempting %r (content_types %r)' % (filename, content_types), 'TOOLS.STATICDIR')
    156     try:
    157         content_type = None
    158         if content_types:
    159             r, ext = os.path.splitext(filename)
    160             content_type = content_types.get(ext[1:], None)
    161         serve_file(filename, content_type=content_type, debug=debug)
    162         return True
    163     except cherrypy.NotFound:
    164         if debug:
    165             cherrypy.log('NotFound', 'TOOLS.STATICFILE')
    166         return False
    167 
    168 
    169 def staticdir(section, dir, root = '', match = '', content_types = None, index = '', debug = False):
    170     request = cherrypy.serving.request
    171     if request.method not in ('GET', 'HEAD'):
    172         if debug:
    173             cherrypy.log('request.method not GET or HEAD', 'TOOLS.STATICDIR')
    174         return False
    175     if match and not re.search(match, request.path_info):
    176         if debug:
    177             cherrypy.log('request.path_info %r does not match pattern %r' % (request.path_info, match), 'TOOLS.STATICDIR')
    178         return False
    179     dir = os.path.expanduser(dir)
    180     if not os.path.isabs(dir):
    181         if not root:
    182             msg = 'Static dir requires an absolute dir (or root).'
    183             if debug:
    184                 cherrypy.log(msg, 'TOOLS.STATICDIR')
    185             raise ValueError(msg)
    186         dir = os.path.join(root, dir)
    187     if section == 'global':
    188         section = '/'
    189     section = section.rstrip('\\/')
    190     branch = request.path_info[len(section) + 1:]
    191     branch = unquote(branch.lstrip('\\/'))
    192     filename = os.path.join(dir, branch)
    193     if debug:
    194         cherrypy.log('Checking file %r to fulfill %r' % (filename, request.path_info), 'TOOLS.STATICDIR')
    195     if not os.path.normpath(filename).startswith(os.path.normpath(dir)):
    196         raise cherrypy.HTTPError(403)
    197     handled = _attempt(filename, content_types)
    198     if not handled:
    199         if index:
    200             handled = _attempt(os.path.join(filename, index), content_types)
    201             if handled:
    202                 request.is_index = filename[-1] in '\\/'
    203     return handled
    204 
    205 
    206 def staticfile(filename, root = None, match = '', content_types = None, debug = False):
    207     request = cherrypy.serving.request
    208     if request.method not in ('GET', 'HEAD'):
    209         if debug:
    210             cherrypy.log('request.method not GET or HEAD', 'TOOLS.STATICFILE')
    211         return False
    212     if match and not re.search(match, request.path_info):
    213         if debug:
    214             cherrypy.log('request.path_info %r does not match pattern %r' % (request.path_info, match), 'TOOLS.STATICFILE')
    215         return False
    216     if not os.path.isabs(filename):
    217         if not root:
    218             msg = "Static tool requires an absolute filename (got '%s')." % filename
    219             if debug:
    220                 cherrypy.log(msg, 'TOOLS.STATICFILE')
    221             raise ValueError(msg)
    222         filename = os.path.join(root, filename)
    223     return _attempt(filename, content_types, debug=debug)