Merge remote-tracking branch 'origin/master' into jetty-8

Conflicts:
	VERSION.txt
This commit is contained in:
Jan Bartel 2011-08-16 11:35:46 +10:00
commit 6e8afd6795
21 changed files with 414 additions and 130 deletions

View File

@ -11,7 +11,7 @@ jetty-8.0.0.M3 27 May 2011
+ 346180 jsp-2.2 support
+ Updated to jetty-7.4.2.v20110526
jetty-7.5.0-SNAPSHOT
jetty-7.5.0.RC0 August 15th 2011
+ 298502 Handle 200 Connect responses with no content-length
+ 351516 Refactored sessions to better support nosql session managers
+ 351576 Do not use deprecated method File.toURL()
@ -30,6 +30,7 @@ jetty-7.5.0-SNAPSHOT
+ 353862 Improve performance of QuotedStringTokenizer.quote()
+ 354014 Content-Length is passed to wrapped response in GZipFilter
+ 354204 Charset encodings property file not used
+ 354397 RewriteRegexRule handles special characters in regex group
+ 354466 Typo in example config of jetty-plus.xml
jetty-7.4.4.v20110707 July 7th 2011
@ -2357,7 +2358,7 @@ jetty-6.0.0rc0 - 7 July 2006
+ fixed HttpGenerator convertion of non UTF-8: JETTY-82
+ added html module from jetty 5 - but deprecated until maintainer found
jetty-6.0.0beta17 - 1/6/2006
jetty-6.0.0beta17 - 1 Jun 2006
+ Added config to disable file memory mapped buffers for windows
+ Added Request.isHandled()
+ Refactored Synchronization of SelectChannelConnector
@ -2373,11 +2374,11 @@ jetty-6.0.0beta17 - 1/6/2006
+ don't reset headers during forward
+ BoundedThreadPool.doStop waits for threads to complete
jetty-6.0.0beta16 - 12/5/2006
jetty-6.0.0beta16 - 12 May 2006
+ remove a couple of System.err.printlns
+ replace backwards compativle API in UrlEncoded
jetty-6.0.0beta15 - 11/5/2006
jetty-6.0.0beta15 - 11 May 2006
+ Added Server attribute org.mortbay.jetty.Request.maxFormContentSize
+ Renamed NotFoundHandler to DefaultHandler
+ Added automatic scan of all WEB-INF/jetty-*.xml files for plugin
@ -2404,7 +2405,7 @@ jetty-6.0.0beta15 - 11/5/2006
+ don't accept partial authority in request line.
+ enforce 204 and 304 have no content
jetty-6.0.0beta14 - 9/4/2006
jetty-6.0.0beta14 - 9 Apr 2006
+ ignore dirs and files that don't exist in plugin scanner
+ added support for stopping jetty using "java -jar start.jar --stop"
+ added configurability for webdefault.xml in maven plugin
@ -2428,7 +2429,7 @@ jetty-6.0.0beta14 - 9/4/2006
+ added reset to Continuation
jetty-6.0.0beta12 - 16/3/2006
jetty-6.0.0beta12 - 16 Mar 2006
+ Fixed maven plugin JNDI for redeploys
+ Fixed tld discovery for plugin (search dependencies)
+ Fixed JettyPlus for root contexts
@ -2438,7 +2439,7 @@ jetty-6.0.0beta12 - 16/3/2006
+ Added provider support to SslListener
+ Log ERROR for runtimeExceptions
jetty-6.0.0beta11 - 14/3/2006
jetty-6.0.0beta11 - 14 Mar 2006
+ added JAAS
+ added webapp-specific JNDI entries
+ added missing Configurations for maven plugin
@ -2451,7 +2452,7 @@ jetty-6.0.0beta11 - 14/3/2006
+ Added HttpURI and improved UTF-8 parsing.
+ refactored writers and improved UTF-8 generation.
jetty-6.0.0beta10 25/2/2006
jetty-6.0.0beta10 25 Feb 2006
+ Added support for java:comp/env
+ Added support for pluggable transaction manager
+ Forward masks include attributes and vice versa
@ -2465,7 +2466,7 @@ jetty-6.0.0beta10 25/2/2006
+ Fix http://jira.codehaus.org/browse/JETTY-6. hi byte reader
+ Updates javax to MR2 release
jetty-6.0.0beta9 9/2/2006
jetty-6.0.0beta9 9 Feb 2006
+ PathMap for direct context mapping.
+ Refactored chat demo and upgraded prototype.js
+ Continuation cleanup
@ -2479,7 +2480,7 @@ jetty-6.0.0beta9 9/2/2006
+ fixed setLocale bug sf1426940
+ Added TLD tag listener handling.
jetty-6.0.0beta8 24/1/2006
jetty-6.0.0beta8 24 Jan 2006
+ fixed dispatch of new session problem. sf:1407090
+ reinstated rfc2616 test harness
+ Handle pipeline requests without hangs
@ -3248,7 +3249,7 @@ Jetty-4.2.0 - 16 November 2002
+ Added upload demo to dump servlet.
+ Many more optimizations.
Jetty-4.1.4 - 16 November
Jetty-4.1.4 - 16 November 2002
+ Fixed ContextLoader parent delegation bug
+ Fixed remove SocketListener bug.
+ Fixed Invoker servlet for RD.include
@ -3277,7 +3278,7 @@ Jetty-4.2.0rc0 - 24 October 2002
+ Added authenticator to admin.xml
+ Fixed Session timeout NPE.
Jetty-4.1.3 - 24 October 2002
Jetty-4.1.3 - 24 October 2002
+ Fixed RolloverFileOutputStream without date.
+ Fixed SessionManager initialization
+ Added authenticator to admin.xml

