Merge remote-tracking branch 'origin/master' into bug-359329
This commit is contained in:
commit
397aa79a50
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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$
|
||||
*/
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue