ace-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From j...@apache.org
Subject svn commit: r1545277 - in /ace/trunk: org.apache.ace.agent.itest/src/org/apache/ace/agent/itest/ org.apache.ace.agent/src/org/apache/ace/agent/ org.apache.ace.agent/src/org/apache/ace/agent/impl/ org.apache.ace.agent/test/org/apache/ace/agent/impl/ org...
Date Mon, 25 Nov 2013 13:41:38 GMT
Author: jawi
Date: Mon Nov 25 13:41:37 2013
New Revision: 1545277

URL: http://svn.apache.org/r1545277
Log:
ACE-437 - Ensure content-length header is not sent for DPs:

- simplify the ContentRangeResponseWrapper to no longer stream to an
  intermediary file to determine the content length;
- ensure the agent is no longer depending on the content-length header
  and does not make assumptions about the length;
- removed the reporting of total bytes as we no longer can provide this
  information.


Modified:
    ace/trunk/org.apache.ace.agent.itest/src/org/apache/ace/agent/itest/CustomAgentControllerTest.java
    ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/DownloadHandle.java
    ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/ContentRangeInputStream.java
    ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/DefaultController.java
    ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/DiscoveryHandlerImpl.java
    ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/DownloadCallableImpl.java
    ace/trunk/org.apache.ace.agent/test/org/apache/ace/agent/impl/ContentRangeInputStreamTest.java
    ace/trunk/org.apache.ace.agent/test/org/apache/ace/agent/impl/DownloadHandleImplTest.java
    ace/trunk/org.apache.ace.agent/test/org/apache/ace/agent/impl/DownloadHandlerTest.java
    ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/servlet/ContentRangeResponseWrapper.java
    ace/trunk/org.apache.ace.deployment/test/org/apache/ace/deployment/servlet/DeploymentServletTest.java

Modified: ace/trunk/org.apache.ace.agent.itest/src/org/apache/ace/agent/itest/CustomAgentControllerTest.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.agent.itest/src/org/apache/ace/agent/itest/CustomAgentControllerTest.java?rev=1545277&r1=1545276&r2=1545277&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.agent.itest/src/org/apache/ace/agent/itest/CustomAgentControllerTest.java
(original)
+++ ace/trunk/org.apache.ace.agent.itest/src/org/apache/ace/agent/itest/CustomAgentControllerTest.java
Mon Nov 25 13:41:37 2013
@@ -200,8 +200,8 @@ public class CustomAgentControllerTest e
 
                     Future<DownloadResult> future = downloadHandle.start(new DownloadProgressListener()
{
                         @Override
-                        public void progress(long bytesRead, long totalBytes) {
-                            System.out.printf("Download progress: %d of %d bytes read...%n",
bytesRead, totalBytes);
+                        public void progress(long bytesRead) {
+                            System.out.printf("Download progress: %d bytes read...%n", bytesRead);
                         }
                     });
                     // Block until the download is complete...

Modified: ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/DownloadHandle.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/DownloadHandle.java?rev=1545277&r1=1545276&r2=1545277&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/DownloadHandle.java (original)
+++ ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/DownloadHandle.java Mon Nov 25
13:41:37 2013
@@ -42,10 +42,8 @@ public interface DownloadHandle {
          * 
          * @param bytesRead
          *            The number of bytes that has been received so far;
-         * @param totalBytes
-         *            The total length of the content or -1 if unknown.
          */
-        void progress(long bytesRead, long totalBytes);
+        void progress(long bytesRead);
     }
 
     /**

Modified: ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/ContentRangeInputStream.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/ContentRangeInputStream.java?rev=1545277&r1=1545276&r2=1545277&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/ContentRangeInputStream.java
(original)
+++ ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/ContentRangeInputStream.java
Mon Nov 25 13:41:37 2013
@@ -34,6 +34,15 @@ import org.apache.ace.agent.RetryAfterEx
 /**
  * Abstraction for {@link HttpURLConnection}s that might use content range headers, or partial
responses, to return the
  * contents of an URL.
+ * <p>
+ * This implementation is capable of handling partial content requests, using the HTTP 216
response code, and tries to
+ * follow the recommendations as specified in RFC 2616 as closely as possible. This implementation
deviates from the RFC
+ * by allowing the Content-Range header to be lacking both the last-byte-pos and a resource-length,
as used in
+ * {@link ContentRangeResponseWrapper}. This is an optimization that is used for ACE as we
do not want to, nor can, know
+ * the exact length of some of the streams we're sending.
+ * </p>
+ * 
+ * @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.16
  */
 class ContentRangeInputStream extends InputStream {
     private static final String HDR_CONTENT_RANGE = "Content-Range";
@@ -143,22 +152,6 @@ class ContentRangeInputStream extends In
         }
     }
 
