This is an automated email from the ASF dual-hosted git repository.

remm pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/tomcat.git


The following commit(s) were added to refs/heads/master by this push:
     new b9aff64  Remove internal Range helpers
b9aff64 is described below

commit b9aff64f78740235a5565004423be40cadc740ac
Author: remm <r...@apache.org>
AuthorDate: Mon Mar 23 15:54:23 2020 +0100

    Remove internal Range helpers
    
    Refactor DefaultServlet to avoid using an internal Range structure that
    is duplicated from the parsing result. Hopefully no regressions.
---
 TOMCAT-NEXT.txt                                    |   2 -
 .../apache/catalina/servlets/DefaultServlet.java   | 172 ++++++++++-----------
 .../org/apache/tomcat/util/http/parser/Ranges.java |   2 +-
 webapps/docs/changelog.xml                         |   4 +
 4 files changed, 83 insertions(+), 97 deletions(-)

diff --git a/TOMCAT-NEXT.txt b/TOMCAT-NEXT.txt
index 0b3a519..f8cd94c 100644
--- a/TOMCAT-NEXT.txt
+++ b/TOMCAT-NEXT.txt
@@ -36,8 +36,6 @@ New items for 10.0.x onwards:
  3. RFC 3986 states (section 2.2) that a %nn encoded delimiter is NOT 
equivalent
     to the decoded form. Provide an option not to decode delimiters in %nn 
form.
 
