diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/InclusiveByteRange.java b/jetty-server/src/main/java/org/eclipse/jetty/server/InclusiveByteRange.java index 784f87643a2..d283579093e 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/InclusiveByteRange.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/InclusiveByteRange.java @@ -18,11 +18,12 @@ package org.eclipse.jetty.server; +import java.util.ArrayList; import java.util.Enumeration; +import java.util.Iterator; import java.util.List; import java.util.StringTokenizer; -import org.eclipse.jetty.util.LazyList; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -54,8 +55,8 @@ public class InclusiveByteRange { private static final Logger LOG = Log.getLogger(InclusiveByteRange.class); - long first = 0; - long last = 0; + private long first; + private long last; public InclusiveByteRange(long first, long last) { @@ -74,19 +75,87 @@ public class InclusiveByteRange } + /* ------------------------------------------------------------ */ + private void coalesce(InclusiveByteRange r) + { + first = Math.min(first,r.first); + last = Math.max(last,r.last); + } + + /* ------------------------------------------------------------ */ + private boolean overlaps(InclusiveByteRange range) + { + return (range.first>=this.first && range.first<=this.last) + || + (range.last>=this.first && range.last<=this.last) + || + (range.firstthis.last); + } + + /* ------------------------------------------------------------ */ + public long getSize() + { + return last-first+1; + } + + /* ------------------------------------------------------------ */ + public String toHeaderRangeString(long size) + { + StringBuilder sb = new StringBuilder(40); + sb.append("bytes "); + sb.append(first); + sb.append('-'); + sb.append(last); + sb.append("/"); + sb.append(size); + return sb.toString(); + } + + /* ------------------------------------------------------------ */ + @Override + public int hashCode() + { + return (int)(first ^ last); + } + + /* ------------------------------------------------------------ */ + @Override + public boolean equals( Object obj ) + { + if(obj == null) + return false; + + if(!(obj instanceof InclusiveByteRange)) + return false; + + return ((InclusiveByteRange)obj).first == this.first && + ((InclusiveByteRange)obj).last == this.last; + } + + /* ------------------------------------------------------------ */ + @Override + public String toString() + { + StringBuilder sb = new StringBuilder(60); + sb.append(Long.toString(first)); + sb.append(":"); + sb.append(Long.toString(last)); + return sb.toString(); + } + /* ------------------------------------------------------------ */ /** * @param headers Enumeration of Range header fields. * @param size Size of the resource. - * @return LazyList of satisfiable ranges + * @return List of satisfiable ranges */ public static List satisfiableRanges(Enumeration headers, long size) { - Object satRanges=null; + List ranges = null; + final long end = size-1; // walk through all Range headers - headers: while (headers.hasMoreElements()) { String header = headers.nextElement(); @@ -100,52 +169,89 @@ public class InclusiveByteRange try { t = tok.nextToken().trim(); + if ("bytes".equals(t)) + continue; long first = -1; long last = -1; - int d = t.indexOf('-'); - if (d < 0 || t.indexOf("-",d + 1) >= 0) + int dash = t.indexOf('-'); + if (dash < 0 || t.indexOf("-",dash + 1) >= 0) { - if ("bytes".equals(t)) - continue; LOG.warn("Bad range format: {}",t); - continue headers; + break; } - else if (d == 0) + + if (dash>0) + first = Long.parseLong(t.substring(0,dash).trim()); + if (dash<(t.length()-1)) + last = Long.parseLong(t.substring(dash + 1).trim()); + + if (first==-1) { - if (d + 1 < t.length()) - last = Long.parseLong(t.substring(d + 1).trim()); - else + if (last==-1) { LOG.warn("Bad range format: {}",t); + break; + } + + if (last==0) continue; + + // This is a suffix range + first = Math.max(0,size-last); + last = end; + } + else + { + // Range starts after end + if (first>=size) + continue; + + if (last==-1) + last = end; + else if (last>=end) + last = end; + } + + if (last(); + + boolean coalesced = false; + for (Iterator i = ranges.listIterator(); i.hasNext();) + { + InclusiveByteRange r = i.next(); + if (range.overlaps(r)) + { + coalesced = true; + r.coalesce(range); + while(i.hasNext()) + { + InclusiveByteRange r2 = i.next(); + + if (r2.overlaps(r)) + { + r.coalesce(r2); + i.remove(); + } + } } } - else if (d + 1 < t.length()) - { - first = Long.parseLong(t.substring(0,d).trim()); - last = Long.parseLong(t.substring(d + 1).trim()); - } - else - first = Long.parseLong(t.substring(0,d).trim()); + + if (!coalesced) + ranges.add(range); - if (first == -1 && last == -1) - continue headers; - - if (first != -1 && last != -1 && (first > last)) - continue headers; - - if (first < size) - { - InclusiveByteRange range = new InclusiveByteRange(first,last); - satRanges = LazyList.add(satRanges,range); - } } catch (NumberFormatException e) { LOG.warn("Bad range format: {}",t); LOG.ignore(e); - continue; } } } @@ -155,51 +261,8 @@ public class InclusiveByteRange LOG.ignore(e); } } - return LazyList.getList(satRanges,true); - } - - /* ------------------------------------------------------------ */ - public long getFirst(long size) - { - if (first<0) - { - long tf=size-last; - if (tf<0) - tf=0; - return tf; - } - return first; - } - - /* ------------------------------------------------------------ */ - public long getLast(long size) - { - if (first<0) - return size-1; - if (last<0 ||last>=size) - return size-1; - return last; - } - - /* ------------------------------------------------------------ */ - public long getSize(long size) - { - return getLast(size)-getFirst(size)+1; - } - - - /* ------------------------------------------------------------ */ - public String toHeaderRangeString(long size) - { - StringBuilder sb = new StringBuilder(40); - sb.append("bytes "); - sb.append(getFirst(size)); - sb.append('-'); - sb.append(getLast(size)); - sb.append("/"); - sb.append(size); - return sb.toString(); + return ranges; } /* ------------------------------------------------------------ */ @@ -212,18 +275,6 @@ public class InclusiveByteRange } - /* ------------------------------------------------------------ */ - @Override - public String toString() - { - StringBuilder sb = new StringBuilder(60); - sb.append(Long.toString(first)); - sb.append(":"); - sb.append(Long.toString(last)); - return sb.toString(); - } - - } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/ResourceService.java b/jetty-server/src/main/java/org/eclipse/jetty/server/ResourceService.java index f95402276ea..73c6b1be12e 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/ResourceService.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/ResourceService.java @@ -735,7 +735,7 @@ public class ResourceService else { // Parse the satisfiable ranges - List ranges =InclusiveByteRange.satisfiableRanges(reqRanges,content_length); + List ranges =InclusiveByteRange.satisfiableRanges( reqRanges, content_length); // if there are no satisfiable ranges, send 416 response if (ranges==null || ranges.size()==0) @@ -752,15 +752,15 @@ public class ResourceService // since were here now), send that range with a 216 response if ( ranges.size()== 1) { - InclusiveByteRange singleSatisfiableRange = ranges.get(0); - long singleLength = singleSatisfiableRange.getSize(content_length); + InclusiveByteRange singleSatisfiableRange = ranges.iterator().next(); + long singleLength = singleSatisfiableRange.getSize(); putHeaders(response,content,singleLength); response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT); if (!response.containsHeader(HttpHeader.DATE.asString())) response.addDateHeader(HttpHeader.DATE.asString(),System.currentTimeMillis()); response.setHeader(HttpHeader.CONTENT_RANGE.asString(), singleSatisfiableRange.toHeaderRangeString(content_length)); - content.getResource().writeTo(out,singleSatisfiableRange.getFirst(content_length),singleLength); + content.getResource().writeTo(out,singleSatisfiableRange.getFirst(),singleLength); return true; } @@ -793,9 +793,9 @@ public class ResourceService // calculate the content-length int length=0; String[] header = new String[ranges.size()]; - for (int i=0;i0)?2:0)+ @@ -803,18 +803,19 @@ public class ResourceService (mimetype==null?0:HttpHeader.CONTENT_TYPE.asString().length()+2+mimetype.length())+2+ HttpHeader.CONTENT_RANGE.asString().length()+2+header[i].length()+2+ 2+ - (ibr.getLast(content_length)-ibr.getFirst(content_length))+1; + (ibr.getLast()-ibr.getFirst())+1; + i++; } length+=2+2+multi.getBoundary().length()+2+2; response.setContentLength(length); - for (int i=0;i strings = new Vector<>(); strings.add(rangeString); - List ranges = InclusiveByteRange.satisfiableRanges(strings.elements(),200); + List ranges = InclusiveByteRange.satisfiableRanges( strings.elements(), 200); assertNull("Invalid Range [" + rangeString + "] should result in no satisfiable ranges",ranges); } private void assertRange(String msg, int expectedFirst, int expectedLast, int size, InclusiveByteRange actualRange) { - assertEquals(msg + " - first",expectedFirst,actualRange.getFirst(size)); - assertEquals(msg + " - last",expectedLast,actualRange.getLast(size)); + assertEquals(msg + " - first",expectedFirst,actualRange.getFirst()); + assertEquals(msg + " - last",expectedLast,actualRange.getLast()); String expectedHeader = String.format("bytes %d-%d/%d",expectedFirst,expectedLast,size); assertEquals(msg + " - header range string",expectedHeader,actualRange.toHeaderRangeString(size)); } @@ -54,32 +55,30 @@ public class InclusiveByteRangeTest { InclusiveByteRange range = parseRange(rangeId,size); - assertEquals("Range [" + rangeId + "] - first",expectedFirst,range.getFirst(size)); - assertEquals("Range [" + rangeId + "] - last",expectedLast,range.getLast(size)); + assertEquals("Range [" + rangeId + "] - first",expectedFirst,range.getFirst()); + assertEquals("Range [" + rangeId + "] - last",expectedLast,range.getLast()); String expectedHeader = String.format("bytes %d-%d/%d",expectedFirst,expectedLast,size); assertEquals("Range [" + rangeId + "] - header range string",expectedHeader,range.toHeaderRangeString(size)); } - @SuppressWarnings("unchecked") private InclusiveByteRange parseRange(String rangeString, int size) { - Vector strings = new Vector(); + Vector strings = new Vector<>(); strings.add(rangeString); - List ranges = InclusiveByteRange.satisfiableRanges(strings.elements(),size); + List ranges = InclusiveByteRange.satisfiableRanges(strings.elements(),size); assertNotNull("Satisfiable Ranges should not be null",ranges); assertEquals("Satisfiable Ranges of [" + rangeString + "] count",1,ranges.size()); - return (InclusiveByteRange)ranges.get(0); + return (InclusiveByteRange)ranges.iterator().next(); } - @SuppressWarnings("unchecked") - private List parseRanges(String rangeString, int size) + private List parseRanges(int size, String... rangeString) { - Vector strings = new Vector(); - strings.add(rangeString); + Vector strings = new Vector<>(); + for (String range : rangeString) + strings.add(range); - List ranges; - ranges = InclusiveByteRange.satisfiableRanges(strings.elements(),size); + List ranges = InclusiveByteRange.satisfiableRanges(strings.elements(),size); assertNotNull("Satisfiable Ranges should not be null",ranges); return ranges; } @@ -112,10 +111,26 @@ public class InclusiveByteRangeTest rangeString = "bytes=5-20,35-65"; - List ranges = parseRanges(rangeString,size); + List ranges = parseRanges(size,rangeString); assertEquals("Satisfiable Ranges of [" + rangeString + "] count",2,ranges.size()); - assertRange("Range [" + rangeString + "]",5,20,size,ranges.get(0)); - assertRange("Range [" + rangeString + "]",35,49,size,ranges.get(1)); + Iterator inclusiveByteRangeIterator = ranges.iterator(); + assertRange("Range [" + rangeString + "]",5,20,size,inclusiveByteRangeIterator.next()); + assertRange("Range [" + rangeString + "]",35,49,size,inclusiveByteRangeIterator.next()); + } + + /** + * Ranges have a multiple ranges, all absolutely defined. + */ + @Test + public void testMultipleAbsoluteRangesSplit() + { + int size = 50; + + List ranges = parseRanges(size,"bytes=5-20","bytes=35-65"); + assertEquals(2,ranges.size()); + Iterator inclusiveByteRangeIterator = ranges.iterator(); + assertRange("testMultipleAbsoluteRangesSplit[0]",5,20,size,inclusiveByteRangeIterator.next()); + assertRange("testMultipleAbsoluteRangesSplit[1]",35,49,size,inclusiveByteRangeIterator.next()); } /** @@ -124,42 +139,122 @@ public class InclusiveByteRangeTest @Test public void testMultipleRangesClipped() { + int size = 50; String rangeString; rangeString = "bytes=5-20,35-65,-5"; - List ranges = parseRanges(rangeString,50); - assertEquals("Satisfiable Ranges of [" + rangeString + "] count",3,ranges.size()); - assertRange("Range [" + rangeString + "]",5,20,50,ranges.get(0)); - assertRange("Range [" + rangeString + "]",35,49,50,ranges.get(1)); - assertRange("Range [" + rangeString + "]",45,49,50,ranges.get(2)); + List ranges = parseRanges(size,rangeString); + assertEquals("Satisfiable Ranges of [" + rangeString + "] count",2,ranges.size()); + Iterator inclusiveByteRangeIterator = ranges.iterator(); + assertRange("Range [" + rangeString + "]",5,20,size,inclusiveByteRangeIterator.next()); + assertRange("Range [" + rangeString + "]",35,49,size,inclusiveByteRangeIterator.next()); } @Test public void testMultipleRangesOverlapping() { + int size = 200; String rangeString; rangeString = "bytes=5-20,15-25"; - List ranges = parseRanges(rangeString,200); - assertEquals("Satisfiable Ranges of [" + rangeString + "] count",2,ranges.size()); - assertRange("Range [" + rangeString + "]",5,20,200,ranges.get(0)); - assertRange("Range [" + rangeString + "]",15,25,200,ranges.get(1)); + List ranges = parseRanges(size,rangeString); + assertEquals("Satisfiable Ranges of [" + rangeString + "] count",1,ranges.size()); + Iterator inclusiveByteRangeIterator = ranges.iterator(); + assertRange("Range [" + rangeString + "]",5,25,size,inclusiveByteRangeIterator.next()); } @Test public void testMultipleRangesSplit() { + int size = 200; String rangeString; rangeString = "bytes=5-10,15-20"; - List ranges = parseRanges(rangeString,200); + List ranges = parseRanges(size,rangeString); assertEquals("Satisfiable Ranges of [" + rangeString + "] count",2,ranges.size()); - assertRange("Range [" + rangeString + "]",5,10,200,ranges.get(0)); - assertRange("Range [" + rangeString + "]",15,20,200,ranges.get(1)); + Iterator inclusiveByteRangeIterator = ranges.iterator(); + assertRange("Range [" + rangeString + "]",5,10,size,inclusiveByteRangeIterator.next()); + assertRange("Range [" + rangeString + "]",15,20,size,inclusiveByteRangeIterator.next()); } + @Test + public void testMultipleSameRangesSplit() + { + int size = 200; + String rangeString; + rangeString = "bytes=5-10,15-20,5-10,15-20,5-10,5-10,5-10,5-10,5-10,5-10"; + + List ranges = parseRanges(size,rangeString); + assertEquals("Satisfiable Ranges of [" + rangeString + "] count",2,ranges.size()); + Iterator inclusiveByteRangeIterator = ranges.iterator(); + assertRange("Range [" + rangeString + "]",5,10,size,inclusiveByteRangeIterator.next()); + assertRange("Range [" + rangeString + "]",15,20,size,inclusiveByteRangeIterator.next()); + } + + @Test + public void testMultipleOverlappingRanges() + { + int size = 200; + String rangeString; + rangeString = "bytes=5-15,20-30,10-25"; + + List ranges = parseRanges(size,rangeString); + assertEquals("Satisfiable Ranges of [" + rangeString + "] count",1,ranges.size()); + Iterator inclusiveByteRangeIterator = ranges.iterator(); + assertRange("Range [" + rangeString + "]",5,30,size,inclusiveByteRangeIterator.next()); + } + + @Test + public void testMultipleOverlappingRangesOrdered() + { + int size = 200; + String rangeString; + rangeString = "bytes=20-30,5-15,0-5,25-35"; + + List ranges = parseRanges(size,rangeString); + assertEquals("Satisfiable Ranges of [" + rangeString + "] count",2,ranges.size()); + Iterator inclusiveByteRangeIterator = ranges.iterator(); + assertRange("Range [" + rangeString + "]",20,35,size,inclusiveByteRangeIterator.next()); + assertRange("Range [" + rangeString + "]",0,15,size,inclusiveByteRangeIterator.next()); + } + + @Test + public void testMultipleOverlappingRangesOrderedSplit() + { + int size = 200; + String rangeString; + rangeString = "bytes=20-30,5-15,0-5,25-35"; + List ranges = parseRanges(size,"bytes=20-30","bytes=5-15","bytes=0-5,25-35"); + + assertEquals("Satisfiable Ranges of [" + rangeString + "] count",2,ranges.size()); + Iterator inclusiveByteRangeIterator = ranges.iterator(); + assertRange("Range [" + rangeString + "]",20,35,size,inclusiveByteRangeIterator.next()); + assertRange("Range [" + rangeString + "]",0,15,size,inclusiveByteRangeIterator.next()); + } + + @Test + public void testNasty() + { + int size = 200; + String rangeString; + + rangeString = "bytes=90-100, 10-20, 30-40, -161"; + List ranges = parseRanges(size,rangeString); + + assertEquals("Satisfiable Ranges of [" + rangeString + "] count",2,ranges.size()); + Iterator inclusiveByteRangeIterator = ranges.iterator(); + assertRange("Range [" + rangeString + "]",30,199,size,inclusiveByteRangeIterator.next()); + assertRange("Range [" + rangeString + "]",10,20,size,inclusiveByteRangeIterator.next()); + } + + @Test + public void testRange_OpenEnded() + { + assertSimpleRange(50, 499, "bytes=50-", 500); + } + @Test public void testSimpleRange() { @@ -167,5 +262,93 @@ public class InclusiveByteRangeTest assertSimpleRange(195,199,"bytes=-5",200); assertSimpleRange(50,119,"bytes=50-150",120); assertSimpleRange(50,119,"bytes=50-",120); + + assertSimpleRange(1,50,"bytes= 1 - 50",120); + } + + // TODO: evaluate this vs assertInvalidRange() above, which behavior is correct? null? or empty list? + private void assertBadRangeList(int size, String badRange) + { + Vector strings = new Vector<>(); + strings.add(badRange); + + List ranges = InclusiveByteRange.satisfiableRanges(strings.elements(),size); + // if one part is bad, the entire set of ranges should be treated as bad, per RFC7233 + assertThat("Should have no ranges", ranges, is(nullValue())); + } + + @Test + @Ignore + public void testBadRange_SetPartiallyBad() + { + assertBadRangeList(500, "bytes=1-50,1-b,a-50"); + } + + @Test + public void testBadRange_NoNumbers() + { + assertBadRangeList(500, "bytes=a-b"); + } + + @Test + public void testBadRange_Empty() + { + assertBadRangeList(500, "bytes="); + } + + @Test + @Ignore + public void testBadRange_ZeroPrefixed() + { + assertBadRangeList(500, "bytes=01-050"); + } + + @Test + public void testBadRange_Hex() + { + assertBadRangeList(500, "bytes=0F-FF"); + } + + @Test + @Ignore + public void testBadRange_TabWhitespace() + { + assertBadRangeList(500, "bytes=\t1\t-\t50"); + } + + @Test + public void testBadRange_TabDelim() + { + assertBadRangeList(500, "bytes=1-50\t90-101\t200-250"); + } + + @Test + public void testBadRange_SemiColonDelim() + { + assertBadRangeList(500, "bytes=1-50;90-101;200-250"); + } + + @Test + public void testBadRange_NegativeSize() + { + assertBadRangeList(500, "bytes=50-1"); + } + + @Test + public void testBadRange_DoubleDash() + { + assertBadRangeList(500, "bytes=1--20"); + } + + @Test + public void testBadRange_TrippleDash() + { + assertBadRangeList(500, "bytes=1---"); + } + + @Test + public void testBadRange_ZeroedNegativeSize() + { + assertBadRangeList(500, "bytes=050-001"); } } diff --git a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/DefaultServletRangesTest.java b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/DefaultServletRangesTest.java index 8e5ec88648a..b359f2a87bd 100644 --- a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/DefaultServletRangesTest.java +++ b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/DefaultServletRangesTest.java @@ -18,12 +18,15 @@ package org.eclipse.jetty.servlet; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import java.io.File; -import java.io.FileOutputStream; import java.io.IOException; +import java.io.OutputStream; import java.nio.charset.StandardCharsets; +import java.nio.file.Files; import org.eclipse.jetty.server.HttpConfiguration; import org.eclipse.jetty.server.LocalConnector; @@ -32,7 +35,6 @@ import org.eclipse.jetty.toolchain.test.FS; import org.eclipse.jetty.toolchain.test.MavenTestingUtils; import org.eclipse.jetty.toolchain.test.OS; import org.eclipse.jetty.toolchain.test.TestingDir; -import org.eclipse.jetty.util.IO; import org.hamcrest.Matchers; import org.junit.After; import org.junit.Assert; @@ -161,6 +163,59 @@ public class DefaultServletRangesTest } + + @Test + public void testMultipleSameRangeRequests() throws Exception + { + StringBuilder stringBuilder = new StringBuilder( ); + for(int i = 0; i < 1000; i++) + { + stringBuilder.append( "10-60," ); + } + + + String response; + response = connector.getResponse( + "GET /context/data.txt HTTP/1.1\r\n" + + "Host: localhost\r\n" + + "Connection: close\r\n"+ + "Range: bytes=" + stringBuilder.toString() +"0-2\r\n" + + "\r\n"); + int start = response.indexOf("--jetty"); + String body = response.substring(start); + String boundary = body.substring(0, body.indexOf("\r\n")); + assertResponseContains("206 Partial", response); + assertResponseContains("Content-Type: multipart/byteranges; boundary=", response); + + assertResponseContains("Content-Range: bytes 10-60/80", response); + assertResponseContains("Content-Range: bytes 0-2/80", response); + Assert.assertEquals( "Content range 0-60/80 in response not only 1:" + response , // + 2, response.split( "Content-Range: bytes 10-60/80" ).length); + assertTrue(body.endsWith(boundary + "--\r\n")); + } + + @Test + public void testMultipleSameRangeRequestsTooLargeHeader() throws Exception + { + StringBuilder stringBuilder = new StringBuilder( ); + for(int i = 0; i < 2000; i++) + { + stringBuilder.append( "10-60," ); + } + + + String response; + response = connector.getResponse( + "GET /context/data.txt HTTP/1.1\r\n" + + "Host: localhost\r\n" + + "Connection: close\r\n"+ + "Range: bytes=" + stringBuilder.toString() +"0-2\r\n" + + "\r\n"); + int start = response.indexOf("--jetty"); + assertEquals( -1, start ); + assertResponseContains("HTTP/1.1 431 Request Header Fields Too Large", response); + } + @Test public void testOpenEndRange() throws Exception { @@ -211,17 +266,11 @@ public class DefaultServletRangesTest private void createFile(File file, String str) throws IOException { - FileOutputStream out = null; - try + try(OutputStream out = Files.newOutputStream( file.toPath())) { - out = new FileOutputStream(file); out.write(str.getBytes(StandardCharsets.UTF_8)); out.flush(); } - finally - { - IO.close(out); - } } private void assertResponseNotContains(String forbidden, String response) diff --git a/tests/test-integration/src/test/java/org/eclipse/jetty/test/rfcs/RFC2616BaseTest.java b/tests/test-integration/src/test/java/org/eclipse/jetty/test/rfcs/RFC2616BaseTest.java index 994de2f21a6..ec3888b4465 100644 --- a/tests/test-integration/src/test/java/org/eclipse/jetty/test/rfcs/RFC2616BaseTest.java +++ b/tests/test-integration/src/test/java/org/eclipse/jetty/test/rfcs/RFC2616BaseTest.java @@ -1567,75 +1567,6 @@ public abstract class RFC2616BaseTest assertEquals("--"+boundary+"--",lines.get(i++)); } - /** - * Test Range (Header Field) - * - * @see RFC 2616 (section 14.35) - */ - @Test - public void test14_35_Range_Multipart2() throws Exception - { - // Request the last 1 byte, last 2 bytes, and last 3 bytes. - // This is an example of overlapping ranges - - String rangedef = "-1,-2,-3"; - - StringBuffer req1 = new StringBuffer(); - req1.append("GET /rfc2616-webapp/alpha.txt HTTP/1.1\n"); - req1.append("Host: localhost\n"); - req1.append("Range: ").append(rangedef).append("\n"); - req1.append("Connection: close\n"); - req1.append("\n"); - - HttpTester.Response response = http.request(req1); - - String msg = "Partial (Byte) Range: '" + rangedef + "'"; - assertEquals(msg,HttpStatus.PARTIAL_CONTENT_206,response.getStatus()); - - String contentType = response.get("Content-Type"); - // RFC states that multiple parts should result in multipart/byteranges Content type. - StringAssert.assertContains(msg + " Content-Type",contentType,"multipart/byteranges"); - - // Collect 'boundary' string - String boundary = null; - String parts[] = StringUtil.split(contentType,';'); - for (int i = 0; i < parts.length; i++) - { - if (parts[i].trim().startsWith("boundary=")) - { - String boundparts[] = StringUtil.split(parts[i],'='); - Assert.assertEquals(msg + " Boundary parts.length",2,boundparts.length); - boundary = boundparts[1]; - } - } - - Assert.assertNotNull(msg + " Should have found boundary in Content-Type header",boundary); - - - List lines = StringUtil.asLines(response.getContent().trim()); - int i=0; - assertEquals("--"+boundary,lines.get(i++)); - assertEquals("Content-Type: text/plain",lines.get(i++)); - assertEquals("Content-Range: bytes 26-26/27",lines.get(i++)); - assertEquals("",lines.get(i++)); - assertEquals("",lines.get(i++)); - assertEquals("",lines.get(i++)); - assertEquals("--"+boundary,lines.get(i++)); - assertEquals("Content-Type: text/plain",lines.get(i++)); - assertEquals("Content-Range: bytes 25-26/27",lines.get(i++)); - assertEquals("",lines.get(i++)); - assertEquals("Z",lines.get(i++)); - assertEquals("",lines.get(i++)); - assertEquals("--"+boundary,lines.get(i++)); - assertEquals("Content-Type: text/plain",lines.get(i++)); - assertEquals("Content-Range: bytes 24-26/27",lines.get(i++)); - assertEquals("",lines.get(i++)); - assertEquals("YZ",lines.get(i++)); - assertEquals("",lines.get(i++)); - assertEquals("--"+boundary+"--",lines.get(i++)); - - } - /** * Test Range (Header Field) *