-    /**
-     * Returns the total content size, if available.
-     * 
-     * @return the total length (in bytes) of the content, or <tt>-1</tt> if
no content size is known.
-     * @throws IOException
-     *             in case of I/O errors, such as when this stream is already closed.
-     */
-    public long getContentSize() throws IOException {
-        assertOpen();
-
-        if (m_contentInfo == null || m_contentInfo.length < 2) {
-            return -1L;
-        }
-        return m_contentInfo[1];
-    }
-
     @Override
     public int read() throws IOException {
         assertOpen();
@@ -335,7 +328,7 @@ class ContentRangeInputStream extends In
             if (contentRange != null) {
                 return parseContentRangeHeader(contentRange);
             }
-            
+
             // fall through, we cannot handle this...
         }
         else if (rc == SC_SERVICE_UNAVAILABLE) {
@@ -385,10 +378,16 @@ class ContentRangeInputStream extends In
         if (!"*".equals(parts[0])) {
             String[] rangeDef = parts[0].split("-");
 
-            long start = Long.parseLong(rangeDef[0]);
-            long end = Long.parseLong(rangeDef[1]);
+            try {
+                long start = Long.parseLong(rangeDef[0]);
+                long end = Long.parseLong(rangeDef[1]);
 
-            chunkSize = end - start;
+                chunkSize = end - start;
+            }
+            catch (Exception exception) {
+                // Ack; invalid range specified, cannot determine chunk size!
+                chunkSize = -1L;
+            }
         }
 
         long totalBytes;

Modified: ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/DefaultController.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/DefaultController.java?rev=1545277&r1=1545276&r2=1545277&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/DefaultController.java (original)
+++ ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/DefaultController.java Mon
Nov 25 13:41:37 2013
@@ -175,9 +175,9 @@ public class DefaultController extends C
         }
 
         @Override
-        public void progress(long bytesRead, long totalBytes) {
+        public void progress(long bytesRead) {
             if (m_updateInfo != null) {
-                getController().logInfo("Progress of %s update download: %d of %d bytes...",
m_updateInfo.m_type, bytesRead, totalBytes);
+                getController().logInfo("%d bytes of %s update downloaded...", bytesRead,
m_updateInfo.m_type);
             }
         }
 

Modified: ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/DiscoveryHandlerImpl.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/DiscoveryHandlerImpl.java?rev=1545277&r1=1545276&r2=1545277&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/DiscoveryHandlerImpl.java
(original)
+++ ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/DiscoveryHandlerImpl.java
Mon Nov 25 13:41:37 2013
@@ -78,7 +78,8 @@ public class DiscoveryHandlerImpl extend
         }
     }
 
-    private static final String DEFAULT_SERVER_URL = "http://localhost:8080";
+    static final String DEFAULT_SERVER_URL = "http://localhost:8080";
+
     private static final boolean DEFAULT_CHECK_SERVER_URLS = true;
     private static final long DEFAULT_CACHE_MILLISECONDS = 30000;
     private final Map<String, CheckedURL> m_checkedURLs = new HashMap<String, CheckedURL>();

Modified: ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/DownloadCallableImpl.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/DownloadCallableImpl.java?rev=1545277&r1=1545276&r2=1545277&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/DownloadCallableImpl.java
(original)
+++ ace/trunk/org.apache.ace.agent/src/org/apache/ace/agent/impl/DownloadCallableImpl.java
Mon Nov 25 13:41:37 2013
@@ -64,15 +64,12 @@ final class DownloadCallableImpl impleme
 
             byte buffer[] = new byte[READBUFFER_SIZE];
             long bytesRead = targetLength;