- 4. Refactor DefaultServlet to use Ranges in parseRanges().
-
 Deferred until 10.1.x:
 
  1.  Remove the ExtensionValidator and associated classes (assuming that the
diff --git a/java/org/apache/catalina/servlets/DefaultServlet.java 
b/java/org/apache/catalina/servlets/DefaultServlet.java
index 2db2251..406b120 100644
--- a/java/org/apache/catalina/servlets/DefaultServlet.java
+++ b/java/org/apache/catalina/servlets/DefaultServlet.java
@@ -41,7 +41,6 @@ import java.util.Arrays;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.Enumeration;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Locale;
 import java.util.StringTokenizer;
@@ -151,9 +150,9 @@ public class DefaultServlet extends HttpServlet {
     /**
      * Full range marker.
      */
-    protected static final ArrayList<Range> FULL = new ArrayList<>();
+    protected static final Ranges FULL = new Ranges(null, new 
ArrayList<Ranges.Entry>());
 
-    private static final Range IGNORE = new Range();
+    private static final ContentRange IGNORE = new ContentRange(null, 0, 0, 0);
 
     /**
      * MIME multipart separation string
@@ -614,7 +613,7 @@ public class DefaultServlet extends HttpServlet {
 
         WebResource resource = resources.getResource(path);
 
-        Range range = parseContentRange(req, resp);
+        ContentRange range = parseContentRange(req, resp);
 
         if (range == null) {
             // Processing error. parseContentRange() set the error code
@@ -666,7 +665,7 @@ public class DefaultServlet extends HttpServlet {
      * @return the associated file object
      * @throws IOException an IO error occurred
      */
-    protected File executePartialPut(HttpServletRequest req, Range range,
+    protected File executePartialPut(HttpServletRequest req, ContentRange 
range,
                                      String path)
         throws IOException {
 
@@ -703,10 +702,10 @@ public class DefaultServlet extends HttpServlet {
                 }
             }
 
-            randAccessContentFile.setLength(range.length);
+            randAccessContentFile.setLength(range.getLength());
 
             // Append data in request input stream to contentFile
-            randAccessContentFile.seek(range.start);
+            randAccessContentFile.seek(range.getStart());
             int numBytesRead;
             byte[] transferBuffer = new byte[BUFFER_SIZE];
             try (BufferedInputStream requestBufInStream =
@@ -928,7 +927,7 @@ public class DefaultServlet extends HttpServlet {
             }
         }
 
-        ArrayList<Range> ranges = FULL;
+        Ranges ranges = FULL;
         long contentLength = -1L;
 
         if (resource.isDirectory()) {
@@ -1148,21 +1147,22 @@ public class DefaultServlet extends HttpServlet {
 
         } else {
 
-            if ((ranges == null) || (ranges.isEmpty()))
+            if ((ranges == null) || (ranges.getEntries().isEmpty()))
                 return;
 
             // Partial content response.
 
             response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
 
-            if (ranges.size() == 1) {
+            if (ranges.getEntries().size() == 1) {
 
-                Range range = ranges.get(0);
-                response.addHeader("Content-Range", "bytes "
-                                   + range.start
-                                   + "-" + range.end + "/"
-                                   + range.length);
-                long length = range.end - range.start + 1;
+                Ranges.Entry range = ranges.getEntries().get(0);
+                long resourceLength = resource.getContentLength();
+                long start = getStart(range, resourceLength);
+                long end = getEnd(range, resourceLength);
+                response.addHeader("Content-Range",
+                        "bytes " + start + "-" + end + "/" + resourceLength);
+                long length = end - start + 1;
                 response.setContentLengthLong(length);
 
                 if (contentType != null) {
@@ -1180,7 +1180,7 @@ public class DefaultServlet extends HttpServlet {
                     }
                     if (ostream != null) {
                         if (!checkSendfile(request, response, resource,
-                                range.end - range.start + 1, range))
+                                end - start + 1, range))
                             copy(resource, ostream, range);
                     } else {
                         // we should not get here
@@ -1197,7 +1197,7 @@ public class DefaultServlet extends HttpServlet {
                         // Silent catch
                     }
                     if (ostream != null) {
-                        copy(resource, ostream, ranges.iterator(), 
contentType);
+                        copy(resource, ostream, ranges, contentType);
                     } else {
                         // we should not get here
                         throw new IllegalStateException();
@@ -1291,6 +1291,41 @@ public class DefaultServlet extends HttpServlet {
                 contentType.endsWith("xml") || 
contentType.contains("/javascript");
     }
 
+    private static boolean validate(ContentRange range) {
+        // bytes is the only range unit supported
+        return (range != null) && ("bytes".equals(range.getUnits())) && 
(range.getStart() >= 0)
+                && (range.getEnd() >= 0) && (range.getStart() <= 
range.getEnd()) && (range.getLength() > 0);
+    }
+
+    private static boolean validate(Ranges.Entry range, long length) {
+        long start = getStart(range, length);
+        long end = getEnd(range, length);
+        return (range != null) && (start >= 0) && (end >= 0) && (start <= end);
+    }
+
+    private static long getStart(Ranges.Entry range, long length) {
+        long start = range.getStart();
+        if (start == -1 ) {
+            long end = range.getEnd();
+            // If there is no start, then the start is based on the end
+            if (end >= length) {
+                return 0;
+            } else {
+                return length - end;
+            }
+        } else {
+            return start;
+        }
+    }
+
+    private static long getEnd(Ranges.Entry range, long length) {
+        long end = range.getEnd();
+        if (range.getStart() == -1 || end == -1 || end >= length) {
+            return length - 1;
+        } else {
+            return end;
+        }
+    }
 
     private boolean pathEndsWithCompressedExtension(String path) {
         for (CompressionFormat format : compressionFormats) {
@@ -1397,7 +1432,7 @@ public class DefaultServlet extends HttpServlet {
      *         process
      * @throws IOException an IO error occurred
      */
-    protected Range parseContentRange(HttpServletRequest request,
+    protected ContentRange parseContentRange(HttpServletRequest request,
                                       HttpServletResponse response)
         throws IOException {
 
@@ -1420,26 +1455,12 @@ public class DefaultServlet extends HttpServlet {
             return null;
         }
 
-
-        // bytes is the only range unit supported
-        if (!contentRange.getUnits().equals("bytes")) {
-            response.sendError(HttpServletResponse.SC_BAD_REQUEST);
-            return null;
-        }
-
-        // TODO: Remove the internal representation and use Ranges
-        // Convert to internal representation
-        Range range = new Range();
-        range.start = contentRange.getStart();
-        range.end = contentRange.getEnd();
-        range.length = contentRange.getLength();
-
-        if (!range.validate()) {
+        if (!validate(contentRange)) {
             response.sendError(HttpServletResponse.SC_BAD_REQUEST);
             return null;
         }
 
-        return range;
+        return contentRange;
     }
 
 
@@ -1453,7 +1474,7 @@ public class DefaultServlet extends HttpServlet {
      *         {@code #FULL} if the Range header should be ignored.
      * @throws IOException an IO error occurred
      */
-    protected ArrayList<Range> parseRange(HttpServletRequest request,
+    protected Ranges parseRange(HttpServletRequest request,
             HttpServletResponse response,
             WebResource resource) throws IOException {
 
@@ -1528,37 +1549,15 @@ public class DefaultServlet extends HttpServlet {
             return FULL;
         }
 
-        // TODO: Remove the internal representation and use Ranges
-        // Convert to internal representation
-        ArrayList<Range> result = new ArrayList<>();
-
-        for (Ranges.Entry entry : ranges.getEntries()) {
-            Range currentRange = new Range();
-            if (entry.getStart() == -1) {
-                currentRange.start = fileLength - entry.getEnd();
-                if (currentRange.start < 0) {
-                    currentRange.start = 0;
-                }
-                currentRange.end = fileLength - 1;
-            } else if (entry.getEnd() == -1) {
-                currentRange.start = entry.getStart();
-                currentRange.end = fileLength - 1;
-            } else {
-                currentRange.start = entry.getStart();
-                currentRange.end = entry.getEnd();
-            }
-            currentRange.length = fileLength;
-
-            if (!currentRange.validate()) {
+        for (Ranges.Entry range : ranges.getEntries()) {
+            if (!validate(range, fileLength)) {
                 response.addHeader("Content-Range", "bytes */" + fileLength);
                 
response.sendError(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);
                 return null;
             }
-
-            result.add(currentRange);
         }
 
-        return result;
+        return ranges;
     }
 
 
@@ -2123,7 +2122,7 @@ public class DefaultServlet extends HttpServlet {
     protected boolean checkSendfile(HttpServletRequest request,
                                   HttpServletResponse response,
                                   WebResource resource,
-                                  long length, Range range) {
+                                  long length, Ranges.Entry range) {
         String canonicalPath;
         if (sendfileSize > 0
             && length > sendfileSize
@@ -2138,8 +2137,8 @@ public class DefaultServlet extends HttpServlet {
                 request.setAttribute(Globals.SENDFILE_FILE_START_ATTR, 
Long.valueOf(0L));
                 request.setAttribute(Globals.SENDFILE_FILE_END_ATTR, 
Long.valueOf(length));
             } else {
-                request.setAttribute(Globals.SENDFILE_FILE_START_ATTR, 
Long.valueOf(range.start));
-                request.setAttribute(Globals.SENDFILE_FILE_END_ATTR, 
Long.valueOf(range.end + 1));
+                request.setAttribute(Globals.SENDFILE_FILE_START_ATTR, 
Long.valueOf(getStart(range, resource.getContentLength())));
+                request.setAttribute(Globals.SENDFILE_FILE_END_ATTR, 
Long.valueOf(getEnd(range, resource.getContentLength()) + 1));
             }
             return true;
         }
@@ -2387,7 +2386,7 @@ public class DefaultServlet extends HttpServlet {
      * @exception IOException if an input/output error occurs
      */
     protected void copy(WebResource resource, ServletOutputStream ostream,
-                      Range range)
+                      Ranges.Entry range)
         throws IOException {
 
         IOException exception = null;
@@ -2395,7 +2394,8 @@ public class DefaultServlet extends HttpServlet {
         InputStream resourceInputStream = resource.getInputStream();
         InputStream istream =
             new BufferedInputStream(resourceInputStream, input);
-        exception = copyRange(istream, ostream, range.start, range.end);
+        exception = copyRange(istream, ostream, getStart(range, 
resource.getContentLength()),
+                getEnd(range, resource.getContentLength()));
 
         // Clean up the input stream
         istream.close();
@@ -2420,31 +2420,33 @@ public class DefaultServlet extends HttpServlet {
      * @exception IOException if an input/output error occurs
      */
     protected void copy(WebResource resource, ServletOutputStream ostream,
-                      Iterator<Range> ranges, String contentType)
+                      Ranges ranges, String contentType)
         throws IOException {
 
         IOException exception = null;
+        long length = resource.getContentLength();
 
-        while ( (exception == null) && (ranges.hasNext()) ) {
-
+        for (Ranges.Entry range : ranges.getEntries()) {
+            if (exception != null) {
+                break;
+            }
             InputStream resourceInputStream = resource.getInputStream();
             try (InputStream istream = new 
BufferedInputStream(resourceInputStream, input)) {
 
-                Range currentRange = ranges.next();
-
                 // Writing MIME header.
                 ostream.println();
                 ostream.println("--" + mimeSeparation);
                 if (contentType != null)
                     ostream.println("Content-Type: " + contentType);
-                ostream.println("Content-Range: bytes " + currentRange.start
-                               + "-" + currentRange.end + "/"
-                               + currentRange.length);
+                long start = getStart(range, length);
+                long end = getEnd(range, length);
+                ostream.println("Content-Range: bytes " + start
+                               + "-" + end + "/"
+                               + (end - start));
                 ostream.println();
 
                 // Printing content
-                exception = copyRange(istream, ostream, currentRange.start,
-                                      currentRange.end);
+                exception = copyRange(istream, ostream, start, end);
             }
         }
 
@@ -2580,24 +2582,6 @@ public class DefaultServlet extends HttpServlet {
     }
 
 
-    protected static class Range {
-
-        public long start;
-        public long end;
-        public long length;
-
-        /**
-         * Validate range.
-         *
-         * @return true if the range is valid, otherwise false
-         */
-        public boolean validate() {
-            if (end >= length)
-                end = length - 1;
-            return (start >= 0) && (end >= 0) && (start <= end) && (length > 
0);
-        }
-    }
-
     protected static class CompressionFormat implements Serializable {
         private static final long serialVersionUID = 1L;
         public final String extension;
diff --git a/java/org/apache/tomcat/util/http/parser/Ranges.java 
b/java/org/apache/tomcat/util/http/parser/Ranges.java
index c937eb5..15bdbbf 100644
--- a/java/org/apache/tomcat/util/http/parser/Ranges.java
+++ b/java/org/apache/tomcat/util/http/parser/Ranges.java
@@ -28,7 +28,7 @@ public class Ranges {
     private final List<Entry> entries;
 
 
-    private Ranges(String units, List<Entry> entries) {
+    public Ranges(String units, List<Entry> entries) {
         this.units = units;
         this.entries = Collections.unmodifiableList(entries);
     }
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index cc6269d..1e8e357 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -66,6 +66,10 @@
         not override a possibly present <code>jarsToScan</code>. Based on code
         submitted by Iridias. (remm)
       </fix>
+      <update>
+        Refactor DefaultServlet to avoid using an internal Range structure that
+        is duplicated from the parsing result. (remm)
+      </update>
     </changelog>
   </subsection>
   <subsection name="Coyote">


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org

Reply via email to