From df989b31414bd777881534c79779a4e32881dc9c Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Mon, 14 Sep 2009 04:52:16 +0000 Subject: [PATCH] JETTY-1108 SSL EOF detection git-svn-id: svn+ssh://dev.eclipse.org/svnroot/rt/org.eclipse.jetty/jetty/trunk@889 7e9141cc-0065-0410-87d8-b60c137991c4 --- VERSION.txt | 1 + .../http/ssl/SslSelectChannelEndPoint.java | 28 ++++-- .../jetty/server/AsyncContinuation.java | 2 + .../eclipse/jetty/server/HttpConnection.java | 5 +- .../jetty/server/ssl/SslUploadTest.java | 85 +++++++++++-------- 5 files changed, 77 insertions(+), 44 deletions(-) diff --git a/VERSION.txt b/VERSION.txt index 0efa0f820b1..a21805b63ed 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -17,6 +17,7 @@ jetty-7.0.0.RC6-SNAPSHOT + JETTY-1098 Default form encoding is UTF8 + JETTY-1101 Updated servlet3 continuation constructor + JETTY-1105 Custom error pages aren't working + + JETTY-1108 SSL EOF detection + 288514 AbstractConnector does not handle InterruptedExceptions on shutdown + 288466 LocalConnector is not thread safe + 288772 Failure to connect does not set status to EXCEPTED diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/ssl/SslSelectChannelEndPoint.java b/jetty-http/src/main/java/org/eclipse/jetty/http/ssl/SslSelectChannelEndPoint.java index 8495bab8df0..a8cfc03c047 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/ssl/SslSelectChannelEndPoint.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/ssl/SslSelectChannelEndPoint.java @@ -27,6 +27,7 @@ import javax.net.ssl.SSLEngineResult.HandshakeStatus; import org.eclipse.jetty.http.Parser; import org.eclipse.jetty.io.Buffer; import org.eclipse.jetty.io.Buffers; +import org.eclipse.jetty.io.EofException; import org.eclipse.jetty.io.nio.NIOBuffer; import org.eclipse.jetty.io.nio.SelectChannelEndPoint; import org.eclipse.jetty.io.nio.SelectorManager; @@ -586,21 +587,22 @@ public class SslSelectChannelEndPoint extends SelectChannelEndPoint catch(IOException e) { if (_inNIOBuffer.length()==0) + { + _outNIOBuffer.clear(); throw e; + } break; } } - // If we have no data - if (_inNIOBuffer.length()==0) + // If we have no progress and no data + if (total_filled==0 && _inNIOBuffer.length()==0) { - // Check for EOF - // TODO - the EOF is delayed so that unwrappable data in the - // buffer is processed before the EoF. But what if there is - // insufficient data in the buffer to do an unwrap? Will EoF - // be totally ignored, or will it be thrown elsewhere???? if(!isOpen()) - throw new org.eclipse.jetty.io.EofException(); + { + _outNIOBuffer.clear(); + throw new EofException(); + } return false; } @@ -634,9 +636,17 @@ public class SslSelectChannelEndPoint extends SelectChannelEndPoint throw new IllegalStateException(_result.toString()); case BUFFER_UNDERFLOW: - // Not enough data, so return and it will be tried again + // Not enough data, + // If we are closed, we will never get more, so EOF + // else return and we will be tried again // later when more data arriving causes another dispatch. if (Log.isDebugEnabled()) Log.debug("unwrap {}",_result); + if(!isOpen()) + { + _inNIOBuffer.clear(); + _outNIOBuffer.clear(); + throw new EofException(); + } return (total_filled > 0); case CLOSED: diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncContinuation.java b/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncContinuation.java index 715ba9fd138..4fe41e275a5 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncContinuation.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncContinuation.java @@ -712,6 +712,8 @@ public class AsyncContinuation implements AsyncContext, Continuation { case __IDLE: case __DISPATCHED: + case __UNCOMPLETED: + case __COMPLETED: return false; default: diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java index 99d967d28a7..d331e5dba5c 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java @@ -375,6 +375,9 @@ public class HttpConnection implements Connection { if (_request._async.isAsync()) { + // TODO - handle the case of input being read for a + // suspended request. + Log.debug("async request",_request); if (!_request._async.isComplete()) handleRequest(); @@ -419,8 +422,8 @@ public class HttpConnection implements Connection if (!progress) return; - progress=false; } + progress=false; } catch (HttpException e) { diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ssl/SslUploadTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ssl/SslUploadTest.java index 5c2a7f967f8..14c565f476b 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/ssl/SslUploadTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ssl/SslUploadTest.java @@ -28,6 +28,7 @@ import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLSocket; import javax.net.ssl.TrustManagerFactory; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; @@ -37,19 +38,22 @@ import junit.framework.TestCase; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.handler.AbstractHandler; +import org.eclipse.jetty.util.IO; /** * @version $Revision$ $Date$ */ public class SslUploadTest extends TestCase { + int _total; + public void test() throws Exception { Server server = new Server(); SslConnector connector = new SslSelectChannelConnector(); server.addConnector(connector); - String keystorePath = System.getProperty("basedir") + "/src/test/resources/keystore"; + String keystorePath = System.getProperty("basedir",".") + "/src/test/resources/keystore"; connector.setKeystore(keystorePath); connector.setPassword("storepwd"); connector.setKeyPassword("keypwd"); @@ -68,28 +72,11 @@ public class SslUploadTest extends TestCase SSLContext sslContext = SSLContext.getInstance("SSL"); sslContext.init(null, trustManagerFactory.getTrustManagers(), null); - URL url = new URL("https://localhost:" + connector.getLocalPort() + "/"); - final HttpsURLConnection connection = (HttpsURLConnection)url.openConnection(); - connection.setSSLSocketFactory(sslContext.getSocketFactory()); - connection.setHostnameVerifier(new EmptyHostnameVerifier()); - connection.setDoInput(true); - connection.setDoOutput(true); - connection.setRequestMethod("POST"); - connection.setUseCaches(false); - connection.connect(); + _total=0; + final SSLSocket socket = (SSLSocket)sslContext.getSocketFactory().createSocket("localhost",connector.getLocalPort()); - // 64 MiB -// byte[] requestContent = new byte[67108864]; - // 16 MiB - byte[] requestContent = new byte[16777216]; - Arrays.fill(requestContent, (byte)120); - - OutputStream output = connection.getOutputStream(); - output.write(requestContent); - output.flush(); - -/* // Simulate async close + /* new Thread() { @Override @@ -97,8 +84,12 @@ public class SslUploadTest extends TestCase { try { - sleep(200); - connection.disconnect(); + sleep(100); + socket.close(); + } + catch (IOException x) + { + x.printStackTrace(); } catch (InterruptedException x) { @@ -106,19 +97,33 @@ public class SslUploadTest extends TestCase } } }.start(); -*/ + */ + + long start = System.nanoTime(); - InputStream input = connection.getInputStream(); + OutputStream out = socket.getOutputStream(); + out.write("POST / HTTP/1.1\r\n".getBytes()); + out.write("Host: localhost\r\n".getBytes()); + out.write("Content-Length: 16777216\r\n".getBytes()); + out.write("Content-Type: bytes\r\n".getBytes()); + out.write("Connection: close\r\n".getBytes()); + out.write("\r\n".getBytes()); + out.flush(); + + byte[] requestContent = new byte[16777216]; + Arrays.fill(requestContent, (byte)120); + out.write(requestContent); + out.flush(); + + InputStream in = socket.getInputStream(); + String response = IO.toString(in); + // System.err.println(response); + long end = System.nanoTime(); System.out.println("upload time: " + TimeUnit.NANOSECONDS.toMillis(end - start)); - - BufferedReader reader = new BufferedReader(new InputStreamReader(input, "UTF-8")); - String line; - while ((line = reader.readLine()) != null) - System.err.println(line); - - connection.disconnect(); + assertEquals(requestContent.length,_total); + } finally { @@ -126,12 +131,24 @@ public class SslUploadTest extends TestCase } } - private static class EmptyHandler extends AbstractHandler + private class EmptyHandler extends AbstractHandler { public void handle(String path, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws IOException, ServletException { - System.out.println("path = " + path); + // System.out.println("path = " + path); request.setHandled(true); + + InputStream in = request.getInputStream(); + byte[] b = new byte[4096*4]; + int l; + + while((l=in.read(b))>=0) + { + // System.out.println("Read "+l); + _total+=l; + } + System.err.println("Read "+_total); + } }