-            long totalBytes = -1L;
+            boolean downloadComplete = false;
             int read = 0;
 
             try {
                 while (!Thread.currentThread().isInterrupted() && (read >= 0))
{
                     read = is.read(buffer);
-                    // this can only fail when the IS is closed, but in that case, the read()
above should have failed
-                    // already...
-                    totalBytes = is.getContentSize();
 
                     if (read >= 0) {
                         os.write(buffer, 0, read);
@@ -80,11 +77,12 @@ final class DownloadCallableImpl impleme
                         bytesRead += read;
                     }
                     else {
+                        downloadComplete = true;
                         break; // EOF...
                     }
 
                     if (m_listener != null) {
-                        m_listener.progress(bytesRead, totalBytes);
+                        m_listener.progress(bytesRead);
                     }
                 }
             }
@@ -97,16 +95,15 @@ final class DownloadCallableImpl impleme
                 os.flush();
             }
 
-            boolean downloadComplete = (bytesRead == totalBytes);
             boolean stoppedEarly = Thread.currentThread().isInterrupted() || !downloadComplete;
 
             if (stoppedEarly) {
-                m_handle.logDebug("Download stopped early: %d of %d bytes downloaded... (%d)",
bytesRead, totalBytes, targetLength);
+                m_handle.logDebug("Download stopped early: %d bytes downloaded...", bytesRead);
 
                 return new DownloadResultImpl(DownloadState.STOPPED);
             }
 
-            m_handle.logDebug("Download completed: %d bytes downloaded...", totalBytes);
+            m_handle.logDebug("Download completed: %d bytes downloaded...", bytesRead);
 
             return new DownloadResultImpl(DownloadState.SUCCESSFUL, m_target);
         }

