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

http.py (8856B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\carbon\common\lib\werkzeug\http.py
      2 import re
      3 import inspect
      4 try:
      5     from email.utils import parsedate_tz
      6 except ImportError:
      7     from email.Utils import parsedate_tz
      8 
      9 from urllib2 import parse_http_list as _parse_list_header
     10 from datetime import datetime, timedelta
     11 try:
     12     from hashlib import md5
     13 except ImportError:
     14     from md5 import new as md5
     15 
     16 from werkzeug._internal import HTTP_STATUS_CODES
     17 _accept_re = re.compile('([^\\s;,]+)(?:[^,]*?;\\s*q=(\\d*(?:\\.\\d+)?))?')
     18 _token_chars = frozenset("!#$%&'*+-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ^_`abcdefghijklmnopqrstuvwxyz|~")
     19 _etag_re = re.compile('([Ww]/)?(?:"(.*?)"|(.*?))(?:\\s*,\\s*|$)')
     20 _unsafe_header_chars = set('()<>@,;:"/[]?={} \t')
     21 _quoted_string_re = '"[^"\\\\]*(?:\\\\.[^"\\\\]*)*"'
     22 _option_header_piece_re = re.compile(';\\s*([^\\s;=]+|%s)\\s*(?:=\\s*([^;]+|%s))?\\s*' % (_quoted_string_re, _quoted_string_re))
     23 _entity_headers = frozenset(['allow',
     24  'content-encoding',
     25  'content-language',
     26  'content-length',
     27  'content-location',
     28  'content-md5',
     29  'content-range',
     30  'content-type',
     31  'expires',
     32  'last-modified'])
     33 _hop_by_pop_headers = frozenset(['connection',
     34  'keep-alive',
     35  'proxy-authenticate',
     36  'proxy-authorization',
     37  'te',
     38  'trailers',
     39  'transfer-encoding',
     40  'upgrade'])
     41 
     42 def quote_header_value(value, extra_chars = '', allow_token = True):
     43     value = str(value)
     44     if allow_token:
     45         token_chars = _token_chars | set(extra_chars)
     46         if set(value).issubset(token_chars):
     47             return value
     48     return '"%s"' % value.replace('\\', '\\\\').replace('"', '\\"')
     49 
     50 
     51 def unquote_header_value(value, is_filename = False):
     52     if value and value[0] == value[-1] == '"':
     53         value = value[1:-1]
     54         if not is_filename or value[:2] != '\\\\':
     55             return value.replace('\\\\', '\\').replace('\\"', '"')
     56     return value
     57 
     58 
     59 def dump_options_header(header, options):
     60     segments = []
     61     if header is not None:
     62         segments.append(header)
     63     for key, value in options.iteritems():
     64         if value is None:
     65             segments.append(key)
     66         else:
     67             segments.append('%s=%s' % (key, quote_header_value(value)))
     68 
     69     return '; '.join(segments)
     70 
     71 
     72 def dump_header(iterable, allow_token = True):
     73     if isinstance(iterable, dict):
     74         items = []
     75         for key, value in iterable.iteritems():
     76             if value is None:
     77                 items.append(key)
     78             else:
     79                 items.append('%s=%s' % (key, quote_header_value(value, allow_token=allow_token)))
     80 
     81     else:
     82         items = [ quote_header_value(x, allow_token=allow_token) for x in iterable ]
     83     return ', '.join(items)
     84 
     85 
     86 def parse_list_header(value):
     87     result = []
     88     for item in _parse_list_header(value):
     89         if item[:1] == item[-1:] == '"':
     90             item = unquote_header_value(item[1:-1])
     91         result.append(item)
     92 
     93     return result
     94 
     95 
     96 def parse_dict_header(value):
     97     result = {}
     98     for item in _parse_list_header(value):
     99         if '=' not in item:
    100             result[item] = None
    101             continue
    102         name, value = item.split('=', 1)
    103         if value[:1] == value[-1:] == '"':
    104             value = unquote_header_value(value[1:-1])
    105         result[name] = value
    106 
    107     return result
    108 
    109 
    110 def parse_options_header(value):
    111 
    112     def _tokenize(string):
    113         for match in _option_header_piece_re.finditer(string):
    114             key, value = match.groups()
    115             key = unquote_header_value(key)
    116             if value is not None:
    117                 value = unquote_header_value(value, key == 'filename')
    118             yield (key, value)
    119 
    120     if not value:
    121         return ('', {})
    122     parts = _tokenize(';' + value)
    123     name = parts.next()[0]
    124     extra = dict(parts)
    125     return (name, extra)
    126 
    127 
    128 def parse_accept_header(value, cls = None):
    129     if cls is None:
    130         cls = Accept
    131     if not value:
    132         return cls(None)
    133     result = []
    134     for match in _accept_re.finditer(value):
    135         quality = match.group(2)
    136         if not quality:
    137             quality = 1
    138         else:
    139             quality = max(min(float(quality), 1), 0)
    140         result.append((match.group(1), quality))
    141 
    142     return cls(result)
    143 
    144 
    145 def parse_cache_control_header(value, on_update = None, cls = None):
    146     if cls is None:
    147         cls = RequestCacheControl
    148     if not value:
    149         return cls(None, on_update)
    150     return cls(parse_dict_header(value), on_update)
    151 
    152 
    153 def parse_set_header(value, on_update = None):
    154     if not value:
    155         return HeaderSet(None, on_update)
    156     return HeaderSet(parse_list_header(value), on_update)
    157 
    158 
    159 def parse_authorization_header(value):
    160     if not value:
    161         return
    162     try:
    163         auth_type, auth_info = value.split(None, 1)
    164         auth_type = auth_type.lower()
    165     except ValueError:
    166         return
    167 
    168     if auth_type == 'basic':
    169         try:
    170             username, password = auth_info.decode('base64').split(':', 1)
    171         except Exception as e:
    172             return
    173 
    174         return Authorization('basic', {'username': username,
    175          'password': password})
    176     if auth_type == 'digest':
    177         auth_map = parse_dict_header(auth_info)
    178         for key in ('username', 'realm', 'nonce', 'uri', 'nc', 'cnonce', 'response'):
    179             if key not in auth_map:
    180                 return
    181 
    182         return Authorization('digest', auth_map)
    183 
    184 
    185 def parse_www_authenticate_header(value, on_update = None):
    186     if not value:
    187         return WWWAuthenticate(on_update=on_update)
    188     try:
    189         auth_type, auth_info = value.split(None, 1)
    190         auth_type = auth_type.lower()
    191     except (ValueError, AttributeError):
    192         return WWWAuthenticate(value.strip().lower(), on_update=on_update)
    193 
    194     return WWWAuthenticate(auth_type, parse_dict_header(auth_info), on_update)
    195 
    196 
    197 def quote_etag(etag, weak = False):
    198     if '"' in etag:
    199         raise ValueError('invalid etag')
    200     etag = '"%s"' % etag
    201     if weak:
    202         etag = 'w/' + etag
    203     return etag
    204 
    205 
    206 def unquote_etag(etag):
    207     if not etag:
    208         return (None, None)
    209     etag = etag.strip()
    210     weak = False
    211     if etag[:2] in ('w/', 'W/'):
    212         weak = True
    213         etag = etag[2:]
    214     if etag[:1] == etag[-1:] == '"':
    215         etag = etag[1:-1]
    216     return (etag, weak)
    217 
    218 
    219 def parse_etags(value):
    220     if not value:
    221         return ETags()
    222     strong = []
    223     weak = []
    224     end = len(value)
    225     pos = 0
    226     while pos < end:
    227         match = _etag_re.match(value, pos)
    228         if match is None:
    229             break
    230         is_weak, quoted, raw = match.groups()
    231         if raw == '*':
    232             return ETags(star_tag=True)
    233         if quoted:
    234             raw = quoted
    235         if is_weak:
    236             weak.append(raw)
    237         else:
    238             strong.append(raw)
    239         pos = match.end()
    240 
    241     return ETags(strong, weak)
    242 
    243 
    244 def generate_etag(data):
    245     return md5(data).hexdigest()
    246 
    247 
    248 def parse_date(value):
    249     if value:
    250         t = parsedate_tz(value.strip())
    251         if t is not None:
    252             try:
    253                 year = t[0]
    254                 if year >= 0 and year <= 68:
    255                     year += 2000
    256                 elif year >= 69 and year <= 99:
    257                     year += 1900
    258                 return datetime(*((year,) + t[1:7])) - timedelta(seconds=t[-1] or 0)
    259             except (ValueError, OverflowError):
    260                 return
    261 
    262 
    263 def is_resource_modified(environ, etag = None, data = None, last_modified = None):
    264     if etag is None and data is not None:
    265         etag = generate_etag(data)
    266     elif data is not None:
    267         raise TypeError('both data and etag given')
    268     if environ['REQUEST_METHOD'] not in ('GET', 'HEAD'):
    269         return False
    270     unmodified = False
    271     if isinstance(last_modified, basestring):
    272         last_modified = parse_date(last_modified)
    273     modified_since = parse_date(environ.get('HTTP_IF_MODIFIED_SINCE'))
    274     if modified_since and last_modified and last_modified <= modified_since:
    275         unmodified = True
    276     if etag:
    277         if_none_match = parse_etags(environ.get('HTTP_IF_NONE_MATCH'))
    278         if if_none_match:
    279             unmodified = if_none_match.contains_raw(etag)
    280     return not unmodified
    281 
    282 
    283 def remove_entity_headers(headers, allowed = ('expires', 'content-location')):
    284     allowed = set((x.lower() for x in allowed))
    285     headers[:] = [ (key, value) for key, value in headers if not is_entity_header(key) or key.lower() in allowed ]
    286 
    287 
    288 def remove_hop_by_hop_headers(headers):
    289     headers[:] = [ (key, value) for key, value in headers if not is_hop_by_hop_header(key) ]
    290 
    291 
    292 def is_entity_header(header):
    293     return header.lower() in _entity_headers
    294 
    295 
    296 def is_hop_by_hop_header(header):
    297     return header.lower() in _hop_by_pop_headers
    298 
    299 
    300 from werkzeug.datastructures import Headers, Accept, RequestCacheControl, ResponseCacheControl, HeaderSet, ETags, Authorization, WWWAuthenticate
    301 from werkzeug.datastructures import MIMEAccept, CharsetAccept, LanguageAccept