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

formparser.py (7606B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\carbon\common\lib\werkzeug\formparser.py
      2 import re
      3 from cStringIO import StringIO
      4 from tempfile import TemporaryFile
      5 from itertools import chain, repeat
      6 from werkzeug._internal import _decode_unicode, _empty_stream
      7 _empty_string_iter = repeat('')
      8 _multipart_boundary_re = re.compile('^[ -~]{0,200}[!-~]$')
      9 _supported_multipart_encodings = frozenset(['base64', 'quoted-printable'])
     10 
     11 def default_stream_factory(total_content_length, filename, content_type, content_length = None):
     12     if total_content_length > 512000:
     13         return TemporaryFile('wb+')
     14     return StringIO()
     15 
     16 
     17 def parse_form_data(environ, stream_factory = None, charset = 'utf-8', errors = 'ignore', max_form_memory_size = None, max_content_length = None, cls = None, silent = True):
     18     content_type, extra = parse_options_header(environ.get('CONTENT_TYPE', ''))
     19     try:
     20         content_length = int(environ['CONTENT_LENGTH'])
     21     except (KeyError, ValueError):
     22         content_length = 0
     23 
     24     if cls is None:
     25         cls = MultiDict
     26     if max_content_length is not None and content_length > max_content_length:
     27         raise RequestEntityTooLarge()
     28     stream = _empty_stream
     29     files = ()
     30     if content_type == 'multipart/form-data':
     31         try:
     32             form, files = parse_multipart(environ['wsgi.input'], extra.get('boundary'), content_length, stream_factory, charset, errors, max_form_memory_size=max_form_memory_size)
     33         except ValueError as e:
     34             if not silent:
     35                 raise
     36             form = cls()
     37         else:
     38             form = cls(form)
     39 
     40     elif content_type == 'application/x-www-form-urlencoded' or content_type == 'application/x-url-encoded':
     41         if max_form_memory_size is not None and content_length > max_form_memory_size:
     42             raise RequestEntityTooLarge()
     43         form = url_decode(environ['wsgi.input'].read(content_length), charset, errors=errors, cls=cls)
     44     else:
     45         form = cls()
     46         stream = LimitedStream(environ['wsgi.input'], content_length)
     47     return (stream, form, cls(files))
     48 
     49 
     50 def _fix_ie_filename(filename):
     51     if filename[1:3] == ':\\' or filename[:2] == '\\\\':
     52         return filename.split('\\')[-1]
     53     return filename
     54 
     55 
     56 def _line_parse(line):
     57     if line[-2:] == '\r\n':
     58         return (line[:-2], True)
     59     if line[-1:] in '\r\n':
     60         return (line[:-1], True)
     61     return (line, False)
     62 
     63 
     64 def _find_terminator(iterator):
     65     for line in iterator:
     66         if not line:
     67             break
     68         line = line.strip()
     69         if line:
     70             return line
     71 
     72     return ''
     73 
     74 
     75 def is_valid_multipart_boundary(boundary):
     76     return _multipart_boundary_re.match(boundary) is not None
     77 
     78 
     79 def parse_multipart(file, boundary, content_length, stream_factory = None, charset = 'utf-8', errors = 'ignore', buffer_size = 10240, max_form_memory_size = None):
     80     if stream_factory is None:
     81         stream_factory = default_stream_factory
     82     if not boundary:
     83         raise ValueError('Missing boundary')
     84     if not is_valid_multipart_boundary(boundary):
     85         raise ValueError('Invalid boundary: %s' % boundary)
     86     if len(boundary) > buffer_size:
     87         raise ValueError('Boundary longer than buffer size')
     88     total_content_length = content_length
     89     next_part = '--' + boundary
     90     last_part = next_part + '--'
     91     form = []
     92     files = []
     93     in_memory = 0
     94     file = LimitedStream(file, content_length)
     95     iterator = chain(make_line_iter(file, buffer_size=buffer_size), _empty_string_iter)
     96     try:
     97         terminator = _find_terminator(iterator)
     98         if terminator != next_part:
     99             raise ValueError('Expected boundary at start of multipart data')
    100         while terminator != last_part:
    101             headers = parse_multipart_headers(iterator)
    102             disposition = headers.get('content-disposition')
    103             if disposition is None:
    104                 raise ValueError('Missing Content-Disposition header')
    105             disposition, extra = parse_options_header(disposition)
    106             name = extra.get('name')
    107             transfer_encoding = headers.get('content-transfer-encoding')
    108             try_decode = transfer_encoding is not None and transfer_encoding in _supported_multipart_encodings
    109             filename = extra.get('filename')
    110             if filename is None:
    111                 is_file = False
    112                 container = []
    113                 _write = container.append
    114                 guard_memory = max_form_memory_size is not None
    115             else:
    116                 content_type = headers.get('content-type')
    117                 content_type = parse_options_header(content_type)[0] or 'text/plain'
    118                 is_file = True
    119                 guard_memory = False
    120                 if filename is not None:
    121                     filename = _fix_ie_filename(_decode_unicode(filename, charset, errors))
    122                 try:
    123                     content_length = int(headers['content-length'])
    124                 except (KeyError, ValueError):
    125                     content_length = 0
    126 
    127                 container = stream_factory(total_content_length, content_type, filename, content_length)
    128                 _write = container.write
    129             buf = ''
    130             for line in iterator:
    131                 if not line:
    132                     raise ValueError('unexpected end of stream')
    133                 if line[:2] == '--':
    134                     terminator = line.rstrip()
    135                     if terminator in (next_part, last_part):
    136                         break
    137                 if try_decode:
    138                     try:
    139                         line = line.decode(transfer_encoding)
    140                     except:
    141                         raise ValueError('could not decode transfer encoded chunk')
    142 
    143                 if buf:
    144                     _write(buf)
    145                     buf = ''
    146                 if line[-2:] == '\r\n':
    147                     buf = '\r\n'
    148                     cutoff = -2
    149                 else:
    150                     buf = line[-1]
    151                     cutoff = -1
    152                 _write(line[:cutoff])
    153                 if guard_memory:
    154                     in_memory += len(line)
    155                     if in_memory > max_form_memory_size:
    156                         from werkzeug.exceptions import RequestEntityTooLarge
    157                         raise RequestEntityTooLarge()
    158             else:
    159                 raise ValueError('unexpected end of part')
    160 
    161             if is_file:
    162                 container.seek(0)
    163                 files.append((name, FileStorage(container, filename, name, content_type, content_length, headers)))
    164             else:
    165                 form.append((name, _decode_unicode(''.join(container), charset, errors)))
    166 
    167     finally:
    168         file.exhaust()
    169 
    170     return (form, files)
    171 
    172 
    173 def parse_multipart_headers(iterable):
    174     result = []
    175     for line in iterable:
    176         line, line_terminated = _line_parse(line)
    177         if not line_terminated:
    178             raise ValueError('unexpected end of line in multipart header')
    179         if not line:
    180             break
    181         elif line[0] in ' \t' and result:
    182             key, value = result[-1]
    183             result[-1] = (key, value + '\n ' + line[1:])
    184         else:
    185             parts = line.split(':', 1)
    186             if len(parts) == 2:
    187                 result.append((parts[0].strip(), parts[1].strip()))
    188 
    189     return Headers.linked(result)
    190 
    191 
    192 from werkzeug.urls import url_decode
    193 from werkzeug.wsgi import LimitedStream, make_line_iter
    194 from werkzeug.exceptions import RequestEntityTooLarge
    195 from werkzeug.datastructures import Headers, FileStorage, MultiDict
    196 from werkzeug.http import parse_options_header