Merge remote-tracking branch 'origin/master' into bug-359329

This commit is contained in:
Jan Bartel 2011-12-19 15:01:29 +11:00
commit 397aa79a50
28 changed files with 872 additions and 439 deletions

View File

@ -355,9 +355,8 @@ public abstract class AbstractHttpConnection extends AbstractConnection implemen
@Override
public String toString()
{
return String.format("%s@%x//%s,g=%s,p=%s",
getClass().getSimpleName(),
hashCode(),
return String.format("%s %s g=%s p=%s",
super.toString(),
_destination == null ? "?.?.?.?:??" : _destination.getAddress(),
_generator,
_parser);

View File

@ -1,7 +1,6 @@
package org.eclipse.jetty.client;
import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.Matchers.lessThan;
import static org.hamcrest.Matchers.*;
import java.io.BufferedReader;
import java.io.File;
@ -100,6 +99,7 @@ public class SslBytesServerTest extends SslBytesTest
};
}
};
connector.setMaxIdleTime(2000);
// connector.setPort(5870);
connector.setPort(0);
@ -1181,6 +1181,54 @@ public class SslBytesServerTest extends SslBytesTest
closeClient(client);
}
@Ignore
@Test
public void testServerCloseClientDoesNotClose() throws Exception
{
final SSLSocket client = newClient();
final OutputStream clientOutput = client.getOutputStream();
SimpleProxy.AutomaticFlow automaticProxyFlow = proxy.startAutomaticFlow();
client.startHandshake();
Assert.assertTrue(automaticProxyFlow.stop(5, TimeUnit.SECONDS));
byte[] data = new byte[3 * 1024];
Arrays.fill(data, (byte)'Y');
String content = new String(data, "UTF-8");
automaticProxyFlow = proxy.startAutomaticFlow();
clientOutput.write(("" +
"POST / HTTP/1.1\r\n" +
"Host: localhost\r\n" +
"Content-Type: text/plain\r\n" +
"Content-Length: " + content.length() + "\r\n" +
"Connection: close\r\n" +
"\r\n" +
content).getBytes("UTF-8"));
clientOutput.flush();
Assert.assertTrue(automaticProxyFlow.stop(5, TimeUnit.SECONDS));
BufferedReader reader = new BufferedReader(new InputStreamReader(client.getInputStream(), "UTF-8"));
String line = reader.readLine();
Assert.assertNotNull(line);
Assert.assertTrue(line.startsWith("HTTP/1.1 200 "));
while ((line = reader.readLine()) != null)
{
if (line.trim().length() == 0)
break;
}
// Check that we did not spin
Assert.assertThat(sslHandles.get(), lessThan(20));
Assert.assertThat(httpParses.get(), lessThan(50));
// TODO: instead of sleeping, we should expect the connection being closed by the idle timeout
// TODO: mechanism; unfortunately this now is not working, and this test fails because the idle
// TODO: timeout will not trigger.
TimeUnit.SECONDS.sleep(100);
closeClient(client);
}
private void assumeJavaVersionSupportsTLSRenegotiations()
{
// Due to a security bug, TLS renegotiations were disabled in JDK 1.6.0_19-21

View File

@ -0,0 +1,212 @@
package org.eclipse.jetty.client;
import static org.hamcrest.Matchers.*;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;
import java.nio.channels.SocketChannel;
import java.util.Arrays;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.http.HttpParser;
import org.eclipse.jetty.io.AsyncEndPoint;
import org.eclipse.jetty.io.Buffers;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.io.nio.AsyncConnection;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.AbstractHandler;
import org.eclipse.jetty.server.nio.SelectChannelConnector;
import org.eclipse.jetty.toolchain.test.IO;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
public class TimeoutTest
{
private static final Logger logger = Log.getLogger(TimeoutTest.class);
private final AtomicInteger httpParses = new AtomicInteger();
private ExecutorService threadPool;
private Server server;
private int serverPort;
@Before
public void init() throws Exception
{
threadPool = Executors.newCachedThreadPool();
server = new Server();
SelectChannelConnector connector = new SelectChannelConnector()
{
@Override
protected AsyncConnection newConnection(SocketChannel channel, final AsyncEndPoint endPoint)
{
return new org.eclipse.jetty.server.AsyncHttpConnection(this,endPoint,getServer())
{
@Override
protected HttpParser newHttpParser(Buffers requestBuffers, EndPoint endPoint, HttpParser.EventHandler requestHandler)
{
return new HttpParser(requestBuffers,endPoint,requestHandler)
{
@Override
public int parseNext() throws IOException
{
System.out.print(".");
httpParses.incrementAndGet();
return super.parseNext();
}
};
}
};
}
};
connector.setMaxIdleTime(2000);
// connector.setPort(5870);
connector.setPort(0);
server.addConnector(connector);
server.setHandler(new AbstractHandler()
{
public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws IOException,
ServletException
{
request.setHandled(true);
String contentLength = request.getHeader("Content-Length");
if (contentLength != null)
{
int length = Integer.parseInt(contentLength);
ServletInputStream input = request.getInputStream();
for (int i = 0; i < length; ++i)
input.read();
}
}
});
server.start();
serverPort = connector.getLocalPort();
logger.debug(" => :{}",serverPort);
}
@After
public void destroy() throws Exception
{
if (server != null)
server.stop();
if (threadPool != null)
threadPool.shutdownNow();
}
private Socket newClient() throws IOException, InterruptedException
{
Socket client = new Socket("localhost",serverPort);
return client;
}
/**
* Test that performs a seemingly normal http POST request, but with
* a client that issues "connection: close", waits 100 seconds to
* do anything with the connection (at all), and then attempts to
* write a second POST request.
* <p>
* The connection should be closed by the server, and/or be closed
* due to a timeout on the socket.
*/
@Ignore
@Test
public void testServerCloseClientDoesNotClose() throws Exception
{
// Log.getLogger("").setDebugEnabled(true);
final Socket client = newClient();
final OutputStream clientOutput = client.getOutputStream();
byte[] data = new byte[3 * 1024];
Arrays.fill(data,(byte)'Y');
String content = new String(data,"UTF-8");
// The request section
StringBuilder req = new StringBuilder();
req.append("POST / HTTP/1.1\r\n");
req.append("Host: localhost\r\n");
req.append("Content-Type: text/plain\r\n");
req.append("Content-Length: ").append(content.length()).append("\r\n");
req.append("Connection: close\r\n");
req.append("\r\n");
// and now, the POST content section.
req.append(content);
// Send request to server
clientOutput.write(req.toString().getBytes("UTF-8"));
clientOutput.flush();
System.out.println("Client request #1 flushed");
InputStream in = null;
InputStreamReader isr = null;
BufferedReader reader = null;
try
{
in = client.getInputStream();
isr = new InputStreamReader(in);
reader = new BufferedReader(isr);
// Read the response header
String line = reader.readLine();
Assert.assertNotNull(line);
Assert.assertThat(line,startsWith("HTTP/1.1 200 "));
while ((line = reader.readLine()) != null)
{
if (line.trim().length() == 0)
{
break;
}
}
System.out.println("Got response header");
// Check that we did not spin
int httpParseCount = httpParses.get();
System.out.printf("Got %d http parses%n",httpParseCount);
Assert.assertThat(httpParseCount,lessThan(50));
// TODO: instead of sleeping, we should expect the connection being closed by the idle timeout
// TODO: mechanism; unfortunately this now is not working, and this test fails because the idle
// TODO: timeout will not trigger.
TimeUnit.SECONDS.sleep(100);
// Try to write another request (to prove that stream is closed)
clientOutput.write(req.toString().getBytes("UTF-8"));
clientOutput.flush();
Assert.fail("Should not have been able to send a second POST request (connection: close)");
}
finally
{
IO.close(reader);
IO.close(isr);
IO.close(in);
closeClient(client);
}
}
private void closeClient(Socket client) throws IOException
{
client.close();
}
}

View File

@ -62,12 +62,6 @@ public abstract class AbstractConnection implements Connection
public String toString()
{
return String.format("%s@%x//%s:%d<->%s:%d",
getClass().getSimpleName(),
hashCode(),
_endp.getLocalAddr(),
_endp.getLocalPort(),
_endp.getRemoteAddr(),
_endp.getRemotePort());
return String.format("%s@%x", getClass().getSimpleName(), hashCode());
}
}