View File

@ -0,0 +1,50 @@
package org.eclipse.jetty.http;
import org.eclipse.jetty.io.Buffer;
import org.junit.Assert;
import org.junit.Test;
public class MimeTypesTest
{
@Test
public void testGetMimeByExtension_Gzip()
{
assertMimeTypeByExtension("application/gzip","test.gz");
}
@Test
public void testGetMimeByExtension_Png()
{
assertMimeTypeByExtension("image/png","test.png");
assertMimeTypeByExtension("image/png","TEST.PNG");
assertMimeTypeByExtension("image/png","Test.Png");
}
@Test
public void testGetMimeByExtension_Png_MultiDot()
{
assertMimeTypeByExtension("image/png","org.eclipse.jetty.Logo.png");
}
@Test
public void testGetMimeByExtension_Png_DeepPath()
{
assertMimeTypeByExtension("image/png","/org/eclipse/jetty/Logo.png");
}
@Test
public void testGetMimeByExtension_Text()
{
assertMimeTypeByExtension("text/plain","test.txt");
assertMimeTypeByExtension("text/plain","TEST.TXT");
}
private void assertMimeTypeByExtension(String expectedMimeType, String filename)
{
MimeTypes mimetypes = new MimeTypes();
Buffer contentType = mimetypes.getMimeByExtension(filename);
String prefix = "MimeTypes.getMimeByExtension(" + filename + ")";
Assert.assertNotNull(prefix,contentType);
Assert.assertEquals(prefix,expectedMimeType,contentType.toString());
}
}

View File

