示例#1
0
def rangefilter(request, oldresponse):
    if oldresponse.stream is None:
        return oldresponse
    size = oldresponse.stream.length
    if size is None:
        # Does not deal with indeterminate length outputs
        return oldresponse

    oldresponse.headers.setHeader('accept-ranges',('bytes',))
    
    rangespec = request.headers.getHeader('range')
    
    # If we've got a range header and the If-Range header check passes, and
    # the range type is bytes, do a partial response.
    if (rangespec is not None and http.checkIfRange(request, oldresponse) and
        rangespec[0] == 'bytes'):
        # If it's a single range, return a simple response
        if len(rangespec[1]) == 1:
            try:
                start,end = canonicalizeRange(rangespec[1][0], size)
            except UnsatisfiableRangeRequest:
                return makeUnsatisfiable(request, oldresponse)

            response = http.Response(responsecode.PARTIAL_CONTENT, oldresponse.headers)
            response.headers.setHeader('content-range',('bytes',start, end, size))
            
            content, after = makeSegment(oldresponse.stream, 0, start, end)
            after.close()
            response.stream = content
            return response
        else:
            # Return a multipart/byteranges response
            lastOffset = -1
            offsetList = []
            for arange in rangespec[1]:
                try:
                    start,end = canonicalizeRange(arange, size)
                except UnsatisfiableRangeRequest:
                    continue
                if start <= lastOffset:
                    # Stupid client asking for out-of-order or overlapping ranges, PUNT!
                    return oldresponse
                offsetList.append((start,end))
                lastOffset = end

            if not offsetList:
                return makeUnsatisfiable(request, oldresponse)
            
            content_type = oldresponse.headers.getRawHeaders('content-type')
            boundary = "%x%x" % (int(time.time()*1000000), os.getpid())
            response = http.Response(responsecode.PARTIAL_CONTENT, oldresponse.headers)
            
            response.headers.setHeader('content-type',
                http_headers.MimeType('multipart', 'byteranges',
                                      [('boundary', boundary)]))
            response.stream = out = stream.CompoundStream()
            
            
            lastOffset = 0
            origStream = oldresponse.stream

            headerString = "\r\n--%s" % boundary
            if len(content_type) == 1:
                headerString+='\r\nContent-Type: %s' % content_type[0]
            headerString+="\r\nContent-Range: %s\r\n\r\n"
            
            for start,end in offsetList:
                out.addStream(headerString % 
                    http_headers.generateContentRange(('bytes', start, end, size)))

                content, origStream = makeSegment(origStream, lastOffset, start, end)
                lastOffset = end + 1
                out.addStream(content)
            origStream.close()
            out.addStream("\r\n--%s--\r\n" % boundary)
            return response
    else:
        return oldresponse
    def testIfRange(self):
        request = http.Request(None, "GET", "/", "HTTP/1.1", 0, http_headers.Headers())
        response = TestResponse()

        self.assertEquals(http.checkIfRange(request, response), True)

        request.headers.setRawHeaders("If-Range", ('"foo"',))
        self.assertEquals(http.checkIfRange(request, response), False)

        response.headers.setHeader("ETag", http_headers.ETag('foo'))
        self.assertEquals(http.checkIfRange(request, response), True)

        request.headers.setRawHeaders("If-Range", ('"bar"',))
        response.headers.setHeader("ETag", http_headers.ETag('foo'))
        self.assertEquals(http.checkIfRange(request, response), False)

        request.headers.setRawHeaders("If-Range", ('W/"foo"',))
        response.headers.setHeader("ETag", http_headers.ETag('foo', weak=True))
        self.assertEquals(http.checkIfRange(request, response), False)

        request.headers.setRawHeaders("If-Range", ('"foo"',))
        response.headers.removeHeader("ETag")
        self.assertEquals(http.checkIfRange(request, response), False)

        request.headers.setRawHeaders("If-Range", ('Sun, 02 Jan 2000 00:00:00 GMT',))
        response.headers.setHeader("Last-Modified", 946771200) # Sun, 02 Jan 2000 00:00:00 GMT
        self.assertEquals(http.checkIfRange(request, response), True)

        request.headers.setRawHeaders("If-Range", ('Sun, 02 Jan 2000 00:00:01 GMT',))
        response.headers.setHeader("Last-Modified", 946771200) # Sun, 02 Jan 2000 00:00:00 GMT
        self.assertEquals(http.checkIfRange(request, response), False)

        request.headers.setRawHeaders("If-Range", ('Sun, 01 Jan 2000 23:59:59 GMT',))
        response.headers.setHeader("Last-Modified", 946771200) # Sun, 02 Jan 2000 00:00:00 GMT
        self.assertEquals(http.checkIfRange(request, response), False)

        request.headers.setRawHeaders("If-Range", ('Sun, 01 Jan 2000 23:59:59 GMT',))
        response.headers.removeHeader("Last-Modified")
        self.assertEquals(http.checkIfRange(request, response), False)

        request.headers.setRawHeaders("If-Range", ('jwerlqjL#$Y*KJAN',))
        self.assertEquals(http.checkIfRange(request, response), False)