View File

@ -709,9 +709,30 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
@Override
public String toString()
{
synchronized(this)
// Do NOT use synchronized (this)
// because it's very easy to deadlock when debugging is enabled.
// We do a best effort to print the right toString() and that's it.
SelectionKey key = _key;
String keyString = "";
if (key != null)
{
return String.format("SCEP@%x{%s->%s,d=%b,open=%b,ishut=%b,oshut=%b,rb=%b,wb=%b,w=%b,i=%d%s%s%s}",
if (key.isValid())
{
if (key.isReadable())
keyString += "r";
if (key.isWritable())
keyString += "w";
}
else
{
keyString += "!";
}
}
else
{
keyString += "-";
}
return String.format("SCEP@%x{l(%s)<->r(%s),d=%b,open=%b,ishut=%b,oshut=%b,rb=%b,wb=%b,w=%b,i=%d%s}-{%s}",
hashCode(),
_socket.getRemoteSocketAddress(),
_socket.getLocalSocketAddress(),
@ -723,10 +744,8 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
_writeBlocked,
_writable,
_interestOps,
_key != null && _key.isValid() ? "" : "!",
_key != null && _key.isValid() && _key.isReadable() ? "r" : "",
_key != null && _key.isValid() && _key.isWritable() ? "w" : "");
}
keyString,
_connection);
}
/* ------------------------------------------------------------ */

View File