@ -119,6 +119,12 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
_manager.endPointUpgraded(this,old);
}
/* ------------------------------------------------------------ */
public long getIdleTimestamp()
{
return _idleTimestamp;
}
/* ------------------------------------------------------------ */
/** Called by selectSet to schedule handling
*

View File

@ -1,5 +1,4 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-project</artifactId>

View File

@ -56,7 +56,7 @@ public class RewriteRegexRule extends RegexRule implements Rule.ApplyURI
target=_replacement;
for (int g=1;g<=matcher.groupCount();g++)
{
String group = matcher.group(g);
String group = Matcher.quoteReplacement(matcher.group(g));
target=target.replaceAll("\\$"+g,group);
}
@ -73,7 +73,7 @@ public class RewriteRegexRule extends RegexRule implements Rule.ApplyURI
String uri=_replacement;
for (int g=1;g<=matcher.groupCount();g++)
{
String group = matcher.group(g);
String group = Matcher.quoteReplacement(matcher.group(g));
uri=uri.replaceAll("\\$"+g,group);
}
request.setRequestURI(uri);

View File

@ -26,6 +26,8 @@ public class RewriteRegexRuleTest extends AbstractRuleTestCase
{"/foo/bar",".*","/replace","/replace"},
{"/foo/bar","/xxx.*","/replace",null},
{"/foo/bar","/(.*)/(.*)","/$2/$1/xxx","/bar/foo/xxx"},
{"/foo/$bar",".*","/$replace","/$replace"},
{"/foo/$bar","/foo/(.*)","/$1/replace","/$bar/replace"},
};
private RewriteRegexRule _rule;

View File

@ -6,12 +6,15 @@ import java.util.List;
import javax.servlet.Servlet;
import org.eclipse.jetty.http.gzip.GzipResponseWrapper;
import org.eclipse.jetty.servlet.DefaultServlet;
import org.eclipse.jetty.servlet.FilterHolder;
import org.eclipse.jetty.servlets.gzip.GzipTester;
import org.eclipse.jetty.servlets.gzip.TestServletLengthStreamTypeWrite;
import org.eclipse.jetty.servlets.gzip.TestServletLengthTypeStreamWrite;
import org.eclipse.jetty.servlets.gzip.TestServletStreamLengthTypeWrite;
import org.eclipse.jetty.servlets.gzip.TestServletStreamTypeLengthWrite;
import org.eclipse.jetty.servlets.gzip.TestServletTypeLengthStreamWrite;
import org.eclipse.jetty.servlets.gzip.TestServletTypeStreamLengthWrite;
import org.eclipse.jetty.toolchain.test.TestingDir;
import org.junit.Rule;
import org.junit.Test;
@ -30,11 +33,13 @@ public class GzipFilterContentLengthTest
/**
* These are the junit parameters for running this test.
* <p>
* We have 4 test servlets, that arrange the content-length/content-type/get stream in different orders so as to
* simulate the real world scenario that caused the bug in <a
* href="Eclipse Bug 354014">http://bugs.eclipse.org/354014</a>
* In addition to Jetty's DefaultServlet we have multiple test
* servlets that arrange content-length/content-type/get stream
* in different order so as to simulate the real world scenario
* that caused the bug in Eclipse <a href="Bug 354014">http://bugs.eclipse.org/354014</a>
* <p>
* This test case will be run with each entry in the array below as setup parameters for the test case.
* This test case will be run with each of the entries in
* the array below as setup parameters for the test case.
*
* @return the junit parameters
*/
@ -43,15 +48,19 @@ public class GzipFilterContentLengthTest
{
return Arrays.asList(new Object[][]
{
{ DefaultServlet.class },
{ TestServletLengthStreamTypeWrite.class },
{ TestServletLengthTypeStreamWrite.class },
{ TestServletStreamLengthTypeWrite.class },
{ TestServletStreamTypeLengthWrite.class },
{ TestServletTypeLengthStreamWrite.class } });
{ TestServletTypeLengthStreamWrite.class },
{ TestServletTypeStreamLengthWrite.class } });
}
private static final int LARGE = GzipResponseWrapper.DEFAULT_BUFFER_SIZE * 8;
private static final int MEDIUM = GzipResponseWrapper.DEFAULT_BUFFER_SIZE;
private static final int SMALL = GzipResponseWrapper.DEFAULT_BUFFER_SIZE / 4;
private static final int TINY = GzipResponseWrapper.DEFAULT_MIN_GZIP_SIZE / 2;
@Rule
public TestingDir testingdir = new TestingDir();
@ -63,20 +72,19 @@ public class GzipFilterContentLengthTest
this.testServlet = testServlet;
}
private void assertIsGzipCompressed(Class<? extends Servlet> servletClass, int filesize) throws Exception
private void assertIsGzipCompressed(String filename, int filesize) throws Exception
{
GzipTester tester = new GzipTester(testingdir);
// Test content that is smaller than the buffer.
tester.prepareServerFile("file.txt",filesize);
tester.prepareServerFile(filename,filesize);
FilterHolder holder = tester.setContentServlet(servletClass);
FilterHolder holder = tester.setContentServlet(testServlet);
holder.setInitParameter("mimeTypes","text/plain");
try
{
tester.start();
tester.assertIsResponseGzipCompressed("file.txt");
tester.assertIsResponseGzipCompressed(filename);
}
finally
{
@ -84,20 +92,19 @@ public class GzipFilterContentLengthTest
}
}
private void assertIsNotGzipCompressed(Class<? extends Servlet> servletClass, int filesize) throws Exception
private void assertIsNotGzipCompressed(String filename, int filesize) throws Exception
{
GzipTester tester = new GzipTester(testingdir);
// Test content that is smaller than the buffer.
tester.prepareServerFile("file.mp3",filesize);
tester.prepareServerFile(filename,filesize);
FilterHolder holder = tester.setContentServlet(org.eclipse.jetty.servlet.DefaultServlet.class);
FilterHolder holder = tester.setContentServlet(testServlet);
holder.setInitParameter("mimeTypes","text/plain");
try
{
tester.start();
tester.assertIsResponseNotGzipCompressed("file.mp3",filesize);
tester.assertIsResponseNotGzipCompressed(filename,filesize);
}
finally
{
@ -105,42 +112,78 @@ public class GzipFilterContentLengthTest
}
}
@Test
public void testIsGzipCompressedTiny() throws Exception
{
assertIsGzipCompressed(testServlet,SMALL);
}
/**
* Tests for Length>Type>Stream>Write problems encountered in GzipFilter
*
* @see <a href="Eclipse Bug 354014">http://bugs.eclipse.org/354014</a>
* Tests gzip compression of a small size file
*/
@Test
public void testIsGzipCompressedSmall() throws Exception
{
assertIsGzipCompressed("file.txt",SMALL);
}
/**
* Tests gzip compression of a medium size file
*/
@Test
public void testIsGzipCompressedMedium() throws Exception
{
assertIsGzipCompressed(testServlet,MEDIUM);
assertIsGzipCompressed("file.txt",MEDIUM);
}
/**
* Tests for Length>Type>Stream>Write problems encountered in GzipFilter
*
* @see <a href="Eclipse Bug 354014">http://bugs.eclipse.org/354014</a>
* Tests gzip compression of a large size file
*/
@Test
public void testIsGzipCompressedLarge() throws Exception
{
assertIsGzipCompressed(testServlet,LARGE);
assertIsGzipCompressed("file.txt",LARGE);
}
/**
* Tests for Length>Type>Stream>Write problems encountered in GzipFilter
* Tests for problems with Content-Length header on small size files
* that are not being compressed encountered when using GzipFilter
*
* @see <a href="Eclipse Bug 354014">http://bugs.eclipse.org/354014</a>
*/
@Test
public void testIsNotGzipCompressed() throws Exception
public void testIsNotGzipCompressedTiny() throws Exception
{
assertIsNotGzipCompressed(TestServletLengthTypeStreamWrite.class,LARGE);
assertIsNotGzipCompressed("file.txt",TINY);
}
/**
* Tests for problems with Content-Length header on small size files
* that are not being compressed encountered when using GzipFilter
*
* @see <a href="Eclipse Bug 354014">http://bugs.eclipse.org/354014</a>
*/
@Test
public void testIsNotGzipCompressedSmall() throws Exception
{
assertIsNotGzipCompressed("file.mp3",SMALL);
}
/**
* Tests for problems with Content-Length header on medium size files
* that are not being compressed encountered when using GzipFilter
*
* @see <a href="Eclipse Bug 354014">http://bugs.eclipse.org/354014</a>
*/
@Test
public void testIsNotGzipCompressedMedium() throws Exception
{
assertIsNotGzipCompressed("file.mp3",MEDIUM);
}
/**
* Tests for problems with Content-Length header on large size files
* that were not being compressed encountered when using GzipFilter
*
* @see <a href="Eclipse Bug 354014">http://bugs.eclipse.org/354014</a>
*/
@Test
public void testIsNotGzipCompressedLarge() throws Exception
{
assertIsNotGzipCompressed("file.mp3",LARGE);
}
}

