Package turbogears :: Package filters :: Module safemultipart

Source Code for Module turbogears.filters.safemultipart

  1  # -*- coding: UTF-8 -*- 
  2  """Request filter to handle multipart uploads from buggy Flash clients.""" 
  3   
  4  __all__ = [ 
  5      'SafeMultipartFilter', 
  6      'MultipartWrapper', 
  7  ] 
  8   
  9  import logging 
 10  import re 
 11   
 12  import cherrypy 
 13  from turbogears import config 
 14   
 15   
 16  log = logging.getLogger('turbogears.filters') 
 17   
 18   
 19  # Taken from http://www.cherrypy.org/ticket/648 
20 -class MultipartWrapper(object):
21 r"""Wraps a file-like object, returning '' when Content-Length is reached. 22 23 The cgi module's logic for reading multipart MIME messages doesn't 24 allow the parts to know when the Content-Length for the entire message 25 has been reached, and doesn't allow for multipart-MIME messages that 26 omit the trailing CRLF (Flash 8's FileReference.upload(url), for example, 27 does this). The read_lines_to_outerboundary function gets stuck in a loop 28 until the socket times out. 29 30 This rfile wrapper simply monitors the incoming stream. When a read is 31 attempted past the Content-Length, it returns an empty string rather 32 than timing out (of course, if the last read *overlaps* the C-L, you'll 33 get the last bit of data up to C-L, and then the next read will return 34 an empty string). 35 36 """
37 - def __init__(self, rfile, clen):
38 self.rfile = rfile 39 self.clen = clen 40 self.bytes_read = 0
41
42 - def read(self, size=None):
43 if self.clen: 44 # Return '' if we've read all the data. 45 if self.bytes_read >= self.clen: 46 return '' 47 48 # Reduce 'size' if it's over our limit. 49 new_bytes_read = self.bytes_read + size 50 if new_bytes_read > self.clen: 51 size = self.clen - self.bytes_read 52 53 data = self.rfile.read(size) 54 self.bytes_read += len(data) 55 return data
56
57 - def readline(self, size=None):
58 if size is not None: 59 if self.clen: 60 # Return '' if we've read all the data. 61 if self.bytes_read >= self.clen: 62 return '' 63 64 # Reduce 'size' if it's over our limit. 65 new_bytes_read = self.bytes_read + size 66 if new_bytes_read > self.clen: 67 size = self.clen - self.bytes_read 68 69 data = self.rfile.readline(size) 70 self.bytes_read += len(data) 71 return data 72 73 # User didn't specify a size ... 74 # We read the line in chunks to make sure it's not a 100MB line ! 75 res = [] 76 size = 256 77 while True: 78 if self.clen: 79 # Return if we've read all the data. 80 if self.bytes_read >= self.clen: 81 return ''.join(res) 82 83 # Reduce 'size' if it's over our limit. 84 new_bytes_read = self.bytes_read + size 85 if new_bytes_read > self.clen: 86 size = self.clen - self.bytes_read 87 88 data = self.rfile.readline(size) 89 self.bytes_read += len(data) 90 res.append(data) 91 # See http://www.cherrypy.org/ticket/421 92 if len(data) < size or data[-1:] == "\n": 93 return ''.join(res)
94
95 - def readlines(self, sizehint=0):
96 # Shamelessly stolen from StringIO 97 total = 0 98 lines = [] 99 line = self.readline() 100 while line: 101 lines.append(line) 102 total += len(line) 103 if 0 < sizehint <= total: 104 break 105 line = self.readline() 106 return lines
107
108 - def close(self):
109 self.rfile.close()
110
111 - def __iter__(self):
112 return self.rfile
113
114 - def next(self):
115 if self.clen: 116 # Return '' if we've read all the data. 117 if self.bytes_read >= self.clen: 118 return '' 119 120 data = self.rfile.next() 121 self.bytes_read += len(data) 122 return data
123 124
125 -class SafeMultipartFilter:
126 """CherryPy filter to handle buggy multipart requests from Flash clients.""" 127 128 flash_ua_rx = re.compile(r'(Shockwave|Adobe)\s+Flash.*') 129
130 - def before_request_body(self):
131 if not config.get("safempfilter.on", False): 132 return 133 log.debug("Using FlashMultipartFilter for request %s.", 134 cherrypy.request.path) 135 ct = cherrypy.request.headers.get('Content-Type', '') 136 ua = cherrypy.request.headers.get('User-Agent', '') 137 138 if ct.startswith('multipart/') and self.flash_ua_rx.match(ua): 139 log.debug("Detected Flash client multipart request. " 140 "Using MulipartWrapper to read request") 141 clen = cherrypy.request.headers.get('Content-Length', '0') 142 try: 143 clen = int(clen) 144 except ValueError: 145 return 146 cherrypy.request.rfile = MultipartWrapper( 147 cherrypy.request.rfile, clen)
148