Modified: ace/trunk/org.apache.ace.agent/test/org/apache/ace/agent/impl/ContentRangeInputStreamTest.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.agent/test/org/apache/ace/agent/impl/ContentRangeInputStreamTest.java?rev=1545277&r1=1545276&r2=1545277&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.agent/test/org/apache/ace/agent/impl/ContentRangeInputStreamTest.java
(original)
+++ ace/trunk/org.apache.ace.agent/test/org/apache/ace/agent/impl/ContentRangeInputStreamTest.java
Mon Nov 25 13:41:37 2013
@@ -39,7 +39,7 @@ import org.testng.annotations.Test;
  */
 public class ContentRangeInputStreamTest {
     static enum Failure {
-        CONTENT_NOT_FOUND, SERVER_UNAVAILABLE, PARTIAL_NO_CONTENT_RANGE, PARTIAL_NON_BYTE_RANGE,
PARTIAL_COMPLETE_BODY, PARTIAL_CHANGING_CONTENT_LENGTH;
+        CONTENT_NOT_FOUND, SERVER_UNAVAILABLE, PARTIAL_NO_CONTENT_RANGE, PARTIAL_NON_BYTE_RANGE,
PARTIAL_COMPLETE_BODY, PARTIAL_CHANGING_CONTENT_LENGTH, PARTIAL_UNKNOWN_CHUNK_SIZE;
     }
 
     /**
@@ -111,6 +111,9 @@ public class ContentRangeInputStreamTest
                     int cl = (getRequestProperty("Range") != null) ? 1024 : m_length;
                     return String.format("bytes %d-%d/%d", 48, 96, cl);
                 }
+                else if (m_failure == Failure.PARTIAL_UNKNOWN_CHUNK_SIZE) {
+                    return String.format("bytes %d-/*", 48);
+                }
                 else if (m_failure != Failure.PARTIAL_NO_CONTENT_RANGE) {
                     return String.format("bytes %d-%d/%d", 48, 96, m_length);
                 }
@@ -121,14 +124,18 @@ public class ContentRangeInputStreamTest
         @Override
         public InputStream getInputStream() throws IOException {
             if (m_stream == null) {
-                m_stream = new ByteArrayInputStream(m_content.substring(48, 96).getBytes());
+                if (m_failure == Failure.PARTIAL_UNKNOWN_CHUNK_SIZE) {
+                    m_stream = new ByteArrayInputStream(m_content.substring(48).getBytes());
+                } else {
+                    m_stream = new ByteArrayInputStream(m_content.substring(48, 96).getBytes());
+                }
             }
             return m_stream;
         }
 
         @Override
         public int getResponseCode() {
-            if (m_failure == Failure.PARTIAL_NO_CONTENT_RANGE || m_failure == Failure.PARTIAL_NON_BYTE_RANGE
|| m_failure == Failure.PARTIAL_CHANGING_CONTENT_LENGTH) {
+            if (m_failure == Failure.PARTIAL_NO_CONTENT_RANGE || m_failure == Failure.PARTIAL_NON_BYTE_RANGE
|| m_failure == Failure.PARTIAL_CHANGING_CONTENT_LENGTH || m_failure == Failure.PARTIAL_UNKNOWN_CHUNK_SIZE)
{
                 return 206;
             }
             else if (m_failure == Failure.PARTIAL_COMPLETE_BODY) {
@@ -531,6 +538,19 @@ public class ContentRangeInputStreamTest
     }
 
     /**
+     * Tests that we can read partial content and return the expected contents.
+     */
+    @Test
+    public void testReadPartialContentWithUnknownChunkSizeOk() throws Exception {
+        String content = m_content;
+
+        ConnectionHandler handler = new TestConnectionHandler(new FailingContentConnection(content,
Failure.PARTIAL_UNKNOWN_CHUNK_SIZE));
+        ContentRangeInputStream is = new ContentRangeInputStream(handler, m_testURL);
+
+        assertEquals(slurpAsStringWithBuffer(is), content.substring(48));
+    }
+
+    /**
      * Tests that we cannot read partial content if the server is not available.
      */
     @Test(expectedExceptions = RetryAfterException.class)

Modified: ace/trunk/org.apache.ace.agent/test/org/apache/ace/agent/impl/DownloadHandleImplTest.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.agent/test/org/apache/ace/agent/impl/DownloadHandleImplTest.java?rev=1545277&r1=1545276&r2=1545277&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.agent/test/org/apache/ace/agent/impl/DownloadHandleImplTest.java
(original)
+++ ace/trunk/org.apache.ace.agent/test/org/apache/ace/agent/impl/DownloadHandleImplTest.java
Mon Nov 25 13:41:37 2013
@@ -147,7 +147,7 @@ public class DownloadHandleImplTest exte
         final DownloadHandle handle = downloadHandler.getHandle(m_testContentURL);
         future = handle.start(new DownloadProgressListener() {
             @Override
-            public void progress(long bytesRead, long totalBytes) {
+            public void progress(long bytesRead) {
                 handle.stop();
             }
         });
@@ -187,8 +187,8 @@ public class DownloadHandleImplTest exte
         // Start the download, but interrupt it after reading the first chunk of data...
         future = handle.start(new DownloadProgressListener() {
             @Override
-            public void progress(long bytesRead, long totalBytes) {
-                System.out.printf("Downloaded %d from %d bytes, interrupting download...%n",
bytesRead, totalBytes);
+            public void progress(long bytesRead) {
+                System.out.printf("Downloaded %d bytes, interrupting download...%n", bytesRead);
                 Thread.currentThread().interrupt();
             }
         });
@@ -208,9 +208,9 @@ public class DownloadHandleImplTest exte
             private int m_count = 5;
 
             @Override
-            public void progress(long bytesRead, long totalBytes) {
+            public void progress(long bytesRead) {
                 if (--m_count == 0) {
-                    System.out.printf("Downloaded %d from %d bytes, stopping download...%n",
bytesRead, totalBytes);
+                    System.out.printf("Downloaded %d bytes, stopping download...%n", bytesRead);
                     handle2.stop();
                 }
             }

Modified: ace/trunk/org.apache.ace.agent/test/org/apache/ace/agent/impl/DownloadHandlerTest.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.agent/test/org/apache/ace/agent/impl/DownloadHandlerTest.java?rev=1545277&r1=1545276&r2=1545277&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.agent/test/org/apache/ace/agent/impl/DownloadHandlerTest.java
(original)
+++ ace/trunk/org.apache.ace.agent/test/org/apache/ace/agent/impl/DownloadHandlerTest.java
Mon Nov 25 13:41:37 2013
@@ -180,7 +180,7 @@ public class DownloadHandlerTest extends
 
         Future<DownloadResult> future = handle.start(new DownloadProgressListener()
{
             @Override
-            public void progress(long read, long total) {
+            public void progress(long read) {
                 Thread.currentThread().interrupt();
             }
         });

Modified: ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/servlet/ContentRangeResponseWrapper.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/servlet/ContentRangeResponseWrapper.java?rev=1545277&r1=1545276&r2=1545277&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/servlet/ContentRangeResponseWrapper.java
(original)
+++ ace/trunk/org.apache.ace.deployment/src/org/apache/ace/deployment/servlet/ContentRangeResponseWrapper.java
Mon Nov 25 13:41:37 2013
@@ -18,12 +18,7 @@
  */
 package org.apache.ace.deployment.servlet;
 
-import java.io.Closeable;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
 import java.io.IOException;
-import java.io.InputStream;
 import java.util.concurrent.atomic.AtomicLong;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -35,114 +30,20 @@ import javax.servlet.http.HttpServletRes
 
 /**
  * Wraps a HttpServletResponse to add byte range support allowing client to request partial
content.
+ * <p>
+ * Note: this implementation does <em>not</em> strictly follow the recommendations
made in RFC 2616! For example, it
+ * does not ever send the "Content-Length" header, nor provide a "Resource-Length" value
at any time. This is an
+ * "optimization" we've added for ACE, as we do not know the content/resource length in advance,
nor are willing to
+ * sacrifice performance to get knowledge about this.
+ * </p>
  * 
  * @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35.1
  */
 public class ContentRangeResponseWrapper extends HttpServletResponseWrapper {
-
-    /**
-     * Internal helper that Wraps a ServletOutputStream to add byte range support.
-     */
-    private static class ContentRangeOutputStreamWrapper extends ServletOutputStream {
-        private static final int BUFFER_SIZE = 32 * 1024; // kB
-
-        private final HttpServletResponse m_response;
-        private final boolean m_streamAll;
-        private final long m_requestFirstBytePos;
-        private final long m_requestLastBytePos;
-        private final FileOutputStream m_os;
-        private final File m_file;
-
-        private final AtomicLong m_instanceLen = new AtomicLong(0);
-
-        public ContentRangeOutputStreamWrapper(HttpServletResponse response) throws IOException
{
-            this(response, 0, Long.MAX_VALUE);
-        }
-
-        public ContentRangeOutputStreamWrapper(HttpServletResponse response, long firstBytePos,
long lastBytePos) throws IOException {
-            this(response, firstBytePos, lastBytePos, (firstBytePos == 0 && lastBytePos
== Long.MAX_VALUE));
-        }
-
-        private ContentRangeOutputStreamWrapper(HttpServletResponse response, long firstBytePos,
long lastBytePos, boolean streamAll) throws IOException {
-            assert response != null;
-            assert firstBytePos >= 0;
-            assert lastBytePos > firstBytePos;
-
-            m_response = response;
-            m_requestFirstBytePos = firstBytePos;
-            m_requestLastBytePos = lastBytePos;
-            m_streamAll = streamAll;
-
-            // We use a file to buffer because Deployment Packages can be big and the current
common ACE Agent case it a
-            // range request for some start position up-to EOF.
-            m_file = File.createTempFile("deploymentpackage", ".jar");
-            m_os = new FileOutputStream(m_file);
-        }
-
-        @Override
-        public void write(int b) throws IOException {
-            // We only need to buffer the relevant bytes since we keep track of the instance
length in the counter.
-            long value = m_instanceLen.getAndIncrement();
-            if (value >= m_requestFirstBytePos && value <= m_requestLastBytePos)
{
-                m_os.write(b);
-            }
-        }
-
-        @Override
-        public void close() throws IOException {
-            closeQuietly(m_os);
-
-            long instanceLength = m_instanceLen.get();
-            long instanceLastBytePos = instanceLength - 1L;
-            InputStream is = null;
-            ServletOutputStream os = null;
-
-            try {
-                if (instanceLastBytePos < m_requestFirstBytePos) {
-                    m_response.setStatus(SC_REQUESTED_RANGE_NOT_SATISFIABLE);
-                    m_response.setHeader("Content-Range", String.format("bytes */%d", instanceLength));
-                }
-                else {
-                    long firstBytePos = m_requestFirstBytePos;
-                    long lastBytePos = instanceLastBytePos < m_requestLastBytePos ? instanceLastBytePos
: m_requestLastBytePos;
-                    long contentLength = lastBytePos - firstBytePos + 1;
-
-                    m_response.setStatus(m_streamAll ? SC_OK : SC_PARTIAL_CONTENT);
-                    m_response.setHeader("Content-Length", String.valueOf(contentLength));
-                    if (!m_streamAll) {
-                        m_response.setHeader("Content-Range", String.format("bytes %d-%d/%d",
firstBytePos, lastBytePos, instanceLength));
-                    }
-
-                    byte[] buffer = new byte[BUFFER_SIZE];
-                    is = new FileInputStream(m_file);
-                    os = m_response.getOutputStream();
-
-                    for (int bytesRead = is.read(buffer); bytesRead != -1; bytesRead = is.read(buffer))
{
-                        os.write(buffer, 0, bytesRead);
-                    }
-                }
-            }
-            finally {
-                closeQuietly(is);
-                closeQuietly(os);
-                m_file.delete();
-            }
-        }
-
-        private static void closeQuietly(Closeable resource) throws IOException {
-            if (resource != null) {
-                try {
-                    resource.close();
-                }
-                catch (Exception e) {
-                    // ignore
-                }
-            }
-        }
-    }
+    private final long m_requestFirstBytePos;
+    private final long m_requestLastBytePos;
 
     private final HttpServletResponse m_response;
-    private final ServletOutputStream m_outputStream;
 
     public ContentRangeResponseWrapper(HttpServletRequest request, HttpServletResponse response)
throws IOException {
         super(response);
@@ -151,25 +52,62 @@ public class ContentRangeResponseWrapper
         assert response != null;
 
         m_response = response;
-        m_response.setHeader("Accept-Ranges", "bytes");
 
-        // If a valid Range request is present we install the ContentRangeOutputStreamWrapper.
Otherwise we do not touch
-        // the response ServletOutputStream until we have to in #getOutputStream().
-        ContentRangeOutputStreamWrapper wrapper = null;
         long[] requestRange = getRequestRange(request);
         if (requestRange != null) {
-            wrapper = new ContentRangeOutputStreamWrapper(response, requestRange[0], requestRange[1]);
+            m_requestFirstBytePos = requestRange[0];
+            m_requestLastBytePos = requestRange[1];
+        }
+        else {
+            m_requestFirstBytePos = 0;
+            m_requestLastBytePos = Long.MAX_VALUE;
+        }
+
+        boolean streamAll = (m_requestFirstBytePos == 0) && (m_requestLastBytePos
== Long.MAX_VALUE);
+
+        m_response.setHeader("Accept-Ranges", "bytes");
+        if (m_requestFirstBytePos < m_requestLastBytePos) {
+            if (streamAll) {
+                m_response.setStatus(SC_OK);
+            }
+            else {
+                m_response.setStatus(SC_PARTIAL_CONTENT);
+
+                StringBuilder cr = new StringBuilder("bytes ").append(m_requestFirstBytePos).append('-');
+                if (m_requestLastBytePos > 0 && m_requestLastBytePos < Long.MAX_VALUE)
{
+                    cr.append(m_requestLastBytePos);
+                }
+                cr.append("/*"); // unknown instance length...
+                m_response.setHeader("Content-Range", cr.toString());
+            }
         }
-        if (wrapper == null) {
-            // Assume a range of "bytes=0-", which simply streams everything. This solves
ACE-435...
-            wrapper = new ContentRangeOutputStreamWrapper(response);
+        else {
+            m_response.setStatus(SC_REQUESTED_RANGE_NOT_SATISFIABLE);
         }
-        m_outputStream = wrapper;
     }
 
     @Override
     public ServletOutputStream getOutputStream() throws IOException {
-        return m_outputStream;
+        final ServletOutputStream delegate = m_response.getOutputStream();
+
+        return new ServletOutputStream() {
+            /** keeps the actual number of bytes written by our caller... */
+            private final AtomicLong m_written = new AtomicLong(0L);
+
+            @Override
+            public void write(int b) throws IOException {
+                // We only need to buffer the relevant bytes since we keep track of the instance
length in the counter.
+                long written = m_written.getAndIncrement();
+                if (written >= m_requestFirstBytePos && written <= m_requestLastBytePos)
{
+                    delegate.write(b);
+                }
+            }
+
+            @Override
+            public void close() throws IOException {
+                delegate.close();
+            }
+        };
     }
 
     /**

Modified: ace/trunk/org.apache.ace.deployment/test/org/apache/ace/deployment/servlet/DeploymentServletTest.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.deployment/test/org/apache/ace/deployment/servlet/DeploymentServletTest.java?rev=1545277&r1=1545276&r2=1545277&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.deployment/test/org/apache/ace/deployment/servlet/DeploymentServletTest.java
(original)
+++ ace/trunk/org.apache.ace.deployment/test/org/apache/ace/deployment/servlet/DeploymentServletTest.java
Mon Nov 25 13:41:37 2013
@@ -96,7 +96,7 @@ public class DeploymentServletTest {
         m_requestPathInfo = "/existing/versions/2.0.0";
         m_servlet.doGet(m_request, m_response);
         assertResponseCode(HttpServletResponse.SC_OK);
-        assertResponseHeaderValue("Content-Length", "100");
+        assertResponseHeaderNotPresent("Content-Length");
         assertResponseOutputSize(100);
         assertGeneratorTargetId("existing");
         assertGeneratorToVersion("2.0.0");
@@ -129,7 +129,7 @@ public class DeploymentServletTest {
         m_requestRangeHeader = "bytes=a-1";
         m_servlet.doGet(m_request, m_response);
         assertResponseCode(HttpServletResponse.SC_OK);
-        assertResponseHeaderValue("Content-Length", "100");
+        assertResponseHeaderNotPresent("Content-Length");
         assertResponseOutputSize(100);
     }
 
@@ -140,8 +140,8 @@ public class DeploymentServletTest {
         m_requestRangeHeader = "bytes=0-10";
         m_servlet.doGet(m_request, m_response);
         assertResponseCode(HttpServletResponse.SC_PARTIAL_CONTENT);
-        assertResponseHeaderValue("Content-Length", "11");
-        assertResponseHeaderValue("Content-Range", "bytes 0-10/100");
+        assertResponseHeaderNotPresent("Content-Length");
+        assertResponseHeaderValue("Content-Range", "bytes 0-10/*");
     }
 
     @Test
@@ -154,8 +154,8 @@ public class DeploymentServletTest {
         m_requestRangeHeader = "bytes=2-";
         m_servlet.doGet(m_request, m_response);
         assertResponseCode(HttpServletResponse.SC_PARTIAL_CONTENT);
-        assertResponseHeaderValue("Content-Length", "98");
-        assertResponseHeaderValue("Content-Range", "bytes 2-99/100");
+        assertResponseHeaderNotPresent("Content-Length");
+        assertResponseHeaderValue("Content-Range", "bytes 2-/*");
         assertResponseOutputSize(98);
     }
 
@@ -166,8 +166,8 @@ public class DeploymentServletTest {
         m_requestRangeHeader = "bytes=2-50";
         m_servlet.doGet(m_request, m_response);
         assertResponseCode(HttpServletResponse.SC_PARTIAL_CONTENT);
-        assertResponseHeaderValue("Content-Length", "49");
-        assertResponseHeaderValue("Content-Range", "bytes 2-50/100");
+        assertResponseHeaderNotPresent("Content-Length");
+        assertResponseHeaderValue("Content-Range", "bytes 2-50/*");
     }
 
     @Test
@@ -180,8 +180,8 @@ public class DeploymentServletTest {
         m_requestRangeHeader = "bytes=2-100";
         m_servlet.doGet(m_request, m_response);
         assertResponseCode(HttpServletResponse.SC_PARTIAL_CONTENT);
-        assertResponseHeaderValue("Content-Length", "98");
-        assertResponseHeaderValue("Content-Range", "bytes 2-99/100");
+        assertResponseHeaderNotPresent("Content-Length");
+        assertResponseHeaderValue("Content-Range", "bytes 2-100/*");
         assertResponseOutputSize(98);
     }
 
@@ -199,7 +199,7 @@ public class DeploymentServletTest {
         m_requestRangeHeader = "bytes=2-1";
         m_servlet.doGet(m_request, m_response);
         assertResponseCode(HttpServletResponse.SC_OK);
-        assertResponseHeaderValue("Content-Length", "100");
+        assertResponseHeaderNotPresent("Content-Length");
         assertResponseOutputSize(100);
     }
 
@@ -209,8 +209,8 @@ public class DeploymentServletTest {
         m_requestPathInfo = "/existing/versions/2.0.0";
         m_requestRangeHeader = "bytes=100-110";
         m_servlet.doGet(m_request, m_response);
-        assertResponseCode(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);
-        assertResponseHeaderValue("Content-Range", "bytes */100");
+        assertResponseCode(HttpServletResponse.SC_PARTIAL_CONTENT);
+        assertResponseHeaderValue("Content-Range", "bytes 100-110/*");
         assertResponseHeaderNotPresent("Content-Length");
         assertResponseOutputSize(0);
     }



Mime
View raw message