@ -190,9 +190,10 @@ public class SslConnection extends AbstractConnection implements AsyncConnection
_connection=next;
progress=true;
}
// TODO: consider moving here hasProgressed() - it's only used in SSL
}
LOG.debug("{} handle {} progress=",_session,this, progress);
LOG.debug("{} handle {} progress={}", _session, this, progress);
}
}
finally
@ -322,13 +323,13 @@ public class SslConnection extends AbstractConnection implements AsyncConnection
case NOT_HANDSHAKING:
{
// Try wrapping some application data
if (toFlush.hasContent() && _outbound.space()>0 && wrap(toFlush))
progress=true;
// Try unwrapping some application data
if (toFill.space()>0 && _inbound.hasContent() && unwrap(toFill))
progress=true;
// Try wrapping some application data
if (toFlush.hasContent() && _outbound.space()>0 && wrap(toFlush))
progress=true;
}
break;
@ -389,6 +390,9 @@ public class SslConnection extends AbstractConnection implements AsyncConnection
some_progress|=progress;
}
if (toFill.hasContent())
_aEndp.asyncDispatch();
}
finally
{
@ -571,7 +575,7 @@ public class SslConnection extends AbstractConnection implements AsyncConnection
public String toString()
{
return String.format("%s | %s", super.toString(), _sslEndPoint);
return String.format("%s %s", super.toString(), _sslEndPoint);
}
/* ------------------------------------------------------------ */
@ -628,7 +632,7 @@ public class SslConnection extends AbstractConnection implements AsyncConnection
public int fill(Buffer buffer) throws IOException
{
int size=buffer.length();
process(buffer,null);
process(buffer, null);
int filled=buffer.length()-size;
@ -688,7 +692,7 @@ public class SslConnection extends AbstractConnection implements AsyncConnection
public void flush() throws IOException
{
process(null,null);
process(null, null);
}
public void asyncDispatch()
@ -793,20 +797,20 @@ public class SslConnection extends AbstractConnection implements AsyncConnection
public String toString()
{
int i;
int o;
int u;
synchronized(SslConnection.this)
{
i=_inbound==null?-1:_inbound.length();
o=_outbound==null?-1:_outbound.length();
u=_unwrapBuf==null?-1:_unwrapBuf.length();
}
return String.format("SSL:%s %s i/u/o=%d/%d/%d ishut=%b oshut=%b",
_endp,
// Do NOT use synchronized (SslConnection.this)
// because it's very easy to deadlock when debugging is enabled.
// We do a best effort to print the right toString() and that's it.
Buffer inbound = _inbound;
Buffer outbound = _outbound;
Buffer unwrap = _unwrapBuf;
int i = inbound == null? -1 : inbound.length();
int o = outbound == null ? -1 : outbound.length();
int u = unwrap == null ? -1 : unwrap.length();
return String.format("SSL %s i/o/u=%d/%d/%d ishut=%b oshut=%b {%s}",
_engine.getHandshakeStatus(),
i, u, o,
_ishut, _oshut);
i, o, u,
_ishut, _oshut,
_connection);
}
}
}

View File

@ -16,7 +16,6 @@ package org.eclipse.jetty.server;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;

View File

@ -16,7 +16,6 @@ package org.eclipse.jetty.server;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.Enumeration;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

View File

@ -13,10 +13,6 @@
package org.eclipse.jetty.server;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertTrue;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@ -29,14 +25,12 @@ import java.net.URL;
import java.util.Arrays;
import java.util.Random;
import java.util.concurrent.Exchanger;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import junit.framework.Assert;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.server.handler.AbstractHandler;
import org.eclipse.jetty.util.IO;
@ -44,6 +38,10 @@ import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.StdErrLog;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertTrue;
/**
*
*/

View File

@ -1,12 +1,10 @@
package org.eclipse.jetty.server.handler;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.io.BufferedReader;
import java.io.EOFException;
import java.io.IOException;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.regex.Matcher;
@ -18,6 +16,9 @@ import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.nio.SelectChannelConnector;
import org.junit.AfterClass;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
/**
* @version $Revision$ $Date$
*/
@ -91,11 +92,21 @@ public abstract class AbstractConnectHandlerTest
StringBuilder body = new StringBuilder();
if (headers.containsKey("content-length"))
{
int readLen = 0;
int length = Integer.parseInt(headers.get("content-length"));
try
{
for (int i = 0; i < length; ++i)
{
char c = (char)reader.read();
body.append(c);
readLen++;
}
}
catch (SocketTimeoutException e)
{
System.err.printf("Read %,d bytes (out of an expected %,d bytes)%n",readLen,length);
throw e;
}
}
else if ("chunked".equals(headers.get("transfer-encoding")))
@ -126,7 +137,7 @@ public abstract class AbstractConnectHandlerTest
protected Socket newSocket() throws IOException
{
Socket socket = new Socket("localhost", proxyConnector.getLocalPort());
socket.setSoTimeout(5000);
socket.setSoTimeout(10000);
return socket;
}

View File

@ -14,23 +14,17 @@
package org.eclipse.jetty.server.handler;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import junit.framework.Assert;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.LocalConnector;
import org.eclipse.jetty.server.Request;
@ -38,6 +32,10 @@ import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.util.resource.Resource;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
/**
* @version $Revision$
*/

View File