View File

@ -8,10 +8,10 @@ import java.util.List;
import org.eclipse.jetty.servlet.DefaultServlet;
import org.eclipse.jetty.servlet.FilterHolder;
import org.eclipse.jetty.servlets.gzip.GzipTester;
import org.eclipse.jetty.servlets.gzip.TestStaticMimeTypeServlet;
import org.eclipse.jetty.toolchain.test.IO;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
import org.eclipse.jetty.toolchain.test.TestingDir;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@ -19,9 +19,8 @@ import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
/**
* Tests {@link GzipFilter} in combination with {@link DefaultServlet} for
* ability to configure {@link GzipFilter} to ignore recompress situations
* from upstream.
* Tests {@link GzipFilter} in combination with {@link DefaultServlet} for ability to configure {@link GzipFilter} to
* ignore recompress situations from upstream.
*/
@RunWith(Parameterized.class)
public class GzipFilterDefaultNoRecompressTest
@ -32,59 +31,52 @@ public class GzipFilterDefaultNoRecompressTest
return Arrays.asList(new Object[][]
{
// Some already compressed files
{ "test_quotes.gz" },
{ "test_quotes.bz2" },
{ "test_quotes.zip" },
{ "test_quotes.rar" },
{ "test_quotes.gz", "application/gzip" },
{ "test_quotes.bz2", "application/bzip2" },
{ "test_quotes.zip", "application/zip" },
{ "test_quotes.rar", "application/octet-stream" },
// Some images (common first)
{ "jetty_logo.png" },
{ "jetty_logo.gif" },
{ "jetty_logo.jpeg" },
{ "jetty_logo.jpg" },
{ "jetty_logo.png", "image/png" },
{ "jetty_logo.gif", "image/gif" },
{ "jetty_logo.jpeg", "image/jpeg" },
{ "jetty_logo.jpg", "image/jpeg" },
// Lesser encountered images (usually found being requested from non-browser clients)
{ "jetty_logo.bmp" },
{ "jetty_logo.tga" },
{ "jetty_logo.tif" },
{ "jetty_logo.tiff" },
{ "jetty_logo.xcf" },
{ "jetty_logo.jp2" } });
{ "jetty_logo.bmp", "image/bmp" },
{ "jetty_logo.tga", "application/tga" },
{ "jetty_logo.tif", "image/tiff" },
{ "jetty_logo.tiff", "image/tiff" },
{ "jetty_logo.xcf", "image/xcf" },
{ "jetty_logo.jp2", "image/jpeg2000" } });
}
@Rule
public TestingDir testingdir = new TestingDir();
private String alreadyCompressedFilename;
public GzipFilterDefaultNoRecompressTest(String testFilename) {
private String expectedContentType;
public GzipFilterDefaultNoRecompressTest(String testFilename, String expectedContentType)
{
this.alreadyCompressedFilename = testFilename;
this.expectedContentType = expectedContentType;
}
@Test
@Ignore("Cannot find a configuration that would allow this to pass")
public void testNotGzipFiltered_Default_AlreadyCompressed() throws Exception
{
GzipTester tester = new GzipTester(testingdir);
copyTestFileToServer(alreadyCompressedFilename);
// Using DefaultServlet, with default GzipFilter setup
FilterHolder holder = tester.setContentServlet(DefaultServlet.class);
// TODO: find a configuration of the GzipFilter to allow
// each of these test cases to pass.
FilterHolder holder = tester.setContentServlet(TestStaticMimeTypeServlet.class);
StringBuilder mimeTypes = new StringBuilder();
mimeTypes.append("images/png");
mimeTypes.append(",images/jpeg");
mimeTypes.append(",images/gif");
mimeTypes.append(",images/jp2");
holder.setInitParameter("mimeTypes", mimeTypes.toString());
mimeTypes.append("text/plain");
holder.setInitParameter("mimeTypes",mimeTypes.toString());
try
{
tester.start();
tester.assertIsResponseNotGzipFiltered(alreadyCompressedFilename,
alreadyCompressedFilename + ".sha1");
tester.assertIsResponseNotGzipFiltered(alreadyCompressedFilename,alreadyCompressedFilename + ".sha1",expectedContentType);
}
finally
{

View File

@ -113,8 +113,9 @@ public class GzipTester
* @param testResourceSha1Sum
* the sha1sum file that contains the SHA1SUM checksum that will be used to verify that the response
* contents are what is intended.
* @param expectedContentType
*/
public void assertIsResponseNotGzipFiltered(String requestedFilename, String testResourceSha1Sum) throws Exception
public void assertIsResponseNotGzipFiltered(String requestedFilename, String testResourceSha1Sum, String expectedContentType) throws Exception
{
System.err.printf("[GzipTester] requesting /context/%s%n",requestedFilename);
HttpTester request = new HttpTester();
@ -135,13 +136,13 @@ public class GzipTester
dumpHeaders(requestedFilename + " / Response Headers",response);
// Assert the response headers
Assert.assertThat(requestedFilename + " / Response.method",response.getMethod(),nullValue());
Assert.assertThat(requestedFilename + " / Response.status",response.getStatus(),is(HttpServletResponse.SC_OK));
Assert.assertThat(requestedFilename + " / Response.header[Content-Length]",response.getHeader("Content-Length"),notNullValue());
Assert.assertThat(requestedFilename + " / Response.header[Content-Encoding] (should not be recompressed by GzipFilter)",
response.getHeader("Content-Encoding"),nullValue());
Assert.assertThat(requestedFilename + " / Response.header[Content-Type] (should have a Content-Type associated with it)",
response.getHeader("Content-Type"),notNullValue());
String prefix = requestedFilename + " / Response";
Assert.assertThat(prefix + ".method",response.getMethod(),nullValue());
Assert.assertThat(prefix + ".status",response.getStatus(),is(HttpServletResponse.SC_OK));
Assert.assertThat(prefix + ".header[Content-Length]",response.getHeader("Content-Length"),notNullValue());
Assert.assertThat(prefix + ".header[Content-Encoding] (should not be recompressed by GzipFilter)",response.getHeader("Content-Encoding"),nullValue());
Assert.assertThat(prefix + ".header[Content-Type] (should have a Content-Type associated with it)",response.getHeader("Content-Type"),notNullValue());
Assert.assertThat(prefix + ".header[Content-Type]",response.getHeader("Content-Type"),is(expectedContentType));
ByteArrayInputStream bais = null;
DigestOutputStream digester = null;

View File

@ -0,0 +1,47 @@
package org.eclipse.jetty.servlets.gzip;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.servlets.GzipFilter;
/**
* A sample servlet to serve static content, using a order of construction that has caused problems for
* {@link GzipFilter} in the past.
*
* Using a real-world pattern of:
*
* <pre>
* 1) set content length
* 2) get stream
* 3) set content type
* 4) write
* </pre>
*
* @see <a href="Eclipse Bug 354014">http://bugs.eclipse.org/354014</a>
*/
@SuppressWarnings("serial")
public class TestServletLengthStreamTypeWrite extends TestDirContentServlet
{
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
String fileName = request.getServletPath();
byte[] dataBytes = loadContentFileBytes(fileName);
response.setContentLength(dataBytes.length);
ServletOutputStream out = response.getOutputStream();
if (fileName.endsWith("txt"))
response.setContentType("text/plain");
else if (fileName.endsWith("mp3"))
response.setContentType("audio/mpeg");
out.write(dataBytes);
}
}

View File

@ -0,0 +1,47 @@
package org.eclipse.jetty.servlets.gzip;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.servlets.GzipFilter;
/**
* A sample servlet to serve static content, using a order of construction that has caused problems for
* {@link GzipFilter} in the past.
*
* Using a real-world pattern of:
*
* <pre>
* 1) set content type
* 2) get stream
* 3) set content length
* 4) write
* </pre>
*
* @see <a href="Eclipse Bug 354014">http://bugs.eclipse.org/354014</a>
*/
@SuppressWarnings("serial")
public class TestServletTypeStreamLengthWrite extends TestDirContentServlet
{
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
String fileName = request.getServletPath();
byte[] dataBytes = loadContentFileBytes(fileName);
if (fileName.endsWith("txt"))
response.setContentType("text/plain");
else if (fileName.endsWith("mp3"))
response.setContentType("audio/mpeg");
ServletOutputStream out = response.getOutputStream();
response.setContentLength(dataBytes.length);
out.write(dataBytes);
}
}

View File

@ -0,0 +1,67 @@
package org.eclipse.jetty.servlets.gzip;
import java.io.IOException;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.http.MimeTypes;
import org.eclipse.jetty.io.Buffer;
/**
* Test servlet for testing against unusual MimeTypes and Content-Types.
*/
@SuppressWarnings("serial")
public class TestStaticMimeTypeServlet extends TestDirContentServlet
{
private MimeTypes mimeTypes;
@Override
public void init(ServletConfig config) throws ServletException
{
super.init(config);
mimeTypes = new MimeTypes();
// Some real world, yet not terribly common, mime type mappings.
mimeTypes.addMimeMapping("bz2","application/bzip2");
mimeTypes.addMimeMapping("bmp","image/bmp");
mimeTypes.addMimeMapping("tga","application/tga");
mimeTypes.addMimeMapping("xcf","image/xcf");
mimeTypes.addMimeMapping("jp2","image/jpeg2000");
// Some of the other gzip mime-types seen in the wild.
// NOTE: Using oddball extensions just so that the calling request can specify
// which strange mime type to use.
mimeTypes.addMimeMapping("x-gzip","application/x-gzip");
mimeTypes.addMimeMapping("x-gunzip","application/x-gunzip");
mimeTypes.addMimeMapping("gzipped","application/gzippped");
mimeTypes.addMimeMapping("gzip-compressed","application/gzip-compressed");
mimeTypes.addMimeMapping("x-compressed","application/x-compressed");
mimeTypes.addMimeMapping("x-compress","application/x-compress");
mimeTypes.addMimeMapping("gzipdoc","gzip/document");
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
String fileName = request.getServletPath();
byte[] dataBytes = loadContentFileBytes(fileName);
response.setContentLength(dataBytes.length);
Buffer buf = mimeTypes.getMimeByExtension(fileName);
if (buf == null)
{
response.setContentType("application/octet-stream");
}
else
{
response.setContentType(buf.toString());
}
ServletOutputStream out = response.getOutputStream();
out.write(dataBytes);
}
}

View File

@ -228,7 +228,7 @@ public class TestClient implements WebSocket.OnFrame
__start=System.currentTimeMillis();
for (int i=0;i<clients;i++)
{
client[i]=new TestClient(host,port,protocol==null?null:protocol,10000);
client[i]=new TestClient(host,port,protocol==null?null:protocol,60000);
client[i].open();
}

View File

@ -14,7 +14,7 @@ public interface WebSocketConnection extends Connection
{
void fillBuffersFrom(Buffer buffer);
void handshake(HttpServletRequest request, HttpServletResponse response, String origin, String subprotocol) throws IOException;
void handshake(HttpServletRequest request, HttpServletResponse response, String subprotocol) throws IOException;
List<Extension> getExtensions();

View File

@ -362,7 +362,7 @@ public class WebSocketConnectionD00 extends AbstractConnection implements WebSoc
void access(EndPoint endp);
}
public void handshake(HttpServletRequest request, HttpServletResponse response, String origin, String subprotocol) throws IOException
public void handshake(HttpServletRequest request, HttpServletResponse response, String subprotocol) throws IOException
{
String uri=request.getRequestURI();
String query=request.getQueryString();
@ -370,7 +370,9 @@ public class WebSocketConnectionD00 extends AbstractConnection implements WebSoc
uri+="?"+query;
String host=request.getHeader("Host");
String origin=request.getHeader("Host");
String key1 = request.getHeader("Sec-WebSocket-Key1");
if (key1!=null)
{
String key2 = request.getHeader("Sec-WebSocket-Key2");

View File

@ -710,7 +710,7 @@ public class WebSocketConnectionD06 extends AbstractConnection implements WebSoc
}
/* ------------------------------------------------------------ */
public void handshake(HttpServletRequest request, HttpServletResponse response, String origin, String subprotocol) throws IOException
public void handshake(HttpServletRequest request, HttpServletResponse response, String subprotocol) throws IOException
{
String uri=request.getRequestURI();
String query=request.getQueryString();

View File

@ -90,7 +90,8 @@ public class WebSocketConnectionD10 extends AbstractConnection implements WebSoc
private final String _protocol;
private final int _draft;
private final ClassLoader _context;
private int _close;
private volatile int _closeCode;
private volatile String _closeMessage;
private volatile boolean _closedIn;
private volatile boolean _closedOut;
private int _maxTextMessageSize;
@ -275,7 +276,8 @@ public class WebSocketConnectionD10 extends AbstractConnection implements WebSoc
@Override
public void idleExpired()
{
closeOut(WebSocketConnectionD10.CLOSE_NORMAL,"Idle");
long idle = System.currentTimeMillis()-((SelectChannelEndPoint)_endp).getIdleTimestamp();
closeOut(WebSocketConnectionD10.CLOSE_NORMAL,"Idle for "+idle+"ms");
}
/* ------------------------------------------------------------ */
@ -290,9 +292,9 @@ public class WebSocketConnectionD10 extends AbstractConnection implements WebSoc
final boolean closed;
synchronized (this)
{
closed=_close==0;
closed=_closeCode==0;
if (closed)
_close=WebSocketConnectionD10.CLOSE_NOCLOSE;
_closeCode=WebSocketConnectionD10.CLOSE_NOCLOSE;
}
if (closed)
_webSocket.onClose(WebSocketConnectionD10.CLOSE_NOCLOSE,"closed");
@ -309,9 +311,12 @@ public class WebSocketConnectionD10 extends AbstractConnection implements WebSoc
{
closedOut=_closedOut;
_closedIn=true;
closed=_close==0;
closed=_closeCode==0;
if (closed)
_close=code;
{
_closeCode=code;
_closeMessage=message;
}
}
try
@ -346,9 +351,12 @@ public class WebSocketConnectionD10 extends AbstractConnection implements WebSoc
{
close=_closedIn || _closedOut;
_closedOut=true;
closed=_close==0;
closed=_closeCode==0;
if (closed)
_close=code;
{
_closeCode=code;
_closeMessage=message;
}
}
try
@ -409,7 +417,7 @@ public class WebSocketConnectionD10 extends AbstractConnection implements WebSoc
public void sendMessage(String content) throws IOException
{
if (_closedOut)
throw new IOException("closing");
throw new IOException("closedOut "+_closeCode+":"+_closeMessage);
byte[] data = content.getBytes(StringUtil.__UTF8);
_outbound.addFrame((byte)FLAG_FIN,WebSocketConnectionD10.OP_TEXT,data,0,data.length);
checkWriteable();
@ -420,7 +428,7 @@ public class WebSocketConnectionD10 extends AbstractConnection implements WebSoc
public void sendMessage(byte[] content, int offset, int length) throws IOException
{
if (_closedOut)
throw new IOException("closing");
throw new IOException("closedOut "+_closeCode+":"+_closeMessage);
_outbound.addFrame((byte)FLAG_FIN,WebSocketConnectionD10.OP_BINARY,content,offset,length);
checkWriteable();
_idle.access(_endp);
@ -430,7 +438,7 @@ public class WebSocketConnectionD10 extends AbstractConnection implements WebSoc
public void sendFrame(byte flags,byte opcode, byte[] content, int offset, int length) throws IOException
{
if (_closedOut)
throw new IOException("closing");
throw new IOException("closedOut "+_closeCode+":"+_closeMessage);
_outbound.addFrame(flags,opcode,content,offset,length);
checkWriteable();
_idle.access(_endp);
@ -440,7 +448,7 @@ public class WebSocketConnectionD10 extends AbstractConnection implements WebSoc
public void sendControl(byte ctrl, byte[] data, int offset, int length) throws IOException
{
if (_closedOut)
throw new IOException("closing");
throw new IOException("closedOut "+_closeCode+":"+_closeMessage);
_outbound.addFrame((byte)FLAG_FIN,ctrl,data,offset,length);
checkWriteable();
_idle.access(_endp);
@ -798,7 +806,7 @@ public class WebSocketConnectionD10 extends AbstractConnection implements WebSoc
}
/* ------------------------------------------------------------ */
public void handshake(HttpServletRequest request, HttpServletResponse response, String origin, String subprotocol) throws IOException
public void handshake(HttpServletRequest request, HttpServletResponse response, String subprotocol) throws IOException
{
String uri=request.getRequestURI();
String query=request.getQueryString();

View File

@ -38,9 +38,21 @@ public class WebSocketFactory
{
public interface Acceptor
{
/* ------------------------------------------------------------ */
/**
* @param request
* @param protocol
* @return
*/
WebSocket doWebSocketConnect(HttpServletRequest request, String protocol);
String checkOrigin(HttpServletRequest request, String host, String origin);
/* ------------------------------------------------------------ */
/** Check the origin of an incoming WebSocket handshake request
* @param request
* @param origin
* @return boolean to indicate that the origin is acceptable.
*/
boolean checkOrigin(HttpServletRequest request, String origin);
}
private final Map<String,Class<? extends Extension>> _extensionClasses = new HashMap<String, Class<? extends Extension>>();
@ -128,7 +140,7 @@ public class WebSocketFactory
* @param protocol The websocket protocol
* @throws IOException in case of I/O errors
*/
public void upgrade(HttpServletRequest request, HttpServletResponse response, WebSocket websocket, String origin, String protocol)
public void upgrade(HttpServletRequest request, HttpServletResponse response, WebSocket websocket, String protocol)
throws IOException
{
if (!"websocket".equalsIgnoreCase(request.getHeader("Upgrade")))
@ -176,7 +188,7 @@ public class WebSocketFactory
}
// Let the connection finish processing the handshake
connection.handshake(request, response, origin, protocol);
connection.handshake(request, response, protocol);
response.flushBuffer();
// Give the connection any unused data from the HTTP connection.
@ -205,11 +217,20 @@ public class WebSocketFactory
{
if ("websocket".equalsIgnoreCase(request.getHeader("Upgrade")))
{
String origin = request.getHeader("Sec-WebSocket-Origin");
if (origin==null)
origin = request.getHeader("Origin");
if (!_acceptor.checkOrigin(request,origin))
{
response.sendError(HttpServletResponse.SC_FORBIDDEN);
return false;
}
// Try each requested protocol
WebSocket websocket = null;
String protocol = request.getHeader("Sec-WebSocket-Protocol");
if (protocol == null) // TODO remove once draft period is over
protocol = request.getHeader("WebSocket-Protocol");
WebSocket websocket = null;
for (String p : parseProtocols(protocol))
{
websocket = _acceptor.doWebSocketConnect(request, p);
@ -220,17 +241,16 @@ public class WebSocketFactory
}
}
String host = request.getHeader("Host");
String origin = request.getHeader("Origin");
origin = _acceptor.checkOrigin(request, host, origin);
if (websocket != null)
// Did we get a websocket?
if (websocket == null)
{
upgrade(request, response, websocket, origin, protocol);
return true;
response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
return false;
}
response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
// Send the upgrade
upgrade(request, response, websocket, protocol);
return true;
}
return false;

View File

@ -100,11 +100,9 @@ public abstract class WebSocketHandler extends HandlerWrapper implements WebSock
}
/* ------------------------------------------------------------ */
public String checkOrigin(HttpServletRequest request, String host, String origin)
public boolean checkOrigin(HttpServletRequest request, String origin)
{
if (origin==null)
origin=host;
return origin;
return true;
}
}

View File

@ -14,6 +14,8 @@
package org.eclipse.jetty.websocket;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
@ -65,11 +67,10 @@ public abstract class WebSocketServlet extends HttpServlet implements WebSocketF
super.service(request,response);
}
public String checkOrigin(HttpServletRequest request, String host, String origin)
/* ------------------------------------------------------------ */
public boolean checkOrigin(HttpServletRequest request, String origin)
{
if (origin==null)
origin=host;
return origin;
return true;
}

View File

@ -745,7 +745,7 @@ public class WebSocketMessageD10Test
lookFor("sent on connect",input);
assertEquals((byte)0x88,(byte)input.read());
assertEquals(0x06,input.read());
assertEquals(17,input.read());
assertEquals(1000/0x100,input.read());
assertEquals(1000%0x100,input.read());
lookFor("Idle",input);