From 223a4d8b3b54c2a5600d90e7eb4322495f437760 Mon Sep 17 00:00:00 2001 From: Joakim Erdfelt Date: Thu, 9 May 2013 14:50:40 -0700 Subject: [PATCH 1/6] 407325 - Test Failure: org.eclipse.jetty.servlets.EventSourceServletTest.testEncoding + Setting charset that test uses to avoid using default charset encoding. --- .../java/org/eclipse/jetty/servlets/EventSourceServletTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/EventSourceServletTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/EventSourceServletTest.java index ed75ec4414e..6f2d6ab7153 100644 --- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/EventSourceServletTest.java +++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/EventSourceServletTest.java @@ -334,7 +334,7 @@ public class EventSourceServletTest { // Read and discard the HTTP response InputStream input = socket.getInputStream(); - BufferedReader reader = new BufferedReader(new InputStreamReader(input)); + BufferedReader reader = new BufferedReader(new InputStreamReader(input, "UTF-8")); String line = reader.readLine(); while (line != null) { From bec2fc576d301919fe87f5f129374e6d48124f7f Mon Sep 17 00:00:00 2001 From: Jan Bartel Date: Fri, 10 May 2013 14:51:18 +1000 Subject: [PATCH 2/6] Remove unneeded commented out code. --- jetty-plus/src/main/config/etc/jetty-plus.xml | 85 +------------------ 1 file changed, 1 insertion(+), 84 deletions(-) diff --git a/jetty-plus/src/main/config/etc/jetty-plus.xml b/jetty-plus/src/main/config/etc/jetty-plus.xml index 4a5c3b41458..bfbcce50534 100644 --- a/jetty-plus/src/main/config/etc/jetty-plus.xml +++ b/jetty-plus/src/main/config/etc/jetty-plus.xml @@ -2,93 +2,10 @@ - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From ccc7a71c74827ecf95a1ec76e9c326dbb34c764f Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Fri, 10 May 2013 09:02:52 +1000 Subject: [PATCH 3/6] 398467 Non Blocking IO Working towards 3.1 by exposing more of the underlying async IO operations. --- .../org/eclipse/jetty/server/HttpChannel.java | 35 ++- .../eclipse/jetty/server/HttpConnection.java | 286 ++++++++++-------- .../org/eclipse/jetty/server/Response.java | 2 +- .../jetty/server/HttpConnectionTest.java | 10 +- 4 files changed, 184 insertions(+), 149 deletions(-) diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java index 278601da3c6..d1e5b501670 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java @@ -198,7 +198,7 @@ public class HttpChannel implements HttpParser.RequestHandler, Runnable throw new IOException("Committed before 100 Continues"); // TODO: break this dependency with HttpGenerator - boolean committed = commitResponse(HttpGenerator.CONTINUE_100_INFO, null, false); + boolean committed = sendResponse(HttpGenerator.CONTINUE_100_INFO, null, false); if (!committed) throw new IOException("Concurrent commit while trying to send 100-Continue"); } @@ -356,7 +356,7 @@ public class HttpChannel implements HttpParser.RequestHandler, Runnable { HttpFields fields = new HttpFields(); ResponseInfo info = new ResponseInfo(_request.getHttpVersion(), fields, 0, HttpStatus.INTERNAL_SERVER_ERROR_500, null, _request.isHead()); - boolean committed = commitResponse(info, null, true); + boolean committed = sendResponse(info, null, true); if (!committed) LOG.warn("Could not send response error 500: "+x); } @@ -584,7 +584,7 @@ public class HttpChannel implements HttpParser.RequestHandler, Runnable { if (_state.handling()==Next.CONTINUE) { - commitResponse(new ResponseInfo(HttpVersion.HTTP_1_1,new HttpFields(),0,status,reason,false),null,true); + sendResponse(new ResponseInfo(HttpVersion.HTTP_1_1,new HttpFields(),0,status,reason,false),null,true); } } catch (IOException e) @@ -598,11 +598,15 @@ public class HttpChannel implements HttpParser.RequestHandler, Runnable } } - protected boolean commitResponse(ResponseInfo info, ByteBuffer content, boolean complete) throws IOException + protected boolean sendResponse(ResponseInfo info, ByteBuffer content, boolean complete) throws IOException { - boolean committed = _committed.compareAndSet(false, true); - if (committed) + boolean committing = _committed.compareAndSet(false, true); + if (committing) { + // We need an info to commit + if (info==null) + info = _response.newResponseInfo(); + try { // Try to commit with the passed info @@ -637,7 +641,12 @@ public class HttpChannel implements HttpParser.RequestHandler, Runnable _response.getHttpOutput().closed(); } } - return committed; + else if (info==null) + { + // This is a normal write + _transport.send(null, content, complete); + } + return committing; } protected boolean isCommitted() @@ -655,17 +664,7 @@ public class HttpChannel implements HttpParser.RequestHandler, Runnable */ protected void write(ByteBuffer content, boolean complete) throws IOException { - if (isCommitted()) - { - _transport.send(null, content, complete); - } - else - { - ResponseInfo info = _response.newResponseInfo(); - boolean committed = commitResponse(info, content, complete); - if (!committed) - throw new IOException("Concurrent commit"); - } + sendResponse(null, content, complete); } protected void execute(Runnable task) 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 7029fd40b41..ab5708ddc82 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 @@ -51,7 +51,7 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http { public static final String UPGRADE_CONNECTION_ATTRIBUTE = "org.eclipse.jetty.server.HttpConnection.UPGRADE"; private static final boolean REQUEST_BUFFER_DIRECT=false; - private static final boolean HEADER_BUFFER_DIRECT=true; + private static final boolean HEADER_BUFFER_DIRECT=false; private static final boolean CHUNK_BUFFER_DIRECT=false; private static final Logger LOG = Log.getLogger(HttpConnection.class); private static final ThreadLocal __currentConnection = new ThreadLocal<>(); @@ -307,149 +307,46 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http @Override public void send(HttpGenerator.ResponseInfo info, ByteBuffer content, boolean lastContent) throws IOException - { - // If we are still expecting a 100 continues - if (_channel.isExpecting100Continue()) - // then we can't be persistent - _generator.setPersistent(false); - - - ByteBuffer header = null; - ByteBuffer chunk = null; - out: while (true) - { - HttpGenerator.Result result = _generator.generateResponse(info, header, chunk, content, lastContent); - if (LOG.isDebugEnabled()) - LOG.debug("{} generate: {} ({},{},{})@{}", - this, - result, - BufferUtil.toSummaryString(header), - BufferUtil.toSummaryString(content), - lastContent, - _generator.getState()); - - switch (result) - { - case NEED_HEADER: - { - if (lastContent && content!=null && BufferUtil.space(content)>_config.getResponseHeaderSize() && content.hasArray() ) - { - // use spare space in content buffer for header buffer - int p=content.position(); - int l=content.limit(); - content.position(l); - content.limit(l+_config.getResponseHeaderSize()); - header=content.slice(); - header.limit(0); - content.position(p); - content.limit(l); - } - else - header = _bufferPool.acquire(_config.getResponseHeaderSize(), HEADER_BUFFER_DIRECT); - continue; - } - case NEED_CHUNK: - { - chunk = _chunk; - if (chunk==null) - chunk = _chunk = _bufferPool.acquire(HttpGenerator.CHUNK_SIZE, CHUNK_BUFFER_DIRECT); - continue; - } - case FLUSH: - { - // Don't write the chunk or the content if this is a HEAD response - if (_channel.getRequest().isHead()) - { - BufferUtil.clear(chunk); - BufferUtil.clear(content); - } - - // If we have a header - if (BufferUtil.hasContent(header)) - { - // we know there will not be a chunk, so write either header+content or just the header - if (BufferUtil.hasContent(content)) - blockingWrite(header, content); - else - blockingWrite(header); - - } - else if (BufferUtil.hasContent(chunk)) - { - if (BufferUtil.hasContent(content)) - blockingWrite(chunk,content); - else - blockingWrite(chunk); - } - else if (BufferUtil.hasContent(content)) - { - blockingWrite(content); - } - continue; - } - case SHUTDOWN_OUT: - { - getEndPoint().shutdownOutput(); - continue; - } - case DONE: - { - if (header!=null) - { - // don't release header in spare content buffer - if (!lastContent || content==null || !content.hasArray() || !header.hasArray() || content.array()!=header.array()) - _bufferPool.release(header); - } - if (chunk!=null) - _bufferPool.release(chunk); - break out; - } - case CONTINUE: - { - break; - } - default: - { - throw new IllegalStateException("generateResponse="+result); - } - } - } - } - - @Override - public void send(ResponseInfo info, ByteBuffer content, boolean lastContent, Callback callback) { try { - send(info,content,lastContent); - callback.succeeded(); - } - catch (IOException e) - { - callback.failed(e); - } - } + // If we are still expecting a 100 continues + if (info !=null && _channel.isExpecting100Continue()) + // then we can't be persistent + _generator.setPersistent(false); + + Sender sender = new Sender(content,lastContent,_writeBlocker); + sender.process(info); - private void blockingWrite(ByteBuffer... bytes) throws IOException - { - try - { - getEndPoint().write(_writeBlocker, bytes); _writeBlocker.block(); } catch (InterruptedException x) { + x.printStackTrace(); throw (IOException)new InterruptedIOException().initCause(x); } catch (TimeoutException e) { + e.printStackTrace(); throw new IOException(e); } catch (ClosedChannelException e) { + e.printStackTrace(); throw new EofException(e); } } + + @Override + public void send(ResponseInfo info, ByteBuffer content, boolean lastContent, Callback callback) + { + // If we are still expecting a 100 continues + if (info !=null && _channel.isExpecting100Continue()) + // then we can't be persistent + _generator.setPersistent(false); + + new Sender(content,lastContent,callback).process(info); + } @Override public void completed() @@ -692,5 +589,144 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http } + private class Sender implements Callback + { + final ByteBuffer _content; + final boolean _lastContent; + final Callback _callback; + + Sender(ByteBuffer content, boolean last, Callback callback) + { + _callback=callback; + _content=content; + _lastContent=last; + } + + public void process(ResponseInfo info) + { + try + { + ByteBuffer header = null; + ByteBuffer chunk = null; + while (true) + { + HttpGenerator.Result result = _generator.generateResponse(info, header, chunk, _content, _lastContent); + if (LOG.isDebugEnabled()) + LOG.debug("{} generate: {} ({},{},{})@{}", + this, + result, + BufferUtil.toSummaryString(header), + BufferUtil.toSummaryString(_content), + _lastContent, + _generator.getState()); + + switch (result) + { + case NEED_HEADER: + { + if (_lastContent && _content!=null && BufferUtil.space(_content)>_config.getResponseHeaderSize() && _content.hasArray() ) + { + // use spare space in content buffer for header buffer + int p=_content.position(); + int l=_content.limit(); + _content.position(l); + _content.limit(l+_config.getResponseHeaderSize()); + header=_content.slice(); + header.limit(0); + _content.position(p); + _content.limit(l); + } + else + header = _bufferPool.acquire(_config.getResponseHeaderSize(), HEADER_BUFFER_DIRECT); + continue; + } + case NEED_CHUNK: + { + chunk = _chunk; + if (chunk==null) + chunk = _chunk = _bufferPool.acquire(HttpGenerator.CHUNK_SIZE, CHUNK_BUFFER_DIRECT); + continue; + } + case FLUSH: + { + // Don't write the chunk or the content if this is a HEAD response + if (_channel.getRequest().isHead()) + { + BufferUtil.clear(chunk); + BufferUtil.clear(_content); + } + + // If we have a header + if (BufferUtil.hasContent(header)) + { + // we know there will not be a chunk, so write either header+content or just the header + if (BufferUtil.hasContent(_content)) + getEndPoint().write(this, header, _content); + else + getEndPoint().write(this, header); + } + else if (BufferUtil.hasContent(chunk)) + { + if (BufferUtil.hasContent(_content)) + getEndPoint().write(this, chunk, _content); + else + getEndPoint().write(this, chunk); + } + else if (BufferUtil.hasContent(_content)) + { + getEndPoint().write(this, _content); + } + else + continue; + return; + } + case SHUTDOWN_OUT: + { + getEndPoint().shutdownOutput(); + continue; + } + case DONE: + { + if (header!=null) + { + // don't release header in spare content buffer + if (!_lastContent || _content==null || !_content.hasArray() || !header.hasArray() || _content.array()!=header.array()) + _bufferPool.release(header); + } + if (chunk!=null) + _bufferPool.release(chunk); + _callback.succeeded(); + return; + } + case CONTINUE: + { + break; + } + default: + { + throw new IllegalStateException("generateResponse="+result); + } + } + } + } + catch(Exception e) + { + _callback.failed(e); + } + } + + @Override + public void succeeded() + { + process(null); + } + + @Override + public void failed(Throwable x) + { + _callback.failed(x); + } + + } } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java index d18366acec1..0ddd3270e22 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java @@ -425,7 +425,7 @@ public class Response implements HttpServletResponse { if (_channel.isExpecting102Processing() && !isCommitted()) { - _channel.commitResponse(HttpGenerator.PROGRESS_102_INFO, null, true); + _channel.sendResponse(HttpGenerator.PROGRESS_102_INFO, null, true); } } diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpConnectionTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpConnectionTest.java index d0c8d3f2b3b..5869d352ebd 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpConnectionTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpConnectionTest.java @@ -158,15 +158,15 @@ public class HttpConnectionTest @Test public void testHead() throws Exception { - String responseHEAD=connector.getResponses("HEAD /R1 HTTP/1.1\015\012"+ - "Host: localhost\015\012"+ - "Connection: close\015\012"+ - "\015\012"); - String responsePOST=connector.getResponses("POST /R1 HTTP/1.1\015\012"+ "Host: localhost\015\012"+ "Connection: close\015\012"+ "\015\012"); + + String responseHEAD=connector.getResponses("HEAD /R1 HTTP/1.1\015\012"+ + "Host: localhost\015\012"+ + "Connection: close\015\012"+ + "\015\012"); assertThat(responsePOST,startsWith(responseHEAD.substring(0,responseHEAD.length()-2))); assertThat(responsePOST.length(),greaterThan(responseHEAD.length())); From affc41ddf53b787b188d7e07a2c418c79123e1ce Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Fri, 10 May 2013 19:47:01 +1000 Subject: [PATCH 4/6] fixed comment --- jetty-distribution/src/main/resources/start.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jetty-distribution/src/main/resources/start.ini b/jetty-distribution/src/main/resources/start.ini index fdd010282f0..3d7646db818 100644 --- a/jetty-distribution/src/main/resources/start.ini +++ b/jetty-distribution/src/main/resources/start.ini @@ -152,7 +152,7 @@ etc/jetty-http.xml #=========================================================== # HTTPS Connector -# Must be used with 200-ssl.ini +# Must be used with jetty-ssl.xml #----------------------------------------------------------- # jetty.https.port=8443 # etc/jetty-https.xml From fe582e544a7b5351904bf3e8f6dbe275d2fb5619 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Fri, 10 May 2013 20:11:19 +1000 Subject: [PATCH 5/6] 398467 Non Blocking IO Working towards 3.1 by exposing more of the underlying async IO operations. added async support to write in HttpChannel --- .../org/eclipse/jetty/server/HttpChannel.java | 112 ++++++++++++------ .../eclipse/jetty/server/ResponseTest.java | 1 + 2 files changed, 77 insertions(+), 36 deletions(-) diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java index d1e5b501670..bc9d29590bc 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java @@ -21,6 +21,7 @@ package org.eclipse.jetty.server; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; +import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; @@ -45,7 +46,8 @@ import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.io.EofException; import org.eclipse.jetty.server.HttpChannelState.Next; import org.eclipse.jetty.server.handler.ErrorHandler; -import org.eclipse.jetty.util.BufferUtil; +import org.eclipse.jetty.util.BlockingCallback; +import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.URIUtil; import org.eclipse.jetty.util.log.Log; @@ -88,7 +90,8 @@ public class HttpChannel implements HttpParser.RequestHandler, Runnable private final HttpURI _uri; private final HttpChannelState _state; private final Request _request; - private final Response _response; + private final Response _response; + private final BlockingCallback _writeblock=new BlockingCallback(); private HttpVersion _version = HttpVersion.HTTP_1_1; private boolean _expect = false; private boolean _expect100Continue = false; @@ -500,6 +503,7 @@ public class HttpChannel implements HttpParser.RequestHandler, Runnable if (charset != null) _request.setCharacterEncodingUnchecked(charset); break; + default: } } @@ -597,55 +601,91 @@ public class HttpChannel implements HttpParser.RequestHandler, Runnable _state.completed(); } } - - protected boolean sendResponse(ResponseInfo info, ByteBuffer content, boolean complete) throws IOException + + protected boolean sendResponse(ResponseInfo info, ByteBuffer content, boolean complete, final Callback callback) { boolean committing = _committed.compareAndSet(false, true); if (committing) { // We need an info to commit if (info==null) + { info = _response.newResponseInfo(); + } - try + final int status=info.getStatus(); + final Callback committed = new Callback() { - // Try to commit with the passed info - _transport.send(info, content, complete); + @Override + public void succeeded() + { + // If we are committing a 1xx response, we need to reset the commit + // status so that the "real" response can be committed again. + if (status<200 && status>=100) + _committed.set(false); + callback.succeeded(); + } - // If we are committing a 1xx response, we need to reset the commit - // status so that the "real" response can be committed again. - if (info.getStatus() < 200) - _committed.set(false); - } - catch (EofException e) - { - LOG.debug(e); - // TODO is it worthwhile sending if we are at EoF? - // "application" info failed to commit, commit with a failsafe 500 info - _transport.send(HttpGenerator.RESPONSE_500_INFO,null,true); - complete=true; - throw e; - } - catch (Exception e) - { - LOG.warn(e); - // "application" info failed to commit, commit with a failsafe 500 info - _transport.send(HttpGenerator.RESPONSE_500_INFO,null,true); - complete=true; - throw e; - } - finally - { - // TODO this indicates the relationship with HttpOutput is not exactly correct - if (complete) - _response.getHttpOutput().closed(); - } + @Override + public void failed(final Throwable x) + { + if (x instanceof EofException) + { + LOG.debug(x); + _response.getHttpOutput().closed(); + callback.failed(x); + } + else + { + LOG.warn(x); + _transport.send(HttpGenerator.RESPONSE_500_INFO,null,true,new Callback() + { + @Override + public void succeeded() + { + _response.getHttpOutput().closed(); + callback.failed(x); + } + + @Override + public void failed(Throwable th) + { + LOG.ignore(th); + _response.getHttpOutput().closed(); + callback.failed(x); + } + }); + } + } + }; + + _transport.send(info, content, complete, committed); } else if (info==null) { // This is a normal write - _transport.send(null, content, complete); + _transport.send(null, content, complete, callback); } + else + { + callback.failed(new IllegalStateException("committed")); + } + return committing; + } + + protected boolean sendResponse(ResponseInfo info, ByteBuffer content, boolean complete) throws IOException + { + boolean committing=sendResponse(info,content,complete,_writeblock); + + try + { + _writeblock.block(); + } + catch (InterruptedException | TimeoutException e) + { + throw new IOException(e); + } + return committing; } diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java index b4d00a19244..21f7427590c 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java @@ -89,6 +89,7 @@ public class ResponseTest @Override public void send(ResponseInfo info, ByteBuffer content, boolean lastContent, Callback callback) { + callback.succeeded(); } @Override From 34b28503e6f0e03970ea2a15745be6a69c1c596a Mon Sep 17 00:00:00 2001 From: Joakim Erdfelt Date: Sat, 11 May 2013 07:16:34 -0700 Subject: [PATCH 6/6] Removing rogue src file from jetty 7/8 merge --- .../websocket/WebSocketMinVersionTest.java | 116 ------------------ 1 file changed, 116 deletions(-) delete mode 100644 jetty-websocket/src/test/java/org/eclipse/jetty/websocket/WebSocketMinVersionTest.java diff --git a/jetty-websocket/src/test/java/org/eclipse/jetty/websocket/WebSocketMinVersionTest.java b/jetty-websocket/src/test/java/org/eclipse/jetty/websocket/WebSocketMinVersionTest.java deleted file mode 100644 index 141231d63e3..00000000000 --- a/jetty-websocket/src/test/java/org/eclipse/jetty/websocket/WebSocketMinVersionTest.java +++ /dev/null @@ -1,116 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2013 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.websocket; - -import static org.hamcrest.Matchers.*; - -import java.net.URI; -import java.util.concurrent.TimeUnit; - -import org.eclipse.jetty.server.Connector; -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.servlet.ServletContextHandler; -import org.eclipse.jetty.servlet.ServletHolder; -import org.eclipse.jetty.websocket.helper.CaptureSocket; -import org.eclipse.jetty.websocket.helper.SafariD00; -import org.eclipse.jetty.websocket.helper.WebSocketCaptureServlet; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; - -public class WebSocketMinVersionTest -{ - private Server server; - private WebSocketCaptureServlet servlet; - private URI serverUri; - - @BeforeClass - public static void initLogging() - { - // Configure Logging - // System.setProperty("org.eclipse.jetty.util.log.class",StdErrLog.class.getName()); - System.setProperty("org.eclipse.jetty.websocket.helper.LEVEL","DEBUG"); - } - - @Before - public void startServer() throws Exception - { - // Configure Server - server = new Server(0); - - ServletContextHandler context = new ServletContextHandler(); - context.setContextPath("/"); - server.setHandler(context); - - // Serve capture servlet - servlet = new WebSocketCaptureServlet(); - ServletHolder holder = new ServletHolder(servlet); - holder.setInitParameter("minVersion","8"); - context.addServlet(holder,"/"); - - // Start Server - server.start(); - - Connector conn = server.getConnectors()[0]; - String host = conn.getHost(); - if (host == null) - { - host = "localhost"; - } - int port = conn.getLocalPort(); - serverUri = new URI(String.format("ws://%s:%d/",host,port)); - // System.out.printf("Server URI: %s%n",serverUri); - } - - @Test - public void testAttemptUpgrade() throws Exception - { - SafariD00 safari = new SafariD00(serverUri); - - try - { - safari.connect(); - safari.issueHandshake(); - Assert.fail("Expected upgrade failure"); - } - catch(IllegalStateException e) { - String respHeader = e.getMessage(); - Assert.assertThat("Response Header", respHeader, containsString("HTTP/1.1 400 Unsupported websocket version specification")); - } - finally - { - // System.out.println("Closing client socket"); - safari.disconnect(); - } - } - - public static void threadSleep(int dur, TimeUnit unit) throws InterruptedException - { - long ms = TimeUnit.MILLISECONDS.convert(dur,unit); - Thread.sleep(ms); - } - - @After - public void stopServer() throws Exception - { - server.stop(); - } -}