@ -1,13 +1,12 @@
package org.eclipse.jetty.servlets;
import java.io.File;
import java.util.Arrays;
import java.util.List;
import javax.servlet.Servlet;
import org.eclipse.jetty.http.HttpStatus;
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;
@ -49,7 +48,6 @@ public class GzipFilterContentLengthTest
{
return Arrays.asList(new Object[][]
{
{ DefaultServlet.class },
{ TestServletLengthStreamTypeWrite.class },
{ TestServletLengthTypeStreamWrite.class },
{ TestServletStreamLengthTypeWrite.class },
@ -77,7 +75,7 @@ public class GzipFilterContentLengthTest
{
GzipTester tester = new GzipTester(testingdir);
tester.prepareServerFile(filename,filesize);
File testfile = tester.prepareServerFile(testServlet.getSimpleName() + "-" + filename,filesize);
FilterHolder holder = tester.setContentServlet(testServlet);
holder.setInitParameter("mimeTypes","text/plain");
@ -85,7 +83,7 @@ public class GzipFilterContentLengthTest
try
{
tester.start();
tester.assertIsResponseGzipCompressed(filename);
tester.assertIsResponseGzipCompressed(testfile.getName());
}
finally
{
@ -97,7 +95,7 @@ public class GzipFilterContentLengthTest
{
GzipTester tester = new GzipTester(testingdir);
tester.prepareServerFile(filename,filesize);
File testfile = tester.prepareServerFile(testServlet.getSimpleName() + "-" + filename,filesize);
FilterHolder holder = tester.setContentServlet(testServlet);
holder.setInitParameter("mimeTypes","text/plain");
@ -105,7 +103,7 @@ public class GzipFilterContentLengthTest
try
{
tester.start();
tester.assertIsResponseNotGzipCompressed(filename,filesize,HttpStatus.OK_200);
tester.assertIsResponseNotGzipCompressed(testfile.getName(),filesize,HttpStatus.OK_200);
}
finally
{
@ -119,7 +117,7 @@ public class GzipFilterContentLengthTest
@Test
public void testIsGzipCompressedSmall() throws Exception
{
assertIsGzipCompressed("file.txt",SMALL);
assertIsGzipCompressed("file-small.txt",SMALL);
}
/**
@ -128,7 +126,7 @@ public class GzipFilterContentLengthTest
@Test
public void testIsGzipCompressedMedium() throws Exception
{
assertIsGzipCompressed("file.txt",MEDIUM);
assertIsGzipCompressed("file-med.txt",MEDIUM);
}
/**
@ -137,7 +135,7 @@ public class GzipFilterContentLengthTest
@Test
public void testIsGzipCompressedLarge() throws Exception
{
assertIsGzipCompressed("file.txt",LARGE);
assertIsGzipCompressed("file-large.txt",LARGE);
}
/**
@ -149,7 +147,7 @@ public class GzipFilterContentLengthTest
@Test
public void testIsNotGzipCompressedTiny() throws Exception
{
assertIsNotGzipCompressed("file.txt",TINY);
assertIsNotGzipCompressed("file-tiny.txt",TINY);
}
/**
@ -161,7 +159,7 @@ public class GzipFilterContentLengthTest
@Test
public void testIsNotGzipCompressedSmall() throws Exception
{
assertIsNotGzipCompressed("file.mp3",SMALL);
assertIsNotGzipCompressed("file-small.mp3",SMALL);
}
/**
@ -173,7 +171,7 @@ public class GzipFilterContentLengthTest
@Test
public void testIsNotGzipCompressedMedium() throws Exception
{
assertIsNotGzipCompressed("file.mp3",MEDIUM);
assertIsNotGzipCompressed("file-medium.mp3",MEDIUM);
}
/**
@ -185,6 +183,6 @@ public class GzipFilterContentLengthTest
@Test
public void testIsNotGzipCompressedLarge() throws Exception
{
assertIsNotGzipCompressed("file.mp3",LARGE);
assertIsNotGzipCompressed("file-large.mp3",LARGE);
}
}

View File

@ -1,8 +1,5 @@
package org.eclipse.jetty.servlets.gzip;
import static org.hamcrest.Matchers.*;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
@ -15,7 +12,6 @@ import java.util.Enumeration;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.GZIPInputStream;
import javax.servlet.Servlet;
import javax.servlet.http.HttpServletResponse;
@ -30,6 +26,12 @@ import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
import org.eclipse.jetty.toolchain.test.TestingDir;
import org.junit.Assert;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.nullValue;
public class GzipTester
{
private Class<? extends GzipFilter> gzipFilterClass = GzipFilter.class;
@ -41,7 +43,7 @@ public class GzipTester
{
this.testdir = testingdir;
// Make sure we start with a clean testing directory.
this.testdir.ensureEmpty();
// DOES NOT WORK IN WINDOWS - this.testdir.ensureEmpty();
}
public void assertIsResponseGzipCompressed(String filename) throws Exception
@ -309,24 +311,29 @@ public class GzipTester
* @param filesize
* the file size to create (Note: this isn't suitable for creating large multi-megabyte files)
*/
public void prepareServerFile(String filename, int filesize) throws IOException
public File prepareServerFile(String filename, int filesize) throws IOException
{
File testFile = testdir.getFile(filename);
File dir = testdir.getDir();
File testFile = new File(dir,filename);
// Make sure we have a uniq filename (to work around windows File.delete bug)
int i = 0;
while (testFile.exists())
{
testFile = new File(dir,(i++) + "-" + filename);
}
FileOutputStream fos = null;
BufferedOutputStream out = null;
ByteArrayInputStream in = null;
try
{
fos = new FileOutputStream(testFile,false);
out = new BufferedOutputStream(fos);
in = new ByteArrayInputStream(generateContent(filesize).getBytes(encoding));
IO.copy(in,out);
IO.copy(in,fos);
return testFile;
}
finally
{
IO.close(in);
IO.close(out);
IO.close(fos);
}
}

View File

@ -141,7 +141,7 @@ public class WebSocketClientFactory extends AggregateLifeCycle
/* ------------------------------------------------------------ */
/**
* @return the shared mask generator, or null if no shared mask generator is used
* @see {@link WebSocketClient#getMaskGen()}
* @see WebSocketClient#getMaskGen()
*/
public MaskGen getMaskGen()
{
@ -151,7 +151,7 @@ public class WebSocketClientFactory extends AggregateLifeCycle
/* ------------------------------------------------------------ */
/**
* @param maskGen the shared mask generator, or null if no shared mask generator is used
* @see {@link WebSocketClient#setMaskGen(MaskGen)}
* @see WebSocketClient#setMaskGen(MaskGen)
*/
public void setMaskGen(MaskGen maskGen)
{

View File

@ -1,12 +1,8 @@
package org.eclipse.jetty.websocket;
import java.io.IOException;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.io.Buffer;
import org.eclipse.jetty.io.nio.AsyncConnection;
@ -14,8 +10,6 @@ public interface WebSocketConnection extends AsyncConnection
{
void fillBuffersFrom(Buffer buffer);
void handshake(HttpServletRequest request, HttpServletResponse response, String subprotocol) throws IOException;
List<Extension> getExtensions();
WebSocket.Connection getConnection();

View File

@ -19,10 +19,6 @@ import java.security.NoSuchAlgorithmException;
import java.util.Collections;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.http.HttpURI;
import org.eclipse.jetty.io.AbstractConnection;
import org.eclipse.jetty.io.AsyncEndPoint;
import org.eclipse.jetty.io.Buffer;
@ -30,7 +26,6 @@ import org.eclipse.jetty.io.ByteArrayBuffer;
import org.eclipse.jetty.io.Connection;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.io.nio.IndirectNIOBuffer;
import org.eclipse.jetty.util.QuotedStringTokenizer;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
@ -43,13 +38,13 @@ public class WebSocketConnectionD00 extends AbstractConnection implements WebSoc
public final static byte LENGTH_FRAME=(byte)0x80;
public final static byte SENTINEL_FRAME=(byte)0x00;
final WebSocketParser _parser;
final WebSocketGenerator _generator;
final WebSocket _websocket;
final String _protocol;
String _key1;
String _key2;
ByteArrayBuffer _hixieBytes;
private final WebSocketParser _parser;
private final WebSocketGenerator _generator;
private final WebSocket _websocket;
private final String _protocol;
private String _key1;
private String _key2;
private ByteArrayBuffer _hixieBytes;
public WebSocketConnectionD00(WebSocket websocket, EndPoint endpoint, WebSocketBuffers buffers, long timestamp, int maxIdleTime, String protocol)
throws IOException
@ -340,54 +335,6 @@ public class WebSocketConnectionD00 extends AbstractConnection implements WebSoc
}
}
public void handshake(HttpServletRequest request, HttpServletResponse response, String subprotocol) throws IOException
{
String uri=request.getRequestURI();
String query=request.getQueryString();
if (query!=null && query.length()>0)
uri+="?"+query;
uri=new HttpURI(uri).toString();
String host=request.getHeader("Host");
String origin=request.getHeader("Sec-WebSocket-Origin");
if (origin==null)
origin=request.getHeader("Origin");
if (origin!=null)
origin= QuotedStringTokenizer.quoteIfNeeded(origin, "\r\n");
String key1 = request.getHeader("Sec-WebSocket-Key1");
if (key1!=null)
{
String key2 = request.getHeader("Sec-WebSocket-Key2");
setHixieKeys(key1,key2);
response.setHeader("Upgrade","WebSocket");
response.addHeader("Connection","Upgrade");
if (origin!=null)
response.addHeader("Sec-WebSocket-Origin",origin);
response.addHeader("Sec-WebSocket-Location",(request.isSecure()?"wss://":"ws://")+host+uri);
if (subprotocol!=null)
response.addHeader("Sec-WebSocket-Protocol",subprotocol);
response.sendError(101,"WebSocket Protocol Handshake");
}
else
{
response.setHeader("Upgrade","WebSocket");
response.addHeader("Connection","Upgrade");
response.addHeader("WebSocket-Origin",origin);
response.addHeader("WebSocket-Location",(request.isSecure()?"wss://":"ws://")+host+uri);
if (subprotocol!=null)
response.addHeader("WebSocket-Protocol",subprotocol);
response.sendError(101,"Web Socket Protocol Handshake");
response.flushBuffer();
if (_websocket instanceof OnFrame)
((OnFrame)_websocket).onHandshake(this);
_websocket.onOpen(this);
}
}
public void setMaxTextMessageSize(int size)
{
}
@ -428,6 +375,19 @@ public class WebSocketConnectionD00 extends AbstractConnection implements WebSoc
return _protocol;
}
protected void onFrameHandshake()
{
if (_websocket instanceof OnFrame)
{
((OnFrame)_websocket).onHandshake(this);
}
}
protected void onWebsocketOpen()
{
_websocket.onOpen(this);
}
static class FrameHandlerD00 implements WebSocketParser.FrameHandler
{
final WebSocket _websocket;

View File

@ -19,9 +19,6 @@ import java.security.MessageDigest;
import java.util.Collections;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.io.AbstractConnection;
import org.eclipse.jetty.io.AsyncEndPoint;
import org.eclipse.jetty.io.Buffer;
@ -73,7 +70,6 @@ public class WebSocketConnectionD06 extends AbstractConnection implements WebSoc
}
}
private final static byte[] MAGIC;
private final WebSocketParser _parser;
private final WebSocketGenerator _generator;
@ -101,10 +97,6 @@ public class WebSocketConnectionD06 extends AbstractConnection implements WebSoc
}
private final WebSocketParser.FrameHandler _frameHandler= new FrameHandlerD06();
/* ------------------------------------------------------------ */
/* ------------------------------------------------------------ */
/* ------------------------------------------------------------ */
private final WebSocket.FrameConnection _connection = new FrameConnectionD06();
@ -288,8 +280,19 @@ public class WebSocketConnectionD06 extends AbstractConnection implements WebSoc
return Collections.emptyList();
}
/* ------------------------------------------------------------ */
/* ------------------------------------------------------------ */
protected void onFrameHandshake()
{
if (_onFrame!=null)
{
_onFrame.onHandshake(_connection);
}
}
protected void onWebSocketOpen()
{
_webSocket.onOpen(_connection);
}
/* ------------------------------------------------------------ */
private class FrameConnectionD06 implements WebSocket.FrameConnection
{
@ -487,6 +490,7 @@ public class WebSocketConnectionD06 extends AbstractConnection implements WebSoc
}
/* ------------------------------------------------------------ */
@Override
public String toString()
{
return this.getClass().getSimpleName()+"@"+_endp.getLocalAddr()+":"+_endp.getLocalPort()+"<->"+_endp.getRemoteAddr()+":"+_endp.getRemotePort();
@ -693,29 +697,13 @@ public class WebSocketConnectionD06 extends AbstractConnection implements WebSoc
_connection.close(code,message);
}
@Override
public String toString()
{
return WebSocketConnectionD06.this.toString()+"FH";
}
}
/* ------------------------------------------------------------ */
public void handshake(HttpServletRequest request, HttpServletResponse response, String subprotocol) throws IOException
{
String key = request.getHeader("Sec-WebSocket-Key");
response.setHeader("Upgrade","WebSocket");
response.addHeader("Connection","Upgrade");
response.addHeader("Sec-WebSocket-Accept",hashKey(key));
if (subprotocol!=null)
response.addHeader("Sec-WebSocket-Protocol",subprotocol);
response.sendError(101);
if (_onFrame!=null)
_onFrame.onHandshake(_connection);
_webSocket.onOpen(_connection);
}
/* ------------------------------------------------------------ */
public static String hashKey(String key)
{

View File

@ -19,16 +19,12 @@ import java.security.MessageDigest;
import java.util.Collections;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.io.AbstractConnection;
import org.eclipse.jetty.io.AsyncEndPoint;
import org.eclipse.jetty.io.Buffer;
import org.eclipse.jetty.io.ByteArrayBuffer;
import org.eclipse.jetty.io.Connection;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.io.nio.SelectChannelEndPoint;
import org.eclipse.jetty.util.B64Code;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.Utf8StringBuilder;
@ -110,7 +106,6 @@ public class WebSocketConnectionD08 extends AbstractConnection implements WebSoc
}
private final WebSocketParser.FrameHandler _frameHandler= new WSFrameHandler();
private final WebSocket.FrameConnection _connection = new WSFrameConnection();
@ -375,8 +370,19 @@ public class WebSocketConnectionD08 extends AbstractConnection implements WebSoc
}
}
/* ------------------------------------------------------------ */
/* ------------------------------------------------------------ */
protected void onFrameHandshake()
{
if (_onFrame != null)
{
_onFrame.onHandshake(_connection);
}
}
protected void onWebSocketOpen()
{
_webSocket.onOpen(_connection);
}
/* ------------------------------------------------------------ */
private class WSFrameConnection implements WebSocket.FrameConnection
{
@ -799,27 +805,6 @@ public class WebSocketConnectionD08 extends AbstractConnection implements WebSoc
}
}
/* ------------------------------------------------------------ */
public void handshake(HttpServletRequest request, HttpServletResponse response, String subprotocol) throws IOException
{
String key = request.getHeader("Sec-WebSocket-Key");
response.setHeader("Upgrade", "WebSocket");
response.addHeader("Connection","Upgrade");
response.addHeader("Sec-WebSocket-Accept",hashKey(key));
if (subprotocol!=null)
response.addHeader("Sec-WebSocket-Protocol",subprotocol);
for(Extension ext : _extensions)
response.addHeader("Sec-WebSocket-Extensions",ext.getParameterizedName());
response.sendError(101);
if (_onFrame!=null)
_onFrame.onHandshake(_connection);
_webSocket.onOpen(_connection);
}
/* ------------------------------------------------------------ */
public static String hashKey(String key)
{
@ -840,6 +825,6 @@ public class WebSocketConnectionD08 extends AbstractConnection implements WebSoc
@Override
public String toString()
{
return "WS/D"+_draft+"-"+_endp;
return String.format("WS/D%d p=%s g=%s", _draft, _parser, _generator);
}
}

