Changeset 7040 for ceda_http_fileserver


Ignore:
Timestamp:
21/06/10 12:24:14 (9 years ago)
Author:
pjkersha
Message:

Incomplete - task 9: Data Browser Replacement

  • fixed client byte range requests bug - added 'bytes=' prefix and added support for default start and end indices e.g. bytes=-9 or bytes=100-
Location:
ceda_http_fileserver/trunk/ceda_http_fileserver
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • ceda_http_fileserver/trunk/ceda_http_fileserver/ceda/server/wsgi/fileserver/app.py

    r7038 r7040  
    5656    """Helper class creates iterable response based on a given block size""" 
    5757    DEFAULT_BLK_SIZE = 1024 
     58    BYTE_RANGE_PREFIX = 'bytes=' 
    5859    BYTE_RANGE_SEP = '-' 
    5960    CONTENT_RANGE_FIELDNAME = 'Content-range' 
    60     CONTENT_RANGE_FORMAT_STR = "%d-%d/%d" 
    61     INVALID_CONTENT_RANGE_FORMAT_STR = "*/%d" 
     61    CONTENT_RANGE_FORMAT_STR = "bytes %d-%d/%d" 
     62    INVALID_CONTENT_RANGE_FORMAT_STR = "bytes */%d" 
    6263     
    6364    __slots__ = ( 
     
    100101        except IOError: 
    101102            log.error('Failed to open file %r: %s', filePath,  
    102                       traceback.format_exc())      
     103                      traceback.format_exc())  
     104            raise     
    103105         
    104106        self.fileSize = os.path.getsize(filePath) 
     
    112114                                 
    113115            try: 
    114                 start, end = [ 
    115                     int(i)  
    116                     for i in requestRange.split(FileResponse.BYTE_RANGE_SEP) 
    117                 ] 
     116                # Remove 'bytes=' prefix 
     117                rangeVals = requestRange.split( 
     118                                        self.__class__.BYTE_RANGE_PREFIX)[-1] 
     119                                         
     120                # Convert into integers taking into account that a value may be 
     121                # absent 
     122                startStr, endStr = rangeVals.split( 
     123                                                self.__class__.BYTE_RANGE_SEP) 
     124                start = int(startStr or 0) 
     125                end = int(endStr or self.fileSize - 1) 
    118126            except ValueError: 
    119127                raise InvalidRangeRequestSyntax('Invalid format for request ' 
     
    129137                raise InvalidRangeRequest('Range start index %r is less than ' 
    130138                                          'zero' % start, 
    131                                           contentRangeHdr) 
     139                                          contentRangeHdr)  
     140            elif end >= self.fileSize: 
     141                # This is not an error -  
     142                # http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35.1 
     143                log.warning('Range end index %r is greater than the length %r ' 
     144                            'of the requested resource %r - reseting to %r', 
     145                            end, self.fileSize, filePath, self.fileSize - 1) 
     146                end = self.fileSize - 1 
    132147                 
    133             elif end >= self.fileSize: 
    134                 raise InvalidRangeRequest('Range end index %r is greater than ' 
    135                                           'the length %r of the requested ' 
    136                                           'resource %r' % (end,  
    137                                                            self.fileSize, 
    138                                                            filePath), 
    139                                           contentRangeHdr) 
    140          
    141148            # Set the total content length to return 
    142149            self.contentLength = end + 1 - start  
     
    506513                                            blkSize=self.writeBlkSize, 
    507514                                            requestRange=requestRange) 
    508                 fileObj = open(filePath, 'rb') 
    509                 log.debug('opened file %s', filePath) 
    510                  
    511515            except IOError, e: 
    512516                # Map file access error to a HTTP response code 
     
    521525                # Byte range was requested for extraction but it was badly  
    522526                # formatted 
    523                 response = str(e) 
     527                response = "%s\n" % e 
    524528                log.error(response) 
    525529                status = FileServerApp.statusCode2Msg(httplib.BAD_REQUEST) 
     
    532536                # Byte range was requested for extraction but it's invalid for 
    533537                # the requested file 
    534                 response = str(e) 
     538                response = "%s\n" % e 
    535539                log.error(response) 
    536540                status = FileServerApp.statusCode2Msg( 
  • ceda_http_fileserver/trunk/ceda_http_fileserver/ceda/server/wsgi/fileserver/test/test_fileserver.py

    r7038 r7040  
    215215    def test15RetrieveRange(self): 
    216216        # Specify a range of bytes for retrieval 
    217         headers = {'Range': '0-599'} 
     217        headers = {'Range': 'bytes=10-609'} 
    218218        response = self.app.get(self.__class__.PDF_REL_URIPATH, 
    219219                                headers=headers,  
     
    223223        self.assert_(len(response.body) == 600) 
    224224         
    225     def test15CatchInvalidRangeSyntax(self): 
     225    def test16RetrieveFirst10Bytes(self): 
     226        # Specify a range of bytes for retrieval 
     227        headers = {'Range': 'bytes=-9'} 
     228        response = self.app.get(self.__class__.HTML_REL_URIPATH, 
     229                                headers=headers,  
     230                                status=httplib.PARTIAL_CONTENT) 
     231        self.assert_('content-range' in response.header_dict) 
     232        print('Content-range: %s' % response.header_dict['content-range']) 
     233        print("output = %r" % response.body) 
     234        self.assert_(len(response.body) == 10) 
     235         
     236    def test17RetrieveLast10Bytes(self): 
     237        # Specify a range of bytes for retrieval 
     238        headers = {'Range': 'bytes=170-'} 
     239        response = self.app.get(self.__class__.HTML_REL_URIPATH, 
     240                                headers=headers,  
     241                                status=httplib.PARTIAL_CONTENT) 
     242        self.assert_('content-range' in response.header_dict) 
     243        print('Content-range: %s' % response.header_dict['content-range']) 
     244        print("output = %r" % response.body) 
     245        self.assert_(len(response.body) == 10) 
     246         
     247    def test18CatchInvalidRangeSyntax(self): 
    226248        # Specify invalid range syntax 
    227         headers = {'Range': 'a bad range'} 
     249        headers = {'Range': 'bytes=a bad range'} 
    228250        response = self.app.get(self.__class__.PDF_REL_URIPATH, 
    229251                                headers=headers,  
    230252                                status=httplib.BAD_REQUEST) 
    231          
    232     def test15CatchInvalidRange(self): 
     253        print("output = %r" % response.body) 
     254         
     255    def test19CatchInvalidRange(self): 
    233256        # Specify a range of bytes for retrieval 
    234         headers = {'Range': '100-99999999999999999'} 
     257        headers = {'Range': '10000-0'} 
    235258        response = self.app.get(self.__class__.PDF_REL_URIPATH, 
    236259                                headers=headers,  
  • ceda_http_fileserver/trunk/ceda_http_fileserver/setup.py

    r7032 r7040  
    2525    long_description =  '''\ 
    2626A WSGI based HTTP file server application extended and enhanced from an  
    27 original package 'wsgi-fileserver' by OSAF / Mikeal Rogers 
     27original package 'wsgi-fileserver' by OSAF / Mikeal Rogers. 
     28 
     29It supports block based file read/write with configurable block size, client 
     30range requests e.g. get the first 600 bytes: 0-599 and provides hooks for 
     31easy integration with PasteDeploy.s 
    2832''', 
    2933    author =            'Philip Kershaw', 
Note: See TracChangeset for help on using the changeset viewer.