[Zope-Checkins] CVS: Zope/lib/python/OFS - Image.py:1.134.12.3

Martijn Pieters mj@zope.com
Wed, 21 Aug 2002 16:51:48 -0400


Update of /cvs-repository/Zope/lib/python/OFS
In directory cvs.zope.org:/tmp/cvs-serv9798/OFS

Modified Files:
      Tag: Zope-2_5-branch
	Image.py 
Log Message:
Fix for Zope Collector issue #530 (http://collector.zope.org/Zope/530);
Adobe Acrobat for windows hangs on optimized byte ranges.

- Improve file byte range serving to allow arbitrary order byte ranges.

- Drop optimizations of byte ranges altogether; rename the method to
  expandRanges. This means we'll have to swallow loosing the small bandwidth
  wins we got from merging overlapping ranges (which was allowed under the
  RFC).

- Update the tests to follow the changes.


=== Zope/lib/python/OFS/Image.py 1.134.12.2 => 1.134.12.3 ===
--- Zope/lib/python/OFS/Image.py:1.134.12.2	Tue May 28 13:39:09 2002
+++ Zope/lib/python/OFS/Image.py	Wed Aug 21 16:51:17 2002
@@ -226,8 +226,7 @@
                     RESPONSE.setStatus(416)
                     return ''
 
-                # Can we optimize?
-                ranges = HTTPRangeSupport.optimizeRanges(ranges, self.size)
+                ranges = HTTPRangeSupport.expandRanges(ranges, self.size)
                                 
                 if len(ranges) == 1:
                     # Easy case, set extra header and return partial set.
@@ -274,9 +273,6 @@
                     return ''
                     
                 else:
-                    # When we get here, ranges have been optimized, so they are
-                    # in order, non-overlapping, and start and end values are
-                    # positive integers.
                     boundary = choose_boundary()
                     
                     # Calculate the content length
@@ -303,8 +299,11 @@
                             draftprefix, boundary))
                     RESPONSE.setStatus(206) # Partial content
 
-                    pos = 0
                     data = self.data
+                    # The Pdata map allows us to jump into the Pdata chain
+                    # arbitrarily during out-of-order range searching.
+                    pdata_map = {}
+                    pdata_map[0] = data
 
                     for start, end in ranges:
                         RESPONSE.write('\r\n--%s\r\n' % boundary)
@@ -318,7 +317,14 @@
                             RESPONSE.write(data[start:end])
 
                         else:
-                            # Yippee. Linked Pdata objects.
+                            # Yippee. Linked Pdata objects. The following
+                            # calculations allow us to fast-forward through the
+                            # Pdata chain without a lot of dereferencing if we
+                            # did the work already.
+                            closest_pos = start - (start % (1<<16))
+                            pos = min(closest_pos, max(pdata_map.keys()))
+                            data = pdata_map[pos]
+
                             while data is not None:
                                 l = len(data.data)
                                 pos = pos + l
@@ -334,16 +340,18 @@
                                         
                                         # Send and loop to next range
                                         RESPONSE.write(data[lstart:lend])
-                                        # Back up the position marker, it will
-                                        # be incremented again for the next
-                                        # part.
-                                        pos = pos - l
                                         break
 
                                     # Not yet at the end, transmit what we have.
                                     RESPONSE.write(data[lstart:])
 
                                 data = data.next
+                                # Store a reference to a Pdata chain link so we
+                                # don't have to deref during this request again.
+                                pdata_map[pos] = data
+
+                    # Do not keep the link references around.
+                    del pdata_map
 
                     RESPONSE.write('\r\n--%s--\r\n' % boundary)
                     return ''