View File

@ -19,16 +19,12 @@ import java.security.MessageDigest;
import java.util.Collections;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.io.AbstractConnection;
import org.eclipse.jetty.io.AsyncEndPoint;
import org.eclipse.jetty.io.Buffer;
import org.eclipse.jetty.io.ByteArrayBuffer;
import org.eclipse.jetty.io.Connection;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.io.nio.SelectChannelEndPoint;
import org.eclipse.jetty.util.B64Code;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.Utf8Appendable;
@ -397,8 +393,19 @@ public class WebSocketConnectionD13 extends AbstractConnection implements WebSoc
}
}
/* ------------------------------------------------------------ */
/* ------------------------------------------------------------ */
protected void onFrameHandshake()
{
if (_onFrame != null)
{
_onFrame.onHandshake(_connection);
}
}
protected void onWebSocketOpen()
{
_webSocket.onOpen(_connection);
}
/* ------------------------------------------------------------ */
private class WSFrameConnection implements WebSocket.FrameConnection
{
@ -917,27 +924,6 @@ public class WebSocketConnectionD13 extends AbstractConnection implements WebSoc
}
}
/* ------------------------------------------------------------ */
public void handshake(HttpServletRequest request, HttpServletResponse response, String subprotocol) throws IOException
{
String key = request.getHeader("Sec-WebSocket-Key");
response.setHeader("Upgrade","WebSocket");
response.addHeader("Connection","Upgrade");
response.addHeader("Sec-WebSocket-Accept",hashKey(key));
if (subprotocol!=null)
response.addHeader("Sec-WebSocket-Protocol",subprotocol);
for(Extension ext : _extensions)
response.addHeader("Sec-WebSocket-Extensions",ext.getParameterizedName());
response.sendError(101);
if (_onFrame!=null)
_onFrame.onHandshake(_connection);
_webSocket.onOpen(_connection);
}
/* ------------------------------------------------------------ */
public static String hashKey(String key)
{
@ -958,6 +944,6 @@ public class WebSocketConnectionD13 extends AbstractConnection implements WebSoc
@Override
public String toString()
{
return "WS/D"+_draft+"-"+_endp;
return String.format("WS/D%d p=%s g=%s", _draft, _parser, _generator);
}
}

