aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Becker2012-08-23 13:36:49 (EDT)
committerThomas Becker2012-08-23 13:36:49 (EDT)
commit9173751438bf29033a8de0336d918380751a39f8 (patch)
tree36c3006338edeae03d7e62c0947f521111b3ec37
parent2bd6cf2ebfdf9f315e12934732f54550d889812b (diff)
downloadorg.eclipse.jetty.project-9173751438bf29033a8de0336d918380751a39f8.zip
org.eclipse.jetty.project-9173751438bf29033a8de0336d918380751a39f8.tar.gz
org.eclipse.jetty.project-9173751438bf29033a8de0336d918380751a39f8.tar.bz2
387919: throw EOFException on early eof from client on http requests
-rw-r--r--jetty-server/src/main/java/org/eclipse/jetty/server/AbstractHttpConnection.java35
-rw-r--r--jetty-server/src/main/java/org/eclipse/jetty/server/HttpInput.java17
-rw-r--r--jetty-server/src/test/java/org/eclipse/jetty/server/HttpServerTestBase.java57
-rw-r--r--jetty-server/src/test/java/org/eclipse/jetty/server/ssl/SelectChannelServerSslTest.java14
-rw-r--r--jetty-server/src/test/java/org/eclipse/jetty/server/ssl/SslSocketServerTest.java6
-rw-r--r--jetty-server/src/test/resources/jetty-logging.properties3
6 files changed, 111 insertions, 21 deletions
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractHttpConnection.java b/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractHttpConnection.java
index 8bf464a..3d2d13f 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractHttpConnection.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractHttpConnection.java
@@ -129,6 +129,7 @@ public abstract class AbstractHttpConnection extends AbstractConnection
private boolean _head = false;
private boolean _host = false;
private boolean _delayedHandling=false;
+ private boolean _earlyEOF = false;
/* ------------------------------------------------------------ */
public static AbstractHttpConnection getCurrentConnection()
@@ -395,6 +396,12 @@ public abstract class AbstractHttpConnection extends AbstractConnection
}
/* ------------------------------------------------------------ */
+ public boolean isEarlyEOF()
+ {
+ return _earlyEOF;
+ }
+
+ /* ------------------------------------------------------------ */
public void reset()
{
_parser.reset();
@@ -407,6 +414,7 @@ public abstract class AbstractHttpConnection extends AbstractConnection
_response.recycle();
_uri.clear();
_writer=null;
+ _earlyEOF = false;
}
/* ------------------------------------------------------------ */
@@ -443,7 +451,7 @@ public abstract class AbstractHttpConnection extends AbstractConnection
{
_uri.getPort();
String path = null;
-
+
try
{
path = _uri.getDecodedPath();
@@ -454,7 +462,7 @@ public abstract class AbstractHttpConnection extends AbstractConnection
LOG.ignore(e);
path = _uri.getDecodedPath(StringUtil.__ISO_8859_1);
}
-
+
info=URIUtil.canonicalPath(path);
if (info==null && !_request.getMethod().equals(HttpMethods.CONNECT))
{
@@ -719,6 +727,7 @@ public abstract class AbstractHttpConnection extends AbstractConnection
_requests);
}
+ /* ------------------------------------------------------------ */
protected void startRequest(Buffer method, Buffer uri, Buffer version) throws IOException
{
uri=uri.asImmutableBuffer();
@@ -778,6 +787,7 @@ public abstract class AbstractHttpConnection extends AbstractConnection
}
}
+ /* ------------------------------------------------------------ */
protected void parsedHeader(Buffer name, Buffer value) throws IOException
{
int ho = HttpHeaders.CACHE.getOrdinal(name);
@@ -839,6 +849,7 @@ public abstract class AbstractHttpConnection extends AbstractConnection
_requestFields.add(name, value);
}
+ /* ------------------------------------------------------------ */
protected void headerComplete() throws IOException
{
_requests++;
@@ -909,6 +920,7 @@ public abstract class AbstractHttpConnection extends AbstractConnection
_delayedHandling=true;
}
+ /* ------------------------------------------------------------ */
protected void content(Buffer buffer) throws IOException
{
if (_delayedHandling)
@@ -918,6 +930,7 @@ public abstract class AbstractHttpConnection extends AbstractConnection
}
}
+ /* ------------------------------------------------------------ */
public void messageComplete(long contentLength) throws IOException
{
if (_delayedHandling)
@@ -928,6 +941,12 @@ public abstract class AbstractHttpConnection extends AbstractConnection
}
/* ------------------------------------------------------------ */
+ public void earlyEOF()
+ {
+ _earlyEOF = true;
+ }
+
+ /* ------------------------------------------------------------ */
/* ------------------------------------------------------------ */
/* ------------------------------------------------------------ */
private class RequestHandler extends HttpParser.EventHandler
@@ -996,6 +1015,18 @@ public abstract class AbstractHttpConnection extends AbstractConnection
if (LOG.isDebugEnabled())
LOG.debug("Bad request!: "+version+" "+status+" "+reason);
}
+
+ /* ------------------------------------------------------------ */
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jetty.server.server.HttpParser.EventHandler#earlyEOF()
+ */
+ @Override
+ public void earlyEOF()
+ {
+ AbstractHttpConnection.this.earlyEOF();
+ }
}
/* ------------------------------------------------------------ */
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpInput.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpInput.java
index af5d510..025cf68 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpInput.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpInput.java
@@ -24,12 +24,13 @@ import javax.servlet.ServletInputStream;
import org.eclipse.jetty.http.HttpParser;
import org.eclipse.jetty.io.Buffer;
+import org.eclipse.jetty.io.EofException;
public class HttpInput extends ServletInputStream
{
protected final AbstractHttpConnection _connection;
protected final HttpParser _parser;
-
+
/* ------------------------------------------------------------ */
public HttpInput(AbstractHttpConnection connection)
{
@@ -44,11 +45,9 @@ public class HttpInput extends ServletInputStream
@Override
public int read() throws IOException
{
- int c=-1;
- Buffer content=_parser.blockForContent(_connection.getMaxIdleTime());
- if (content!=null)
- c= 0xff & content.get();
- return c;
+ byte[] bytes = new byte[1];
+ int read = read(bytes, 0, 1);
+ return read < 0 ? -1 : 0xff & bytes[0];
}
/* ------------------------------------------------------------ */
@@ -62,6 +61,8 @@ public class HttpInput extends ServletInputStream
Buffer content=_parser.blockForContent(_connection.getMaxIdleTime());
if (content!=null)
l= content.get(b, off, len);
+ else if (_connection.isEarlyEOF())
+ throw new EofException("early EOF");
return l;
}
@@ -71,8 +72,4 @@ public class HttpInput extends ServletInputStream
{
return _parser.available();
}
-
-
-
-
}
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpServerTestBase.java b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpServerTestBase.java
index 9d51233..e902ec0 100644
--- a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpServerTestBase.java
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpServerTestBase.java
@@ -30,15 +30,16 @@ import java.net.SocketException;
import java.net.URL;
import java.util.Arrays;
import java.util.Random;
-import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.Exchanger;
+import java.util.concurrent.atomic.AtomicBoolean;
import javax.servlet.ServletException;
+import javax.servlet.ServletInputStream;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
-
import org.eclipse.jetty.io.EndPoint;
+import org.eclipse.jetty.io.EofException;
import org.eclipse.jetty.server.handler.AbstractHandler;
import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.StringUtil;
@@ -50,10 +51,11 @@ import org.junit.Test;
import org.junit.matchers.JUnitMatchers;
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
+import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotSame;
-import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
/**
*
@@ -148,8 +150,55 @@ public abstract class HttpServerTestBase extends HttpServerTestFixture
client.close();
}
}
-
+ @Test
+ public void testInterruptedRequest() throws Exception
+ {
+ final AtomicBoolean fourBytesRead = new AtomicBoolean(false);
+ final AtomicBoolean earlyEOFException = new AtomicBoolean(false);
+ configureServer(new AbstractHandler()
+ {
+ public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
+ {
+ baseRequest.setHandled(true);
+ int contentLength = request.getContentLength();
+ ServletInputStream inputStream = request.getInputStream();
+ for (int i = 0; i < contentLength; i++)
+ {
+ try
+ {
+ inputStream.read();
+ }
+ catch (EofException e)
+ {
+ earlyEOFException.set(true);
+ throw e;
+ }
+ if (i == 3)
+ fourBytesRead.set(true);
+ }
+ }
+ });
+
+ StringBuffer request = new StringBuffer("GET / HTTP/1.0\n");
+ request.append("Host: localhost\n");
+ request.append("Content-length: 6\n\n");
+ request.append("foo");
+
+ Socket client = newSocket(HOST, _connector.getLocalPort());
+ OutputStream os = client.getOutputStream();
+
+ os.write(request.toString().getBytes());
+ os.flush();
+ client.shutdownOutput();
+ String response = readResponse(client);
+ client.close();
+
+// assertThat("response contains 200 OK", response.contains(" 500 "), is(true)); //TODO: check with gregw,
+// currently returns 200
+ assertThat("The 4th byte (-1) has not been passed to the handler", fourBytesRead.get(), is(false));
+ assertThat("EofException has been caught", earlyEOFException.get(), is(true));
+ }
/*
* Feed the server the entire request at once.
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ssl/SelectChannelServerSslTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ssl/SelectChannelServerSslTest.java
index 840219f..096ecca 100644
--- a/jetty-server/src/test/java/org/eclipse/jetty/server/ssl/SelectChannelServerSslTest.java
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ssl/SelectChannelServerSslTest.java
@@ -17,8 +17,6 @@
//
package org.eclipse.jetty.server.ssl;
-import static org.junit.Assert.assertEquals;
-
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
@@ -26,13 +24,11 @@ import java.net.Socket;
import java.security.KeyStore;
import java.util.Arrays;
import java.util.concurrent.atomic.AtomicInteger;
-
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.TrustManagerFactory;
-
import org.eclipse.jetty.io.AsyncEndPoint;
import org.eclipse.jetty.io.Connection;
import org.eclipse.jetty.io.nio.SslConnection;
@@ -41,8 +37,10 @@ import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Test;
-import static org.junit.Assert.assertThat;
+
import static org.hamcrest.Matchers.lessThan;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
/**
* HttpServer Tester.
@@ -167,6 +165,12 @@ public class SelectChannelServerSslTest extends HttpServerTestBase
}
@Override
+ @Test
+ @Ignore("Override and ignore this test as SSLSocket.shutdownOutput() is not supported, " +
+ "but shutdownOutput() is needed by the test.")
+ public void testInterruptedRequest(){}
+
+ @Override
@Ignore
public void testAvailable() throws Exception
{
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ssl/SslSocketServerTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ssl/SslSocketServerTest.java
index 4da4106..0c53417 100644
--- a/jetty-server/src/test/java/org/eclipse/jetty/server/ssl/SslSocketServerTest.java
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ssl/SslSocketServerTest.java
@@ -77,6 +77,12 @@ public class SslSocketServerTest extends HttpServerTestBase
@Override
@Test
+ @Ignore("Override and ignore this test as SSLSocket.shutdownOutput() is not supported, " +
+ "but shutdownOutput() is needed by the test.")
+ public void testInterruptedRequest(){}
+
+ @Override
+ @Test
public void testFlush() throws Exception
{
// TODO this test uses URL, so noop for now
diff --git a/jetty-server/src/test/resources/jetty-logging.properties b/jetty-server/src/test/resources/jetty-logging.properties
new file mode 100644
index 0000000..d8439d1
--- /dev/null
+++ b/jetty-server/src/test/resources/jetty-logging.properties
@@ -0,0 +1,3 @@
+# Setup default logging implementation for during testing
+org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
+org.eclipse.jetty.server.LEVEL=INFO