387919: throw EOFException on early eof from client on http requests

This commit is contained in:
Thomas Becker 2012-08-23 19:36:49 +02:00
parent 2bd6cf2ebf
commit 9173751438
6 changed files with 111 additions and 21 deletions

View File

@ -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()
@ -394,6 +395,12 @@ public abstract class AbstractHttpConnection extends AbstractConnection
return _generator.isCommitted();
}
/* ------------------------------------------------------------ */
public boolean isEarlyEOF()
{
return _earlyEOF;
}
/* ------------------------------------------------------------ */
public void reset()
{
@ -407,6 +414,7 @@ public abstract class AbstractHttpConnection extends AbstractConnection
_response.recycle();
_uri.clear();
_writer=null;
_earlyEOF = false;
}
/* ------------------------------------------------------------ */
@ -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)
@ -927,6 +940,12 @@ public abstract class AbstractHttpConnection extends AbstractConnection
}
}
/* ------------------------------------------------------------ */
public void earlyEOF()
{
_earlyEOF = true;
}
/* ------------------------------------------------------------ */
/* ------------------------------------------------------------ */
/* ------------------------------------------------------------ */
@ -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();
}
}
/* ------------------------------------------------------------ */

View File

@ -24,6 +24,7 @@ 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
{
@ -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();
}
}

View File

@ -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;
/**
*
@ -149,7 +151,54 @@ public abstract class HttpServerTestBase extends HttpServerTestFixture
}
}
@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.

View File

@ -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.
@ -166,6 +164,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

View File

@ -75,6 +75,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

View File

@ -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