View File

@ -20,7 +20,6 @@ import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@ -201,22 +200,25 @@ public class WebSocketFactory
ConnectedEndPoint endp = (ConnectedEndPoint)http.getEndPoint();
List<String> extensions_requested = new ArrayList<String>();
for (Enumeration e=request.getHeaders("Sec-WebSocket-Extensions");e.hasMoreElements();)
@SuppressWarnings("unchecked")
Enumeration<String> e = request.getHeaders("Sec-WebSocket-Extensions");
while (e.hasMoreElements())
{
QuotedStringTokenizer tok = new QuotedStringTokenizer((String)e.nextElement(),",");
QuotedStringTokenizer tok = new QuotedStringTokenizer(e.nextElement(),",");
while (tok.hasMoreTokens())
{
extensions_requested.add(tok.nextToken());
}
}
final WebSocketConnection connection;
final WebSocketServletConnection connection;
final List<Extension> extensions;
switch (draft)
{
case -1:
case 0:
extensions=Collections.emptyList();
connection = new WebSocketConnectionD00(websocket, endp, _buffers, http.getTimeStamp(), _maxIdleTime, protocol);
connection = new WebSocketServletConnectionD00(websocket, endp, _buffers, http.getTimeStamp(), _maxIdleTime, protocol);
break;
case 1:
case 2:
@ -225,16 +227,16 @@ public class WebSocketFactory
case 5:
case 6:
extensions=Collections.emptyList();
connection = new WebSocketConnectionD06(websocket, endp, _buffers, http.getTimeStamp(), _maxIdleTime, protocol);
connection = new WebSocketServletConnectionD06(websocket, endp, _buffers, http.getTimeStamp(), _maxIdleTime, protocol);
break;
case 7:
case 8:
extensions= initExtensions(extensions_requested,8-WebSocketConnectionD08.OP_EXT_DATA, 16-WebSocketConnectionD08.OP_EXT_CTRL,3);
connection = new WebSocketConnectionD08(websocket, endp, _buffers, http.getTimeStamp(), _maxIdleTime, protocol,extensions,draft);
connection = new WebSocketServletConnectionD08(websocket, endp, _buffers, http.getTimeStamp(), _maxIdleTime, protocol,extensions,draft);
break;
case 13:
extensions= initExtensions(extensions_requested,8-WebSocketConnectionD13.OP_EXT_DATA, 16-WebSocketConnectionD13.OP_EXT_CTRL,3);
connection = new WebSocketConnectionD13(websocket, endp, _buffers, http.getTimeStamp(), _maxIdleTime, protocol,extensions,draft);
connection = new WebSocketServletConnectionD13(websocket, endp, _buffers, http.getTimeStamp(), _maxIdleTime, protocol,extensions,draft);
break;
default:
LOG.warn("Unsupported Websocket version: "+draft);
@ -293,6 +295,7 @@ public class WebSocketFactory
// Try each requested protocol
WebSocket websocket = null;
@SuppressWarnings("unchecked")
Enumeration<String> protocols = request.getHeaders("Sec-WebSocket-Protocol");
String protocol=null;
while (protocol==null && protocols!=null && protocols.hasMoreElements())

View File

@ -240,4 +240,17 @@ public class WebSocketGeneratorD13 implements WebSocketGenerator
}
}
@Override
public String toString()
{
// Do NOT use synchronized (this)
// because it's very easy to deadlock when debugging is enabled.
// We do a best effort to print the right toString() and that's it.
Buffer buffer = _buffer;
return String.format("%s@%x closed=%b buffer=%d",
getClass().getSimpleName(),
hashCode(),
_closed,
buffer == null ? -1 : buffer.length());
}
}

