Download Install Tutorial Docs FAQ Tools WikiLicense Team IRC Planet Involvement Shop Book

Changeset 1912

Show
Ignore:
Timestamp:
03/09/08 00:40:48
Author:
fumanchu
Message:

Fix for #783 (File uploads corrupt when using built in SSL).

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • branches/598-sendall/cherrypy/test/test_http.py

    r1906 r1912  
    3939         
    4040        def post_multipart(self, file): 
    41             """Return a summary ("a * 1000000\nb * 1000000") of the uploaded file.""" 
     41            """Return a summary ("a * 65536\nb * 65536") of the uploaded file.""" 
    4242            contents = file.file.read() 
    4343            summary = [] 
     
    7070        # will hang. Verify that CP times out the socket and responds 
    7171        # with 411 Length Required. 
    72         c = httplib.HTTPConnection("127.0.0.1:%s" % self.PORT) 
     72        if self.scheme == "https": 
     73            c = httplib.HTTPSConnection("127.0.0.1:%s" % self.PORT) 
     74        else: 
     75            c = httplib.HTTPConnection("127.0.0.1:%s" % self.PORT) 
    7376        c.request("POST", "/") 
    7477        self.assertEqual(c.getresponse().status, 411) 
     
    7780        alphabet = "abcdefghijklmnopqrstuvwxyz" 
    7881        # generate file contents for a large post 
    79         contents = "".join([c * 1000000 for c in alphabet]) 
     82        contents = "".join([c * 65536 for c in alphabet]) 
    8083         
    8184        # encode as multipart form data 
     
    98101         
    99102        response_body = c.file.read() 
    100         self.assertEquals(", ".join(["%s * 1000000" % c for c in alphabet]), 
     103        self.assertEquals(", ".join(["%s * 65536" % c for c in alphabet]), 
    101104                          response_body) 
    102105 
  • branches/598-sendall/cherrypy/wsgiserver/__init__.py

    r1911 r1912  
    193193    def readline(self, size=None): 
    194194        if size is not None: 
    195             local_bytes_seen = 0 
    196             seen_data = [] 
    197             while local_bytes_seen < size: 
    198                 data = self.rfile.readline(size-local_bytes_seen) 
    199                 if not data: 
    200                     break 
    201                 seen_data.append(data) 
    202                 local_bytes_seen += len(data) 
    203                 if '\n' in data: 
    204                     break 
    205  
    206             self.bytes_read += local_bytes_seen 
     195            data = self.rfile.readline(size) 
     196            self.bytes_read += len(data) 
    207197            self._check_length() 
    208             return "".join(seen_data) 
     198            return data 
    209199         
    210200        # User didn't specify a size ... 
     
    244234        self._check_length() 
    245235        return data 
    246  
    247 class HTTPRequestSocketWrapper(object): 
    248     """ 
    249     A file like wrapper for HTTP on non-blocking sockets. 
    250  
    251     IOW this class provides as much as it can of the file like  
    252     interface for sockets over which HTTP requests are made. 
    253     """ 
    254     def __init__(self, sock): 
    255         self.sock = sock 
    256         self.incomplete_line_buffer = [] 
    257         self.lines_buffer = [] 
    258      
    259     def read(self, size=None): 
    260         raise NotImplementedError 
    261      
    262     def readline(self): 
    263         # This doesn't raise the appropriate exceptions 
    264         # as the result may result in an Index Error? 
    265  
    266         # if we can't return their data right away, let's try to read (blocking) 
    267         if not self.lines_buffer: 
    268             self._fill_lines_buffer() 
    269  
    270         if not self.lines_buffer: 
    271             return "" 
    272          
    273         return self.lines_buffer.pop(0) 
    274  
    275              
    276     def _fill_lines_buffer(self): 
    277         while True: 
    278             data = self.sock.recv(256) 
    279  
    280             lines = data.split("\n") 
    281             # We remove the last piece of the split to ensure 
    282             # that subsequent processing happens only on data 
    283             # Representing complete lines. 
    284             new_incomplete_line = lines.pop() 
    285              
    286             # If we still have data in the lines list that means 
    287             # we have received some data that forms a complete line 
    288             if lines: 
    289                 # Ensure that we take the data left over from previous reads 
    290                 # and join it to our current reads before appending the latest 
    291                 # line seen 
    292                 self.incomplete_line_buffer.append(lines.pop(0)) 
    293                 self.lines_buffer.append("".join(self.incomplete_line_buffer)) 
    294  
    295                 self.incomplete_line_buffer = [] 
    296  
    297                 # remember all other complete lines seen in this read 
    298                 self.lines_buffer.extend(lines) 
    299                 
    300             # Record the latest new incomplete line 
    301             self.incomplete_line_buffer.append(new_incomplete_line) 
    302  
    303             # If they didn't specify a size and we have a line to send them 
    304             # stop reading 
    305             if self.lines_buffer: 
    306                 return 
    307      
    308     def readlines(self, sizehint=0): 
    309         raise NotImplementedError 
    310      
    311     def close(self): 
    312         self.sock.close() 
    313      
    314     def __iter__(self): 
    315         return self 
    316      
    317     def next(self): 
    318         data = self.sock.next() 
    319         self.bytes_read += len(data) 
    320         return data 
    321  
    322     def send(self, *args, **kwargs): 
    323         return self.sock.send(*args, **kwargs) 
    324  
    325     def readline(self, size=None): 
    326         raise NotImplementedError 
    327236 
    328237 
     
    782691 
    783692 
    784 def _ssl_wrap_method(method, is_reader=False): 
    785     """Wrap the given method with SSL error-trapping. 
    786      
    787     is_reader: if False (the default), EOF errors will be raised. 
    788         If True, EOF errors will return "" (to emulate normal sockets). 
    789     """ 
    790     def ssl_method_wrapper(self, *args, **kwargs): 
    791 ##        print (id(self), method, args, kwargs) 
     693class SSL_fileobject(socket._fileobject): 
     694    """Faux file object attached to a socket object.""" 
     695     
     696    ssl_timeout = 3 
     697    ssl_retry = .01 
     698     
     699    def _safe_call(self, is_reader, call, *args, **kwargs): 
     700        """Wrap the given call with SSL error-trapping. 
     701         
     702        is_reader: if False EOF errors will be raised. If True, EOF errors 
     703            will return "" (to emulate normal sockets). 
     704        """ 
    792705        start = time.time() 
    793706        while True: 
    794707            try: 
    795                 return method(self, *args, **kwargs) 
     708                return call(*args, **kwargs) 
    796709            except (SSL.WantReadError, SSL.WantWriteError): 
    797710                # Sleep and try again. This is dangerous, because it means 
     
    828741            if time.time() - start > self.ssl_timeout: 
    829742                raise socket.timeout("timed out") 
    830     return ssl_method_wrapper 
    831  
    832 class SSL_fileobject(socket._fileobject): 
    833     """Faux file object attached to a socket object.""" 
    834      
    835     ssl_timeout = 3 
    836     ssl_retry = .01 
    837      
    838     close = _ssl_wrap_method(socket._fileobject.close) 
    839     flush = _ssl_wrap_method(socket._fileobject.flush) 
    840     write = _ssl_wrap_method(socket._fileobject.write) 
    841     writelines = _ssl_wrap_method(socket._fileobject.writelines) 
    842     read = _ssl_wrap_method(socket._fileobject.read, is_reader=True) 
    843     readline = _ssl_wrap_method(socket._fileobject.readline, is_reader=True) 
    844     readlines = _ssl_wrap_method(socket._fileobject.readlines, is_reader=True) 
     743     
     744    def flush(self): 
     745        if self._wbuf: 
     746            buffer = "".join(self._wbuf) 
     747            self._wbuf = [] 
     748            self._safe_call(False, self._sock.sendall, buffer) 
     749     
     750    def read(self, size=-1): 
     751        data = self._rbuf 
     752        if size < 0: 
     753            # Read until EOF 
     754            buffers = [] 
     755            if data: 
     756                buffers.append(data) 
     757            self._rbuf = "" 
     758            if self._rbufsize <= 1: 
     759                recv_size = self.default_bufsize 
     760            else: 
     761                recv_size = self._rbufsize 
     762             
     763            while True: 
     764                data = self._safe_call(True, self._sock.recv, recv_size) 
     765                if not data: 
     766                    break 
     767                buffers.append(data) 
     768            return "".join(buffers) 
     769        else: 
     770            # Read until size bytes or EOF seen, whichever comes first 
     771            buf_len = len(data) 
     772            if buf_len >= size: 
     773                self._rbuf = data[size:] 
     774                return data[:size] 
     775            buffers = [] 
     776            if data: 
     777                buffers.append(data) 
     778            self._rbuf = "" 
     779            while True: 
     780                left = size - buf_len 
     781                recv_size = max(self._rbufsize, left) 
     782                data = self._safe_call(True, self._sock.recv, recv_size) 
     783                if not data: 
     784                    break 
     785                buffers.append(data) 
     786                n = len(data) 
     787                if n >= left: 
     788                    self._rbuf = data[left:] 
     789                    buffers[-1] = data[:left] 
     790                    break 
     791                buf_len += n 
     792            return "".join(buffers) 
     793 
     794    def readline(self, size=-1): 
     795        data = self._rbuf 
     796        if size < 0: 
     797            # Read until \n or EOF, whichever comes first 
     798            if self._rbufsize <= 1: 
     799                # Speed up unbuffered case 
     800                assert data == "" 
     801                buffers = [] 
     802                while data != "\n": 
     803                    data = self._safe_call(True, self._sock.recv, 1) 
     804                    if not data: 
     805                        break 
     806                    buffers.append(data) 
     807                return "".join(buffers) 
     808            nl = data.find('\n') 
     809            if nl >= 0: 
     810                nl += 1 
     811                self._rbuf = data[nl:] 
     812                return data[:nl] 
     813            buffers = [] 
     814            if data: 
     815                buffers.append(data) 
     816            self._rbuf = "" 
     817            while True: 
     818                data = self._safe_call(True, self._sock.recv, self._rbufsize) 
     819                if not data: 
     820                    break 
     821                buffers.append(data) 
     822                nl = data.find('\n') 
     823                if nl >= 0: 
     824                    nl += 1 
     825                    self._rbuf = data[nl:] 
     826                    buffers[-1] = data[:nl] 
     827                    break 
     828            return "".join(buffers) 
     829        else: 
     830            # Read until size bytes or \n or EOF seen, whichever comes first 
     831            nl = data.find('\n', 0, size) 
     832            if nl >= 0: 
     833                nl += 1 
     834                self._rbuf = data[nl:] 
     835                return data[:nl] 
     836            buf_len = len(data) 
     837            if buf_len >= size: 
     838                self._rbuf = data[size:] 
     839                return data[:size] 
     840            buffers = [] 
     841            if data: 
     842                buffers.append(data) 
     843            self._rbuf = "" 
     844            while True: 
     845                data = self._safe_call(True, self._sock.recv, self._rbufsize) 
     846                if not data: 
     847                    break 
     848                buffers.append(data) 
     849                left = size - buf_len 
     850                nl = data.find('\n', 0, left) 
     851                if nl >= 0: 
     852                    nl += 1 
     853                    self._rbuf = data[nl:] 
     854                    buffers[-1] = data[:nl] 
     855                    break 
     856                n = len(data) 
     857                if n >= left: 
     858                    self._rbuf = data[left:] 
     859                    buffers[-1] = data[:left] 
     860                    break 
     861                buf_len += n 
     862            return "".join(buffers) 
    845863     
    846864    def send(self, *args, **kwargs): 
    847         return self._sock.send(*args, **kwargs) 
    848     send = _ssl_wrap_method(send) 
     865        return self._safe_call(False, self._sock.send, *args, **kwargs) 
     866 
    849867 
    850868class HTTPConnection(object): 
     
    916934            if errnum not in socket_errors_to_ignore: 
    917935                if req: 
    918                     fd = open ("ssl_errors.txt", "a") 
     936                    fd = open("ssl_errors.txt", "a") 
    919937                    fd.write("1" * 80) 
    920938                    fd.write("\n") 
    921939                    fd.write(str(type(e))) 
    922                     fd.write( format_exc()) 
     940                    fd.write(format_exc()) 
    923941                    req.simple_response("500 Internal Server Error", 
    924942                                        format_exc()) 
     
    934952        except Exception, e: 
    935953            if req: 
    936                 fd = open ("ssl_errors.txt", "a") 
    937                 fd.write("2" * 80
     954                fd = open("ssl_errors.txt", "a") 
     955                fd.write("2" * 80
    938956                fd.write("\n") 
    939                 fd.write(str(type(e))) 
    940                 fd.write( format_exc()) 
     957                fd.write(format_exc()) 
    941958                req.simple_response("500 Internal Server Error", format_exc()) 
    942959     

Hosted by WebFaction

Log in as guest/cpguest to create tickets