Package cherrypy :: Package lib :: Module safemime
[hide private]
[frames] | no frames]

Source Code for Module cherrypy.lib.safemime

  1  import cherrypy 
  2   
  3   
4 -class MultipartWrapper(object):
5 """Wraps a file-like object, returning '' when Content-Length is reached. 6 7 The cgi module's logic for reading multipart MIME messages doesn't 8 allow the parts to know when the Content-Length for the entire message 9 has been reached, and doesn't allow for multipart-MIME messages that 10 omit the trailing CRLF (Flash 8's FileReference.upload(url), for example, 11 does this). The read_lines_to_outerboundary function gets stuck in a loop 12 until the socket times out. 13 14 This rfile wrapper simply monitors the incoming stream. When a read is 15 attempted past the Content-Length, it returns an empty string rather 16 than timing out (of course, if the last read *overlaps* the C-L, you'll 17 get the last bit of data up to C-L, and then the next read will return 18 an empty string). 19 """ 20
21 - def __init__(self, rfile, clen):
22 self.rfile = rfile 23 self.clen = clen 24 self.bytes_read = 0
25
26 - def read(self, size = None):
27 if self.clen: 28 # Return '' if we've read all the data. 29 if self.bytes_read >= self.clen: 30 return '' 31 32 # Reduce 'size' if it's over our limit. 33 new_bytes_read = self.bytes_read + size 34 if new_bytes_read > self.clen: 35 size = self.clen - self.bytes_read 36 37 data = self.rfile.read(size) 38 self.bytes_read += len(data) 39 return data
40
41 - def readline(self, size = None):
42 if size is not 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.readline(size) 54 self.bytes_read += len(data) 55 return data 56 57 # User didn't specify a size ... 58 # We read the line in chunks to make sure it's not a 100MB line ! 59 res = [] 60 size = 256 61 while True: 62 if self.clen: 63 # Return if we've read all the data. 64 if self.bytes_read >= self.clen: 65 return ''.join(res) 66 67 # Reduce 'size' if it's over our limit. 68 new_bytes_read = self.bytes_read + size 69 if new_bytes_read > self.clen: 70 size = self.clen - self.bytes_read 71 72 data = self.rfile.readline(size) 73 self.bytes_read += len(data) 74 res.append(data) 75 # See http://www.cherrypy.org/ticket/421 76 if len(data) < size or data[-1:] == "\n": 77 return ''.join(res)
78
79 - def readlines(self, sizehint = 0):
80 # Shamelessly stolen from StringIO 81 total = 0 82 lines = [] 83 line = self.readline() 84 while line: 85 lines.append(line) 86 total += len(line) 87 if 0 < sizehint <= total: 88 break 89 line = self.readline() 90 return lines
91
92 - def close(self):
93 self.rfile.close()
94
95 - def __iter__(self):
96 return self.rfile
97
98 - def next(self):
99 if self.clen: 100 # Return '' if we've read all the data. 101 if self.bytes_read >= self.clen: 102 return '' 103 104 data = self.rfile.next() 105 self.bytes_read += len(data) 106 return data
107 108
109 -def safe_multipart(flash_only=False):
110 """Wrap request.rfile in a reader that won't crash on no trailing CRLF.""" 111 h = cherrypy.request.headers 112 if not h.get('Content-Type','').startswith('multipart/'): 113 return 114 if flash_only and not 'Shockwave Flash' in h.get('User-Agent', ''): 115 return 116 117 clen = h.get('Content-Length', '0') 118 try: 119 clen = int(clen) 120 except ValueError: 121 return 122 cherrypy.request.rfile = MultipartWrapper(cherrypy.request.rfile, clen)
123
124 -def init():
125 """Create a Tool for safe_multipart and add it to cherrypy.tools.""" 126 cherrypy.tools.safe_multipart = cherrypy.Tool('before_request_body', 127 safe_multipart)
128