View File

@ -380,8 +380,10 @@ public class WebSocketParserD13 implements WebSocketParser
@Override
public String toString()
{
Buffer buffer=_buffer;
return WebSocketParserD13.class.getSimpleName()+"@"+ Integer.toHexString(hashCode())+"|"+_state+"|"+(buffer==null?"<>":buffer.toDetailString());
return String.format("%s@%x state=%s buffer=%s",
getClass().getSimpleName(),
hashCode(),
_state,
_buffer);
}
}

View File

@ -14,7 +14,6 @@
package org.eclipse.jetty.websocket;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
@ -41,6 +40,7 @@ import javax.servlet.http.HttpServletResponse;
* that a websocket may be accept before closing.
*
*/
@SuppressWarnings("serial")
public abstract class WebSocketServlet extends HttpServlet implements WebSocketFactory.Acceptor
{
WebSocketFactory _webSocketFactory;

View File

@ -0,0 +1,10 @@
package org.eclipse.jetty.websocket;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public interface WebSocketServletConnection extends WebSocketConnection
{
void handshake(HttpServletRequest request, HttpServletResponse response, String subprotocol) throws IOException;
}

View File

@ -0,0 +1,77 @@
package org.eclipse.jetty.websocket;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.http.HttpURI;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.util.QuotedStringTokenizer;
public class WebSocketServletConnectionD00 extends WebSocketConnectionD00 implements WebSocketServletConnection
{
public WebSocketServletConnectionD00(WebSocket websocket, EndPoint endpoint, WebSocketBuffers buffers, long timestamp, int maxIdleTime, String protocol)
throws IOException
{
super(websocket,endpoint,buffers,timestamp,maxIdleTime,protocol);
}
public void handshake(HttpServletRequest request, HttpServletResponse response, String subprotocol) throws IOException
{
String uri = request.getRequestURI();
String query = request.getQueryString();
if (query != null && query.length() > 0)
{
uri += "?" + query;
}
uri = new HttpURI(uri).toString();
String host = request.getHeader("Host");
String origin = request.getHeader("Sec-WebSocket-Origin");
if (origin == null)
{
origin = request.getHeader("Origin");
}
if (origin != null)
{
origin = QuotedStringTokenizer.quoteIfNeeded(origin,"\r\n");
}
String key1 = request.getHeader("Sec-WebSocket-Key1");
if (key1 != null)
{
String key2 = request.getHeader("Sec-WebSocket-Key2");
setHixieKeys(key1,key2);
response.setHeader("Upgrade","WebSocket");
response.addHeader("Connection","Upgrade");
if (origin != null)
{
response.addHeader("Sec-WebSocket-Origin",origin);
}
response.addHeader("Sec-WebSocket-Location",(request.isSecure()?"wss://":"ws://") + host + uri);
if (subprotocol != null)
{
response.addHeader("Sec-WebSocket-Protocol",subprotocol);
}
response.sendError(101,"WebSocket Protocol Handshake");
}
else
{
response.setHeader("Upgrade","WebSocket");
response.addHeader("Connection","Upgrade");
response.addHeader("WebSocket-Origin",origin);
response.addHeader("WebSocket-Location",(request.isSecure()?"wss://":"ws://") + host + uri);
if (subprotocol != null)
{
response.addHeader("WebSocket-Protocol",subprotocol);
}
response.sendError(101,"Web Socket Protocol Handshake");
response.flushBuffer();
onFrameHandshake();
onWebsocketOpen();
}
}
}

View File

@ -0,0 +1,35 @@
package org.eclipse.jetty.websocket;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.io.EndPoint;
public class WebSocketServletConnectionD06 extends WebSocketConnectionD06 implements WebSocketServletConnection
{
public WebSocketServletConnectionD06(WebSocket websocket, EndPoint endpoint, WebSocketBuffers buffers, long timestamp, int maxIdleTime, String protocol)
throws IOException
{
super(websocket,endpoint,buffers,timestamp,maxIdleTime,protocol);
}
/* ------------------------------------------------------------ */
public void handshake(HttpServletRequest request, HttpServletResponse response, String subprotocol) throws IOException
{
String key = request.getHeader("Sec-WebSocket-Key");
response.setHeader("Upgrade","WebSocket");
response.addHeader("Connection","Upgrade");
response.addHeader("Sec-WebSocket-Accept",hashKey(key));
if (subprotocol!=null)
{
response.addHeader("Sec-WebSocket-Protocol",subprotocol);
}
response.sendError(101);
onFrameHandshake();
onWebSocketOpen();
}
}

View File

@ -0,0 +1,47 @@
package org.eclipse.jetty.websocket;
import java.io.IOException;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.io.EndPoint;
public class WebSocketServletConnectionD08 extends WebSocketConnectionD08 implements WebSocketServletConnection
{
public WebSocketServletConnectionD08(WebSocket websocket, EndPoint endpoint, WebSocketBuffers buffers, long timestamp, int maxIdleTime, String protocol,
List<Extension> extensions, int draft, MaskGen maskgen) throws IOException
{
super(websocket,endpoint,buffers,timestamp,maxIdleTime,protocol,extensions,draft,maskgen);
}
public WebSocketServletConnectionD08(WebSocket websocket, EndPoint endpoint, WebSocketBuffers buffers, long timestamp, int maxIdleTime, String protocol,
List<Extension> extensions, int draft) throws IOException
{
super(websocket,endpoint,buffers,timestamp,maxIdleTime,protocol,extensions,draft);
}
/* ------------------------------------------------------------ */
public void handshake(HttpServletRequest request, HttpServletResponse response, String subprotocol) throws IOException
{
String key = request.getHeader("Sec-WebSocket-Key");
response.setHeader("Upgrade","WebSocket");
response.addHeader("Connection","Upgrade");
response.addHeader("Sec-WebSocket-Accept",hashKey(key));
if (subprotocol != null)
{
response.addHeader("Sec-WebSocket-Protocol",subprotocol);
}
for (Extension ext : getExtensions())
{
response.addHeader("Sec-WebSocket-Extensions",ext.getParameterizedName());
}
response.sendError(101);
onFrameHandshake();
onWebSocketOpen();
}
}

View File

@ -0,0 +1,47 @@
package org.eclipse.jetty.websocket;
import java.io.IOException;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.io.EndPoint;
public class WebSocketServletConnectionD13 extends WebSocketConnectionD13 implements WebSocketServletConnection
{
public WebSocketServletConnectionD13(WebSocket websocket, EndPoint endpoint, WebSocketBuffers buffers, long timestamp, int maxIdleTime, String protocol,
List<Extension> extensions, int draft, MaskGen maskgen) throws IOException
{
super(websocket,endpoint,buffers,timestamp,maxIdleTime,protocol,extensions,draft,maskgen);
}
public WebSocketServletConnectionD13(WebSocket websocket, EndPoint endpoint, WebSocketBuffers buffers, long timestamp, int maxIdleTime, String protocol,
List<Extension> extensions, int draft) throws IOException
{
super(websocket,endpoint,buffers,timestamp,maxIdleTime,protocol,extensions,draft);
}
/* ------------------------------------------------------------ */
public void handshake(HttpServletRequest request, HttpServletResponse response, String subprotocol) throws IOException
{
String key = request.getHeader("Sec-WebSocket-Key");
response.setHeader("Upgrade","WebSocket");
response.addHeader("Connection","Upgrade");
response.addHeader("Sec-WebSocket-Accept",hashKey(key));
if (subprotocol != null)
{
response.addHeader("Sec-WebSocket-Protocol",subprotocol);
}
for (Extension ext : getExtensions())
{
response.addHeader("Sec-WebSocket-Extensions",ext.getParameterizedName());
}
response.sendError(101);
onFrameHandshake();
onWebSocketOpen();
}
}