Merge remote-tracking branch 'origin/master' into jetty-8

Conflicts:
	VERSION.txt
	jetty-server/src/main/java/org/eclipse/jetty/server/AbstractHttpConnection.java
	jetty-server/src/main/java/org/eclipse/jetty/server/Response.java
	jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHandler.java
This commit is contained in:
Greg Wilkins 2011-11-29 09:06:25 +11:00
commit 55d5020980
85 changed files with 1645 additions and 1328 deletions

View File

@ -92,7 +92,7 @@ jetty-7.5.3.v20111011 - 11 October 2011
+ 358649 StdErrLog system properties for package/class logging LEVEL.
jetty-7.5.2.v20111006 - 06 October 2011
+ 336443 add missing comma in DigestAuthenticator string
+ 336443 check nonce count is increasing
+ 342161 ScannerTest fails intermittently on Mac OS X
+ 346419 testing HttpClient FDs
+ 353267 Request._parameters initialization bug

View File

@ -216,7 +216,10 @@ public class Ajp13Connection extends BlockingHttpConnection
public void parsedRequestAttribute(String key, Buffer value) throws IOException
{
_request.setAttribute(key, value.toString());
if (value==null)
_request.removeAttribute(key);
else
_request.setAttribute(key,value.toString());
}
public void parsedRequestAttribute(String key, int value) throws IOException

View File

@ -29,7 +29,6 @@ import org.eclipse.jetty.http.HttpSchemes;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.http.HttpVersions;
import org.eclipse.jetty.io.AbstractConnection;
import org.eclipse.jetty.io.AsyncEndPoint;
import org.eclipse.jetty.io.Buffer;
import org.eclipse.jetty.io.Buffers;
import org.eclipse.jetty.io.ByteArrayBuffer;
@ -149,7 +148,7 @@ public abstract class AbstractHttpConnection extends AbstractConnection implemen
}
public abstract Connection handle() throws IOException;
public boolean isIdle()
{
@ -275,7 +274,7 @@ public abstract class AbstractHttpConnection extends AbstractConnection implemen
_endp.close();
return;
}
switch(status)
{
case HttpStatus.CONTINUE_100:
@ -295,7 +294,7 @@ public abstract class AbstractHttpConnection extends AbstractConnection implemen
_status=status;
exchange.getEventListener().onResponseStatus(version,status,reason);
exchange.setStatus(HttpExchange.STATUS_PARSING_HEADERS);
}
@Override
@ -315,8 +314,6 @@ public abstract class AbstractHttpConnection extends AbstractConnection implemen
@Override
public void headerComplete() throws IOException
{
if (_endp instanceof AsyncEndPoint)
((AsyncEndPoint)_endp).scheduleIdle();
HttpExchange exchange = _exchange;
if (exchange!=null)
exchange.setStatus(HttpExchange.STATUS_PARSING_CONTENT);
@ -325,8 +322,6 @@ public abstract class AbstractHttpConnection extends AbstractConnection implemen
@Override
public void content(Buffer ref) throws IOException
{
if (_endp instanceof AsyncEndPoint)
((AsyncEndPoint)_endp).scheduleIdle();
HttpExchange exchange = _exchange;
if (exchange!=null)
exchange.getEventListener().onResponseContent(ref);
@ -353,16 +348,19 @@ public abstract class AbstractHttpConnection extends AbstractConnection implemen
}
}
}
}
@Override
public String toString()
{
return "HttpConnection@" + hashCode() + "//" +
(_destination==null?"?.?.?.?:??":(_destination.getAddress().getHost() + ":" + _destination.getAddress().getPort()))+
",g="+_generator.getState()+",p="+_parser.getState();
return String.format("%s@%x//%s,g=%s,p=%s",
getClass().getSimpleName(),
hashCode(),
_destination == null ? "?.?.?.?:??" : _destination.getAddress(),
_generator,
_parser);
}
public String toDetailString()

View File

@ -122,16 +122,16 @@ public class AsyncHttpConnection extends AbstractHttpConnection implements Async
exchange.getEventListener().onRequestComplete();
}
// Flush output
_endp.flush();
// Read any input that is available
if (!_parser.isComplete() && _parser.parseAvailable())
{
LOG.debug("parsed");
LOG.debug("parsed {}",exchange);
progress=true;
}
// Flush output
_endp.flush();
// Has any IO been done by the endpoint itself since last loop
if (_asyncEndp.hasProgressed())
{
@ -139,10 +139,6 @@ public class AsyncHttpConnection extends AbstractHttpConnection implements Async
progress=true;
}
}
catch (ThreadDeath e)
{
throw e;
}
catch (Throwable e)
{
LOG.debug("Failure on " + _exchange, e);

View File

@ -31,16 +31,14 @@ import org.eclipse.jetty.util.log.Logger;
*/
public class BlockingHttpConnection extends AbstractHttpConnection
{
private static final Logger LOG = Log.getLogger(BlockingHttpConnection.class);
private boolean _requestComplete;
private int _status;
private Buffer _requestContentChunk;
BlockingHttpConnection(Buffers requestBuffers, Buffers responseBuffers, EndPoint endp)
BlockingHttpConnection(Buffers requestBuffers, Buffers responseBuffers, EndPoint endPoint)
{
super(requestBuffers,responseBuffers,endp);
super(requestBuffers, responseBuffers, endPoint);
}
protected void reset() throws IOException
@ -131,19 +129,14 @@ public class BlockingHttpConnection extends AbstractHttpConnection
exchange.getEventListener().onRequestComplete();
}
// Flush output
_endp.flush();
// Read any input that is available
if (!_parser.isComplete() && _parser.parseAvailable())
{
LOG.debug("parsed");
}
}
catch (ThreadDeath e)
{
throw e;
// Flush output
_endp.flush();
}
catch (Throwable e)
{
@ -235,7 +228,6 @@ public class BlockingHttpConnection extends AbstractHttpConnection
if (_exchange==null && !isReserved()) // TODO how do we return switched connections?
_destination.returnConnection(this, !persistent);
}
}
}
}
@ -249,14 +241,6 @@ public class BlockingHttpConnection extends AbstractHttpConnection
return connection;
}
public void onInputShutdown() throws IOException
{
if (_generator.isIdle())
_endp.shutdownOutput();
}
@Override
public boolean send(HttpExchange ex) throws IOException
{

View File

@ -16,6 +16,7 @@ package org.eclipse.jetty.client;
import java.io.IOException;
import java.io.InputStream;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.LinkedList;
import java.util.Set;
@ -164,7 +165,7 @@ public class HttpClient extends HttpBuffers implements Attributes, Dumpable
public void dump(Appendable out, String indent) throws IOException
{
out.append(String.valueOf(this)).append("\n");
AggregateLifeCycle.dump(out,indent,_destinations.values());
AggregateLifeCycle.dump(out,indent,Arrays.asList(_threadPool,_connector),_destinations.values());
}
/* ------------------------------------------------------------------------------- */
@ -190,7 +191,7 @@ public class HttpClient extends HttpBuffers implements Attributes, Dumpable
pool.setName("HttpClient");
_threadPool = pool;
}
return _threadPool;
}

View File

@ -439,14 +439,7 @@ public class HttpDestination implements Dumpable
public void returnIdleConnection(AbstractHttpConnection connection)
{
try
{
connection.close();
}
catch (IOException e)
{
LOG.ignore(e);
}
connection.onIdleExpired();
boolean startConnection = false;
synchronized (this)

View File

@ -18,8 +18,10 @@ import java.net.SocketTimeoutException;
import java.nio.channels.SelectionKey;
import java.nio.channels.SocketChannel;
import java.nio.channels.UnresolvedAddressException;
import java.util.Arrays;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import javax.net.ssl.SSLEngine;
import org.eclipse.jetty.io.AsyncEndPoint;
@ -31,13 +33,15 @@ import org.eclipse.jetty.io.nio.SelectChannelEndPoint;
import org.eclipse.jetty.io.nio.SelectorManager;
import org.eclipse.jetty.io.nio.SslConnection;
import org.eclipse.jetty.util.component.AbstractLifeCycle;
import org.eclipse.jetty.util.component.AggregateLifeCycle;
import org.eclipse.jetty.util.component.Dumpable;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.eclipse.jetty.util.thread.Timeout;
import org.eclipse.jetty.util.thread.Timeout.Task;
class SelectConnector extends AbstractLifeCycle implements HttpClient.Connector
class SelectConnector extends AbstractLifeCycle implements HttpClient.Connector, Dumpable
{
private static final Logger LOG = Log.getLogger(SelectConnector.class);
@ -69,6 +73,17 @@ class SelectConnector extends AbstractLifeCycle implements HttpClient.Connector
_selectorManager.stop();
}
public String dump()
{
return AggregateLifeCycle.dump(this);
}
public void dump(Appendable out, String indent) throws IOException
{
out.append(String.valueOf(this)).append("\n");
AggregateLifeCycle.dump(out, indent, Arrays.asList(_selectorManager));
}
/* ------------------------------------------------------------ */
public void startConnection( HttpDestination destination )
throws IOException
@ -155,10 +170,8 @@ class SelectConnector extends AbstractLifeCycle implements HttpClient.Connector
// key should have destination at this point (will be replaced by endpoint after this call)
HttpDestination dest=(HttpDestination)key.attachment();
AsyncEndPoint ep=null;
SelectChannelEndPoint scep= new SelectChannelEndPoint(channel, selectSet, key, (int)_httpClient.getIdleTimeout());
ep = scep;
SelectChannelEndPoint scep = new SelectChannelEndPoint(channel, selectSet, key, (int)_httpClient.getIdleTimeout());
AsyncEndPoint ep = scep;
if (dest.isSecure())
{
@ -262,10 +275,10 @@ class SelectConnector extends AbstractLifeCycle implements HttpClient.Connector
public void upgrade()
{
AsyncHttpConnection connection = (AsyncHttpConnection) ((SelectChannelEndPoint)_endp).getConnection();
AsyncHttpConnection connection = (AsyncHttpConnection)_endp.getConnection();
SslConnection sslConnection = new SslConnection(_engine,_endp);
((SelectChannelEndPoint)_endp).setConnection(sslConnection);
_endp.setConnection(sslConnection);
_endp=sslConnection.getSslEndPoint();
sslConnection.getSslEndPoint().setConnection(connection);
@ -319,21 +332,11 @@ class SelectConnector extends AbstractLifeCycle implements HttpClient.Connector
_endp.close();
}
public void scheduleIdle()
{
_endp.scheduleIdle();
}
public int fill(Buffer buffer) throws IOException
{
return _endp.fill(buffer);
}
public void cancelIdle()
{
_endp.cancelIdle();
}
public boolean isWritable()
{
return _endp.isWritable();
@ -434,9 +437,25 @@ class SelectConnector extends AbstractLifeCycle implements HttpClient.Connector
_endp.setMaxIdleTime(timeMs);
}
public void onIdleExpired()
{
_endp.onIdleExpired();
}
public void setCheckForIdle(boolean check)
{
_endp.setCheckForIdle(check);
}
public boolean isCheckForIdle()
{
return _endp.isCheckForIdle();
}
public String toString()
{
return "Upgradable:"+_endp.toString();
}
}
}

View File

@ -14,8 +14,11 @@
package org.eclipse.jetty.client;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import java.io.IOException;
import java.net.SocketTimeoutException;

View File

@ -40,9 +40,9 @@ public class AsyncSslHttpExchangeTest extends SslHttpExchangeTest
@Override
public void testGetWithContentExchange() throws Exception
public void testBigPostWithContentExchange() throws Exception
{
super.testGetWithContentExchange();
super.testBigPostWithContentExchange();
}
}

View File

@ -1,8 +1,6 @@
package org.eclipse.jetty.client;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;

View File

@ -16,7 +16,6 @@ package org.eclipse.jetty.client;
import org.eclipse.jetty.client.helperClasses.ExternalKeyStoreAsyncSslServerAndClientCreator;
import org.eclipse.jetty.client.helperClasses.ServerAndClientCreator;
import org.junit.Before;
import org.junit.Test;
public class ExternalKeyStoreAsyncSslHttpExchangeTest extends SslHttpExchangeTest
{
@ -30,12 +29,4 @@ public class ExternalKeyStoreAsyncSslHttpExchangeTest extends SslHttpExchangeTes
_httpClient = serverAndClientCreator.createClient(3000L,3500L,2000);
_port = _server.getConnectors()[0].getLocalPort();
}
@Override
@Test
public void testBigPostWithContentExchange() throws Exception
{
super.testBigPostWithContentExchange();
}
}

View File

@ -38,7 +38,6 @@ import org.eclipse.jetty.http.HttpStatus;
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.EofException;
import org.eclipse.jetty.io.nio.DirectNIOBuffer;
import org.eclipse.jetty.server.Server;
@ -62,7 +61,7 @@ public class HttpExchangeTest
protected static HttpClient _httpClient;
protected static AtomicInteger _count = new AtomicInteger();
protected static ServerAndClientCreator serverAndClientCreator = new HttpServerAndClientCreator();
protected static URI getBaseURI()
{
return URI.create(_scheme + "://localhost:" + _port + "/");
@ -123,7 +122,7 @@ public class HttpExchangeTest
/* ------------------------------------------------------------ */
/**
* Test sending data through the exchange.
*
*
* @throws IOException
*/
public void sender(final int nb, final boolean close) throws Exception
@ -262,12 +261,12 @@ public class HttpExchangeTest
_httpClient.send(httpExchange[n]);
}
if (!complete.await(2,TimeUnit.SECONDS))
System.err.println(_httpClient.dump());
assertTrue(complete.await(20,TimeUnit.SECONDS));
assertEquals("nb="+nb+" close="+close,0,allcontent.get());
}
@ -301,7 +300,7 @@ public class HttpExchangeTest
httpExchange.setURI(uri);
httpExchange.setMethod(HttpMethods.GET);
_httpClient.send(httpExchange);
int status = httpExchange.waitForDone();
int status = httpExchange.waitForDone();
//httpExchange.waitForStatus(HttpExchange.STATUS_COMPLETED);
String result=httpExchange.getResponseContent();
assertNotNull("Should have received response content", result);
@ -311,7 +310,7 @@ public class HttpExchangeTest
Thread.sleep(5);
}
}
/* ------------------------------------------------------------ */
@Test
public void testLocalAddressAvailabilityWithContentExchange() throws Exception
@ -324,9 +323,9 @@ public class HttpExchangeTest
httpExchange.setMethod(HttpMethods.GET);
_httpClient.send(httpExchange);
int status = httpExchange.waitForDone();
assertNotNull(httpExchange.getLocalAddress());
String result=httpExchange.getResponseContent();
assertNotNull("Should have received response content", result);
assertEquals("i="+i,0,result.indexOf("<hello>"));
@ -335,13 +334,13 @@ public class HttpExchangeTest
Thread.sleep(5);
}
}
/* ------------------------------------------------------------ */
@Test
public void testShutdownWithExchange() throws Exception
{
final AtomicReference<Throwable> throwable=new AtomicReference<Throwable>();
HttpExchange httpExchange=new HttpExchange()
{
@ -373,8 +372,8 @@ public class HttpExchangeTest
@Override
public void run()
{
try {
Thread.sleep(500);
try {
Thread.sleep(500);
_httpClient.stop();
} catch(Exception e) {e.printStackTrace();}
}
@ -390,12 +389,12 @@ public class HttpExchangeTest
/* ------------------------------------------------------------ */
@Test
public void testBigPostWithContentExchange() throws Exception
{
{
int size =32;
ContentExchange httpExchange=new ContentExchange()
{
int total;
@Override
protected synchronized void onResponseStatus(Buffer version, int status, Buffer reason) throws IOException
{
@ -438,7 +437,7 @@ public class HttpExchangeTest
System.err.println("] --");
super.onResponseHeaderComplete();
}
};
Buffer babuf = new ByteArrayBuffer(size*36*1024);
@ -451,13 +450,28 @@ public class HttpExchangeTest
babuf.put(bytes);
niobuf.put(bytes);
}
httpExchange.setURI(getBaseURI());
httpExchange.setMethod(HttpMethods.POST);
httpExchange.setRequestContentType("application/data");
httpExchange.setRequestContent(babuf);
_httpClient.send(httpExchange);
long start=System.currentTimeMillis();
while(!httpExchange.isDone())
{
long now=System.currentTimeMillis();
if ((now-start)>=10000)
{
System.err.println("TEST IS TAKING TOOOOO LONG!!!!!!!!!!!!!!!!!!!!");
System.err.println("CLIENT:");
System.err.println(_httpClient.dump());
System.err.println("SERVER:");
_server.dumpStdErr();
break;
}
Thread.sleep(100);
}
int status = httpExchange.waitForDone();
assertEquals(HttpExchange.STATUS_COMPLETED,status);
String result=httpExchange.getResponseContent();
@ -469,6 +483,22 @@ public class HttpExchangeTest
httpExchange.setRequestContentType("application/data");
httpExchange.setRequestContent(niobuf);
_httpClient.send(httpExchange);
start=System.currentTimeMillis();
while(!httpExchange.isDone())
{
long now=System.currentTimeMillis();
if ((now-start)>=10000)
{
System.err.println("TEST IS TAKING TOOOOO LONG!!!!!!!!!!!!!!!!!!!!");
System.err.println("CLIENT:");
System.err.println(_httpClient.dump());
System.err.println("SERVER:");
_server.dumpStdErr();
break;
}
Thread.sleep(100);
}
status = httpExchange.waitForDone();
assertEquals(HttpExchange.STATUS_COMPLETED, status);
result=httpExchange.getResponseContent();
@ -605,13 +635,13 @@ public class HttpExchangeTest
// reserving one should now work
c = destination.reserveConnection(500);
assertNotNull(c);
// release connections
for (AbstractHttpConnection httpConnection : connections){
destination.returnConnection(httpConnection,false);
}
}
@Test
public void testOptionsWithExchange() throws Exception
{
@ -621,15 +651,15 @@ public class HttpExchangeTest
httpExchange.setMethod(HttpMethods.OPTIONS);
// httpExchange.setRequestHeader("Connection","close");
_httpClient.send(httpExchange);
int state = httpExchange.waitForDone();
assertEquals(HttpExchange.STATUS_COMPLETED, state);
assertEquals(HttpStatus.OK_200,httpExchange.getResponseStatus());
HttpFields headers = httpExchange.getResponseFields();
HttpAsserts.assertContainsHeaderKey("Content-Length", headers);
assertEquals("Content-Length header value", 0, headers.getLongField("Content-Length"));
HttpAsserts.assertContainsHeaderKey("Allow",headers);
String allow = headers.getStringField("Allow");
String expectedMethods[] =

View File

@ -13,8 +13,11 @@
package org.eclipse.jetty.client;
import static org.junit.Assert.assertEquals;
import java.io.IOException;
import java.net.ProtocolException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@ -29,8 +32,6 @@ import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
/* ------------------------------------------------------------ */
/**
* This UnitTest class executes two tests. Both will send a http request to https://google.com through a misbehaving proxy server.

View File

@ -3,8 +3,6 @@ package org.eclipse.jetty.client;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Random;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
@ -13,8 +11,6 @@ import javax.servlet.http.HttpServletResponse;
import junit.framework.Assert;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.HttpExchange;
import org.eclipse.jetty.http.HttpHeaderValues;
import org.eclipse.jetty.http.HttpHeaders;
import org.eclipse.jetty.io.Buffer;

View File

@ -0,0 +1,148 @@
package org.eclipse.jetty.client;
import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLSocket;
import org.eclipse.jetty.http.HttpMethods;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
public class SslBytesClientTest extends SslBytesTest
{
private ExecutorService threadPool;
private HttpClient client;
private SimpleProxy proxy;
private SSLServerSocket acceptor;
@Before
public void init() throws Exception
{
threadPool = Executors.newCachedThreadPool();
client = new HttpClient();
client.setMaxConnectionsPerAddress(1);
client.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL);
File keyStore = MavenTestingUtils.getTestResourceFile("keystore");
SslContextFactory cf = client.getSslContextFactory();
cf.setKeyStorePath(keyStore.getAbsolutePath());
cf.setKeyStorePassword("storepwd");
cf.setKeyManagerPassword("keypwd");
client.start();
SSLContext sslContext = cf.getSslContext();
acceptor = (SSLServerSocket)sslContext.getServerSocketFactory().createServerSocket(0);
int serverPort = acceptor.getLocalPort();
proxy = new SimpleProxy(threadPool, "localhost", serverPort);
proxy.start();
logger.debug(":{} <==> :{}", proxy.getPort(), serverPort);
}
@After
public void destroy() throws Exception
{
if (acceptor != null)
acceptor.close();
if (proxy != null)
proxy.stop();
if (client != null)
client.stop();
if (threadPool != null)
threadPool.shutdownNow();
}
@Test
public void testHandshake() throws Exception
{
ContentExchange exchange = new ContentExchange(true);
exchange.setURL("https://localhost:" + proxy.getPort());
String method = HttpMethods.GET;
exchange.setMethod(method);
client.send(exchange);
Assert.assertTrue(proxy.awaitClient(5, TimeUnit.SECONDS));
final SSLSocket server = (SSLSocket)acceptor.accept();
server.setUseClientMode(false);
Future<Object> handshake = threadPool.submit(new Callable<Object>()
{
public Object call() throws Exception
{
server.startHandshake();
return null;
}
});
// Client Hello
TLSRecord record = proxy.readFromClient();
Assert.assertEquals(TLSRecord.Type.HANDSHAKE, record.getType());
proxy.flushToServer(record);
// Server Hello + Certificate + Server Done
record = proxy.readFromServer();
Assert.assertEquals(TLSRecord.Type.HANDSHAKE, record.getType());
proxy.flushToClient(record);
// Client Key Exchange
record = proxy.readFromClient();
Assert.assertEquals(TLSRecord.Type.HANDSHAKE, record.getType());
proxy.flushToServer(record);
// Change Cipher Spec
record = proxy.readFromClient();
Assert.assertEquals(TLSRecord.Type.CHANGE_CIPHER_SPEC, record.getType());
proxy.flushToServer(record);
// Client Done
record = proxy.readFromClient();
Assert.assertEquals(TLSRecord.Type.HANDSHAKE, record.getType());
proxy.flushToServer(record);
// Change Cipher Spec
record = proxy.readFromServer();
Assert.assertEquals(TLSRecord.Type.CHANGE_CIPHER_SPEC, record.getType());
proxy.flushToClient(record);
// Server Done
record = proxy.readFromServer();
Assert.assertEquals(TLSRecord.Type.HANDSHAKE, record.getType());
proxy.flushToClient(record);
Assert.assertNull(handshake.get(5, TimeUnit.SECONDS));
SimpleProxy.AutomaticFlow automaticProxyFlow = proxy.startAutomaticFlow();
// Read request
BufferedReader reader = new BufferedReader(new InputStreamReader(server.getInputStream(), "UTF-8"));
String line = reader.readLine();
Assert.assertTrue(line.startsWith(method));
while (line.length() > 0)
line = reader.readLine();
// Write response
OutputStream output = server.getOutputStream();
output.write(("HTTP/1.1 200 OK\r\n" +
"Content-Length: 0\r\n" +
"\r\n").getBytes("UTF-8"));
output.flush();
Assert.assertTrue(automaticProxyFlow.stop(5, TimeUnit.SECONDS));
Assert.assertEquals(HttpExchange.STATUS_COMPLETED, exchange.waitForDone());
Assert.assertEquals(HttpStatus.OK_200, exchange.getResponseStatus());
}
}

View File

@ -1,27 +1,25 @@
package org.eclipse.jetty.client;
import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.Matchers.lessThan;
import java.io.BufferedReader;
import java.io.EOFException;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.InterruptedIOException;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.nio.channels.SocketChannel;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLSocket;
@ -42,20 +40,16 @@ import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.AbstractHandler;
import org.eclipse.jetty.server.ssl.SslSelectChannelConnector;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.junit.After;
import org.junit.Assert;
import org.junit.Assume;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import static org.hamcrest.Matchers.lessThan;
public class SslBytesServerTest
public class SslBytesServerTest extends SslBytesTest
{
private final Logger logger = Log.getLogger(getClass());
private final AtomicInteger sslHandles = new AtomicInteger();
private final AtomicInteger httpParses = new AtomicInteger();
private ExecutorService threadPool;
@ -64,7 +58,7 @@ public class SslBytesServerTest
private SimpleProxy proxy;
@Before
public void startServer() throws Exception
public void init() throws Exception
{
threadPool = Executors.newCachedThreadPool();
server = new Server();
@ -107,7 +101,8 @@ public class SslBytesServerTest
}
};
connector.setPort(5870); // TODO: make this random
// connector.setPort(5870);
connector.setPort(0);
File keyStore = MavenTestingUtils.getTestResourceFile("keystore");
SslContextFactory cf = connector.getSslContextFactory();
@ -131,16 +126,17 @@ public class SslBytesServerTest
}
});
server.start();
int serverPort = connector.getLocalPort();
sslContext = cf.getSslContext();
proxy = new SimpleProxy(threadPool, "localhost", connector.getLocalPort());
proxy = new SimpleProxy(threadPool, "localhost", serverPort);
proxy.start();
logger.debug(":{} <==> :{}", proxy.getPort(), connector.getLocalPort());
logger.debug(":{} <==> :{}", proxy.getPort(), serverPort);
}
@After
public void stopServer() throws Exception
public void destroy() throws Exception
{
if (proxy != null)
proxy.stop();
@ -466,7 +462,7 @@ public class SslBytesServerTest
}
// Check that we did not spin
Assert.assertThat(sslHandles.get(), lessThan(500));
Assert.assertThat(sslHandles.get(), lessThan(750));
Assert.assertThat(httpParses.get(), lessThan(150));
client.close();
@ -867,7 +863,7 @@ public class SslBytesServerTest
// Check that we did not spin
Assert.assertThat(sslHandles.get(), lessThan(20));
Assert.assertThat(httpParses.get(), lessThan(50));
Assert.assertThat(httpParses.get(), lessThan(150));
Assert.assertNull(request.get(5, TimeUnit.SECONDS));
@ -887,7 +883,7 @@ public class SslBytesServerTest
// Check that we did not spin
Assert.assertThat(sslHandles.get(), lessThan(20));
Assert.assertThat(httpParses.get(), lessThan(50));
Assert.assertThat(httpParses.get(), lessThan(150));
closeClient(client);
}
@ -895,6 +891,8 @@ public class SslBytesServerTest
@Test
public void testRequestWithBigContentWithRenegotiationInMiddleOfContent() throws Exception
{
assumeJavaVersionSupportsTLSRenegotiations();
final SSLSocket client = newClient();
final OutputStream clientOutput = client.getOutputStream();
@ -934,10 +932,12 @@ public class SslBytesServerTest
// Renegotiation Handshake
TLSRecord record = proxy.readFromClient();
Assert.assertEquals(TLSRecord.Type.HANDSHAKE, record.getType());
proxy.flushToServer(record);
// Renegotiation Handshake
record = proxy.readFromServer();
Assert.assertEquals(TLSRecord.Type.HANDSHAKE, record.getType());
proxy.flushToClient(record);
// Renegotiation Change Cipher
@ -947,6 +947,7 @@ public class SslBytesServerTest
// Renegotiation Handshake
record = proxy.readFromServer();
Assert.assertEquals(TLSRecord.Type.HANDSHAKE, record.getType());
proxy.flushToClient(record);
// Trigger a read to have the client write the final renegotiation steps
@ -968,6 +969,7 @@ public class SslBytesServerTest
// Renegotiation Handshake
record = proxy.readFromClient();
Assert.assertEquals(TLSRecord.Type.HANDSHAKE, record.getType());
proxy.flushToServer(record);
Assert.assertNull(renegotiation.get(5, TimeUnit.SECONDS));
@ -1019,6 +1021,8 @@ public class SslBytesServerTest
@Test
public void testRequestWithBigContentWithRenegotiationInMiddleOfContentWithSplitBoundary() throws Exception
{
assumeJavaVersionSupportsTLSRenegotiations();
final SSLSocket client = newClient();
final OutputStream clientOutput = client.getOutputStream();
@ -1058,6 +1062,7 @@ public class SslBytesServerTest
// Renegotiation Handshake
TLSRecord record = proxy.readFromClient();
Assert.assertEquals(TLSRecord.Type.HANDSHAKE, record.getType());
byte[] bytes = record.getBytes();
byte[] chunk1 = new byte[2 * bytes.length / 3];
System.arraycopy(bytes, 0, chunk1, 0, chunk1.length);
@ -1070,6 +1075,7 @@ public class SslBytesServerTest
// Renegotiation Handshake
record = proxy.readFromServer();
Assert.assertEquals(TLSRecord.Type.HANDSHAKE, record.getType());
proxy.flushToClient(record);
// Renegotiation Change Cipher
@ -1079,6 +1085,7 @@ public class SslBytesServerTest
// Renegotiation Handshake
record = proxy.readFromServer();
Assert.assertEquals(TLSRecord.Type.HANDSHAKE, record.getType());
proxy.flushToClient(record);
// Trigger a read to have the client write the final renegotiation steps
@ -1169,11 +1176,25 @@ public class SslBytesServerTest
// Check that we did not spin
Assert.assertThat(sslHandles.get(), lessThan(20));
Assert.assertThat(httpParses.get(), lessThan(50));
Assert.assertThat(httpParses.get(), lessThan(100));
closeClient(client);
}
private void assumeJavaVersionSupportsTLSRenegotiations()
{
// Due to a security bug, TLS renegotiations were disabled in JDK 1.6.0_19-21
// so we check the java version in order to avoid to fail the test.
String javaVersion = System.getProperty("java.version");
Pattern regexp = Pattern.compile("1\\.6\\.0_(\\d{2})");
Matcher matcher = regexp.matcher(javaVersion);
if (matcher.matches())
{
String nano = matcher.group(1);
Assume.assumeThat(Integer.parseInt(nano), greaterThan(21));
}
}
private SSLSocket newClient() throws IOException, InterruptedException
{
SSLSocket client = (SSLSocket)sslContext.getSocketFactory().createSocket("localhost", proxy.getPort());
@ -1203,314 +1224,4 @@ public class SslBytesServerTest
proxy.flushToClient(record);
}
public class SimpleProxy implements Runnable
{
private final CountDownLatch latch = new CountDownLatch(1);
private final ExecutorService threadPool;
private final String serverHost;
private final int serverPort;
private volatile ServerSocket serverSocket;
private volatile Socket server;
private volatile Socket client;
public SimpleProxy(ExecutorService threadPool, String serverHost, int serverPort)
{
this.threadPool = threadPool;
this.serverHost = serverHost;
this.serverPort = serverPort;
}
public void start() throws Exception
{
serverSocket = new ServerSocket(5871); // TODO: make this random
Thread acceptor = new Thread(this);
acceptor.start();
server = new Socket(serverHost, serverPort);
}
public void stop() throws Exception
{
serverSocket.close();
}
public void run()
{
try
{
client = serverSocket.accept();
latch.countDown();
}
catch (IOException x)
{
x.printStackTrace();
}
}
public int getPort()
{
return serverSocket.getLocalPort();
}
public TLSRecord readFromClient() throws IOException
{
TLSRecord record = read(client);
logger.debug("C --> P {}", record);
return record;
}
private TLSRecord read(Socket socket) throws IOException
{
InputStream input = socket.getInputStream();
int first = -2;
while (true)
{
try
{
socket.setSoTimeout(500);
first = input.read();
break;
}
catch (SocketTimeoutException x)
{
if (Thread.currentThread().isInterrupted())
break;
}
}
if (first == -2)
throw new InterruptedIOException();
else if (first == -1)
return null;
if (first >= 0x80)
{
// SSLv2 Record
int hiLength = first & 0x3F;
int loLength = input.read();
int length = (hiLength << 8) + loLength;
byte[] bytes = new byte[2 + length];
bytes[0] = (byte)first;
bytes[1] = (byte)loLength;
return read(TLSRecord.Type.HANDSHAKE, input, bytes, 2, length);
}
else
{
// TLS Record
int major = input.read();
int minor = input.read();
int hiLength = input.read();
int loLength = input.read();
int length = (hiLength << 8) + loLength;
byte[] bytes = new byte[1 + 2 + 2 + length];
bytes[0] = (byte)first;
bytes[1] = (byte)major;
bytes[2] = (byte)minor;
bytes[3] = (byte)hiLength;
bytes[4] = (byte)loLength;
return read(TLSRecord.Type.from(first), input, bytes, 5, length);
}
}
private TLSRecord read(TLSRecord.Type type, InputStream input, byte[] bytes, int offset, int length) throws IOException
{
while (length > 0)
{
int read = input.read(bytes, offset, length);
if (read < 0)
throw new EOFException();
offset += read;
length -= read;
}
return new TLSRecord(type, bytes);
}
public void flushToServer(TLSRecord record) throws IOException
{
if (record == null)
{
server.shutdownOutput();
if (client.isOutputShutdown())
{
client.close();
server.close();
}
}
else
{
flush(server, record.getBytes());
}
}
public void flushToServer(byte... bytes) throws IOException
{
flush(server, bytes);
}
private void flush(Socket socket, byte... bytes) throws IOException
{
OutputStream output = socket.getOutputStream();
output.write(bytes);
output.flush();
}
public TLSRecord readFromServer() throws IOException
{
TLSRecord record = read(server);
logger.debug("P <-- S {}", record);
return record;
}
public void flushToClient(TLSRecord record) throws IOException
{
if (record == null)
{
client.shutdownOutput();
if (server.isOutputShutdown())
{
server.close();
client.close();
}
}
else
{
flush(client, record.getBytes());
}
}
public AutomaticFlow startAutomaticFlow() throws InterruptedException
{
final CountDownLatch startLatch = new CountDownLatch(2);
final CountDownLatch stopLatch = new CountDownLatch(2);
Future<Object> clientToServer = threadPool.submit(new Callable<Object>()
{
public Object call() throws Exception
{
startLatch.countDown();
logger.debug("Automatic flow C --> S started");
try
{
while (true)
{
flushToServer(readFromClient());
}
}
catch (InterruptedIOException x)
{
return null;
}
finally
{
stopLatch.countDown();
logger.debug("Automatic flow C --> S finished");
}
}
});
Future<Object> serverToClient = threadPool.submit(new Callable<Object>()
{
public Object call() throws Exception
{
startLatch.countDown();
logger.debug("Automatic flow C <-- S started");
try
{
while (true)
{
flushToClient(readFromServer());
}
}
catch (InterruptedIOException x)
{
return null;
}
finally
{
stopLatch.countDown();
logger.debug("Automatic flow C <-- S finished");
}
}
});
Assert.assertTrue(startLatch.await(5, TimeUnit.SECONDS));
return new AutomaticFlow(stopLatch, clientToServer, serverToClient);
}
public boolean awaitClient(int time, TimeUnit unit) throws InterruptedException
{
return latch.await(time, unit);
}
public class AutomaticFlow
{
private final CountDownLatch stopLatch;
private final Future<Object> clientToServer;
private final Future<Object> serverToClient;
public AutomaticFlow(CountDownLatch stopLatch, Future<Object> clientToServer, Future<Object> serverToClient)
{
this.stopLatch = stopLatch;
this.clientToServer = clientToServer;
this.serverToClient = serverToClient;
}
public boolean stop(long time, TimeUnit unit) throws InterruptedException
{
clientToServer.cancel(true);
serverToClient.cancel(true);
return stopLatch.await(time, unit);
}
}
}
public static class TLSRecord
{
private final Type type;
private final byte[] bytes;
public TLSRecord(Type type, byte[] bytes)
{
this.type = type;
this.bytes = bytes;
}
public Type getType()
{
return type;
}
public byte[] getBytes()
{
return bytes;
}
@Override
public String toString()
{
return "TLSRecord [" + type + "] " + bytes.length + " bytes";
}
public enum Type
{
CHANGE_CIPHER_SPEC(20), ALERT(21), HANDSHAKE(22), APPLICATION(23);
private int code;
private Type(int code)
{
this.code = code;
Mapper.codes.put(this.code, this);
}
public static Type from(int code)
{
Type result = Mapper.codes.get(code);
if (result == null)
throw new IllegalArgumentException("Invalid TLSRecord.Type " + code);
return result;
}
private static class Mapper
{
private static final Map<Integer, Type> codes = new HashMap<Integer, Type>();
}
}
}
}

View File

@ -0,0 +1,337 @@
package org.eclipse.jetty.client;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InterruptedIOException;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.junit.Assert;
public abstract class SslBytesTest
{
protected final Logger logger = Log.getLogger(getClass());
public static class TLSRecord
{
private final SslBytesServerTest.TLSRecord.Type type;
private final byte[] bytes;
public TLSRecord(SslBytesServerTest.TLSRecord.Type type, byte[] bytes)
{
this.type = type;
this.bytes = bytes;
}
public SslBytesServerTest.TLSRecord.Type getType()
{
return type;
}
public byte[] getBytes()
{
return bytes;
}
@Override
public String toString()
{
return "TLSRecord [" + type + "] " + bytes.length + " bytes";
}
public enum Type
{
CHANGE_CIPHER_SPEC(20), ALERT(21), HANDSHAKE(22), APPLICATION(23);
private int code;
private Type(int code)
{
this.code = code;
SslBytesServerTest.TLSRecord.Type.Mapper.codes.put(this.code, this);
}
public static SslBytesServerTest.TLSRecord.Type from(int code)
{
SslBytesServerTest.TLSRecord.Type result = SslBytesServerTest.TLSRecord.Type.Mapper.codes.get(code);
if (result == null)
throw new IllegalArgumentException("Invalid TLSRecord.Type " + code);
return result;
}
private static class Mapper
{
private static final Map<Integer, SslBytesServerTest.TLSRecord.Type> codes = new HashMap<Integer, SslBytesServerTest.TLSRecord.Type>();
}
}
}
public class SimpleProxy implements Runnable
{
private final CountDownLatch latch = new CountDownLatch(1);
private final ExecutorService threadPool;
private final String serverHost;
private final int serverPort;
private volatile ServerSocket serverSocket;
private volatile Socket server;
private volatile Socket client;
public SimpleProxy(ExecutorService threadPool, String serverHost, int serverPort)
{
this.threadPool = threadPool;
this.serverHost = serverHost;
this.serverPort = serverPort;
}
public void start() throws Exception
{
// serverSocket = new ServerSocket(5871);
serverSocket = new ServerSocket(0);
Thread acceptor = new Thread(this);
acceptor.start();
server = new Socket(serverHost, serverPort);
}
public void stop() throws Exception
{
serverSocket.close();
}
public void run()
{
try
{
client = serverSocket.accept();
latch.countDown();
}
catch (IOException x)
{
x.printStackTrace();
}
}
public int getPort()
{
return serverSocket.getLocalPort();
}
public TLSRecord readFromClient() throws IOException
{
TLSRecord record = read(client);
logger.debug("C --> P {}", record);
return record;
}
private TLSRecord read(Socket socket) throws IOException
{
InputStream input = socket.getInputStream();
int first = -2;
while (true)
{
try
{
socket.setSoTimeout(500);
first = input.read();
break;
}
catch (SocketTimeoutException x)
{
if (Thread.currentThread().isInterrupted())
break;
}
}
if (first == -2)
throw new InterruptedIOException();
else if (first == -1)
return null;
if (first >= 0x80)
{
// SSLv2 Record
int hiLength = first & 0x3F;
int loLength = input.read();
int length = (hiLength << 8) + loLength;
byte[] bytes = new byte[2 + length];
bytes[0] = (byte)first;
bytes[1] = (byte)loLength;
return read(TLSRecord.Type.HANDSHAKE, input, bytes, 2, length);
}
else
{
// TLS Record
int major = input.read();
int minor = input.read();
int hiLength = input.read();
int loLength = input.read();
int length = (hiLength << 8) + loLength;
byte[] bytes = new byte[1 + 2 + 2 + length];
bytes[0] = (byte)first;
bytes[1] = (byte)major;
bytes[2] = (byte)minor;
bytes[3] = (byte)hiLength;
bytes[4] = (byte)loLength;
return read(TLSRecord.Type.from(first), input, bytes, 5, length);
}
}
private TLSRecord read(SslBytesServerTest.TLSRecord.Type type, InputStream input, byte[] bytes, int offset, int length) throws IOException
{
while (length > 0)
{
int read = input.read(bytes, offset, length);
if (read < 0)
throw new EOFException();
offset += read;
length -= read;
}
return new TLSRecord(type, bytes);
}
public void flushToServer(TLSRecord record) throws IOException
{
if (record == null)
{
server.shutdownOutput();
if (client.isOutputShutdown())
{
client.close();
server.close();
}
}
else
{
flush(server, record.getBytes());
}
}
public void flushToServer(byte... bytes) throws IOException
{
flush(server, bytes);
}
private void flush(Socket socket, byte... bytes) throws IOException
{
OutputStream output = socket.getOutputStream();
output.write(bytes);
output.flush();
}
public TLSRecord readFromServer() throws IOException
{
TLSRecord record = read(server);
logger.debug("P <-- S {}", record);
return record;
}
public void flushToClient(TLSRecord record) throws IOException
{
if (record == null)
{
client.shutdownOutput();
if (server.isOutputShutdown())
{
server.close();
client.close();
}
}
else
{
flush(client, record.getBytes());
}
}
public SslBytesServerTest.SimpleProxy.AutomaticFlow startAutomaticFlow() throws InterruptedException
{
final CountDownLatch startLatch = new CountDownLatch(2);
final CountDownLatch stopLatch = new CountDownLatch(2);
Future<Object> clientToServer = threadPool.submit(new Callable<Object>()
{
public Object call() throws Exception
{
startLatch.countDown();
logger.debug("Automatic flow C --> S started");
try
{
while (true)
{
flushToServer(readFromClient());
}
}
catch (InterruptedIOException x)
{
return null;
}
finally
{
stopLatch.countDown();
logger.debug("Automatic flow C --> S finished");
}
}
});
Future<Object> serverToClient = threadPool.submit(new Callable<Object>()
{
public Object call() throws Exception
{
startLatch.countDown();
logger.debug("Automatic flow C <-- S started");
try
{
while (true)
{
flushToClient(readFromServer());
}
}
catch (InterruptedIOException x)
{
return null;
}
finally
{
stopLatch.countDown();
logger.debug("Automatic flow C <-- S finished");
}
}
});
Assert.assertTrue(startLatch.await(5, TimeUnit.SECONDS));
return new SslBytesServerTest.SimpleProxy.AutomaticFlow(stopLatch, clientToServer, serverToClient);
}
public boolean awaitClient(int time, TimeUnit unit) throws InterruptedException
{
return latch.await(time, unit);
}
public class AutomaticFlow
{
private final CountDownLatch stopLatch;
private final Future<Object> clientToServer;
private final Future<Object> serverToClient;
public AutomaticFlow(CountDownLatch stopLatch, Future<Object> clientToServer, Future<Object> serverToClient)
{
this.stopLatch = stopLatch;
this.clientToServer = clientToServer;
this.serverToClient = serverToClient;
}
public boolean stop(long time, TimeUnit unit) throws InterruptedException
{
clientToServer.cancel(true);
serverToClient.cancel(true);
return stopLatch.await(time, unit);
}
}
}
}

View File

@ -19,8 +19,6 @@ import static org.hamcrest.Matchers.not;
import org.eclipse.jetty.client.helperClasses.ServerAndClientCreator;
import org.eclipse.jetty.client.helperClasses.SslServerAndClientCreator;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.toolchain.test.OS;
import org.eclipse.jetty.toolchain.test.Stress;
import org.junit.Assume;
import org.junit.Before;
import org.junit.Test;

View File

@ -20,6 +20,7 @@ import java.io.OutputStream;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

View File

@ -16,7 +16,6 @@ package org.eclipse.jetty.client.helperClasses;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ssl.SslSelectChannelConnector;
import org.eclipse.jetty.server.ssl.SslSocketConnector;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
import org.eclipse.jetty.util.log.Log;

View File

@ -1,7 +1,5 @@
package org.eclipse.jetty.client.helperClasses;
import java.io.FileInputStream;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;

View File

@ -23,7 +23,7 @@ public class Jetty6Continuation implements ContinuationFilter.FilteredContinuati
// Exception reused for all continuations
// Turn on debug in ContinuationFilter to see real stack trace.
private final static ContinuationThrowable __exception = new ContinuationThrowable();
private final ServletRequest _request;
private ServletResponse _response;
private final org.mortbay.util.ajax.Continuation _j6Continuation;
@ -66,7 +66,7 @@ public class Jetty6Continuation implements ContinuationFilter.FilteredContinuati
_j6Continuation.resume();
}
}
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.continuation.Continuation#getAttribute(java.lang.String)
@ -233,8 +233,6 @@ public class Jetty6Continuation implements ContinuationFilter.FilteredContinuati
Throwable th=_retry;
_retry=null;
if (th instanceof ThreadDeath)
throw (ThreadDeath)th;
if (th instanceof Error)
throw (Error)th;
if (th instanceof RuntimeException)
@ -245,7 +243,7 @@ public class Jetty6Continuation implements ContinuationFilter.FilteredContinuati
for (ContinuationListener l: _listeners)
l.onComplete(this);
}
return true;
}
}

View File

@ -24,7 +24,7 @@ import org.eclipse.jetty.util.component.AbstractLifeCycle;
*/
public class HttpBuffers extends AbstractLifeCycle
{
private int _requestBufferSize=12*1024;
private int _requestBufferSize=16*1024;
private int _requestHeaderSize=6*1024;
private int _responseBufferSize=32*1024;
private int _responseHeaderSize=6*1024;

View File

@ -177,7 +177,7 @@ public class HttpGenerator extends AbstractGenerator
return;
}
_last = last;
// Handle any unfinished business?
if (_content!=null && _content.length()>0 || _bufferChunked)
{
@ -829,7 +829,7 @@ public class HttpGenerator extends AbstractGenerator
{
try
{
if (_state == STATE_HEADER)
throw new IllegalStateException("State==HEADER");
@ -851,7 +851,7 @@ public class HttpGenerator extends AbstractGenerator
int len = -1;
int to_flush = flushMask();
int last_flush;
do
{
last_flush=to_flush;
@ -914,18 +914,18 @@ public class HttpGenerator extends AbstractGenerator
_state = STATE_END;
if (_state==STATE_END && _persistent != null && !_persistent && _status!=100 && _method==null)
_endp.shutdownOutput();
_endp.shutdownOutput();
}
else
// Try to prepare more to write.
prepareBuffers();
}
}
}
if (len > 0)
total+=len;
to_flush = flushMask();
}
// loop while progress is being made (OR we have prepared some buffers that might make progress)
@ -939,15 +939,15 @@ public class HttpGenerator extends AbstractGenerator
throw (e instanceof EofException) ? e:new EofException(e);
}
}
/* ------------------------------------------------------------ */
private int flushMask()
private int flushMask()
{
return ((_header != null && _header.length() > 0)?4:0)
| ((_buffer != null && _buffer.length() > 0)?2:0)
| ((_bypass && _content != null && _content.length() > 0)?1:0);
}
/* ------------------------------------------------------------ */
private void prepareBuffers()
{
@ -962,7 +962,7 @@ public class HttpGenerator extends AbstractGenerator
if (_content.length() == 0)
_content = null;
}
// Chunk buffer if need be
if (_contentLength == HttpTokens.CHUNKED_CONTENT)
{
@ -974,7 +974,7 @@ public class HttpGenerator extends AbstractGenerator
if (_header == null)
_header = _buffers.getHeader();
// if we need CRLF add this to header
if (_needCRLF)
{
@ -985,7 +985,7 @@ public class HttpGenerator extends AbstractGenerator
// Add the chunk size to the header
BufferUtil.putHexInt(_header, size);
_header.put(HttpTokens.CRLF);
// Need a CRLF after the content
_needCRLF=true;
}
@ -1018,7 +1018,7 @@ public class HttpGenerator extends AbstractGenerator
// No space so lets use a header buffer.
if (_header == null)
_header = _buffers.getHeader();
if (_needCRLF)
{
if (_header.length() > 0) throw new IllegalStateException("EOC");
@ -1101,10 +1101,11 @@ public class HttpGenerator extends AbstractGenerator
@Override
public String toString()
{
return "HttpGenerator{s="+_state+
",h="+(_header==null?"":_header.length())+
",b="+(_buffer==null?"":_buffer.length())+
",c="+(_content==null?"":_content.length())+
"}";
return String.format("%s{s=%d,h=%d,b=%d,c=%d}",
getClass().getSimpleName(),
_state,
_header == null ? -1 : _header.length(),
_buffer == null ? -1 : _buffer.length(),
_content == null ? -1 : _content.length());
}
}

View File

@ -14,8 +14,6 @@
package org.eclipse.jetty.http;
import java.io.IOException;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import org.eclipse.jetty.io.Buffer;
import org.eclipse.jetty.io.BufferCache.CachedBuffer;
@ -82,7 +80,7 @@ public class HttpParser implements Parser
protected int _chunkLength;
protected int _chunkPosition;
private boolean _headResponse;
/* ------------------------------------------------------------------------------- */
/**
* Constructor.
@ -233,7 +231,7 @@ public class HttpParser implements Parser
public boolean parseAvailable() throws IOException
{
boolean progress=parseNext()>0;
// continue parsing
while (!isComplete() && _buffer!=null && _buffer.length()>0)
{
@ -249,7 +247,7 @@ public class HttpParser implements Parser
* @return an indication of progress <0 EOF, 0 no progress, >0 progress.
*/
public int parseNext() throws IOException
{
{
try
{
int progress=0;
@ -300,7 +298,7 @@ public class HttpParser implements Parser
if (filled > 0 )
progress++;
else if (filled < 0 )
{
{
_persistent=false;
// do we have content to deliver?
@ -330,7 +328,8 @@ public class HttpParser implements Parser
default:
_state=STATE_END;
_handler.earlyEOF();
if (!_headResponse)
_handler.earlyEOF();
_handler.messageComplete(_contentPosition);
}
@ -1136,7 +1135,11 @@ public class HttpParser implements Parser
@Override
public String toString()
{
return "HttpParser{s=" + _state + ",l=" + _length + ",c=" + _contentLength+"}";
return String.format("%s{s=%d,l=%d,c=%d}",
getClass().getSimpleName(),
_state,
_length,
_contentLength);
}
/* ------------------------------------------------------------ */
@ -1169,7 +1172,7 @@ public class HttpParser implements Parser
{
if (_contentView.length()>0)
return _contentView;
if (getState() <= STATE_END || isState(STATE_SEEKING_EOF))
return null;
@ -1201,7 +1204,7 @@ public class HttpParser implements Parser
_endp.close();
throw e;
}
return _contentView.length()>0?_contentView:null;
}
@ -1259,7 +1262,7 @@ public class HttpParser implements Parser
*/
public abstract void startResponse(Buffer version, int status, Buffer reason)
throws IOException;
public void earlyEOF()
{}
}

View File

@ -11,14 +11,14 @@ public abstract class AbstractConnection implements Connection
private static final Logger LOG = Log.getLogger(AbstractConnection.class);
private final long _timeStamp;
protected final EndPoint _endp;
protected final EndPoint _endp;
public AbstractConnection(EndPoint endp)
{
_endp=(EndPoint)endp;
_timeStamp = System.currentTimeMillis();
}
public AbstractConnection(EndPoint endp,long timestamp)
{
_endp=(EndPoint)endp;
@ -29,7 +29,7 @@ public abstract class AbstractConnection implements Connection
{
return _timeStamp;
}
public EndPoint getEndPoint()
{
return _endp;
@ -39,7 +39,11 @@ public abstract class AbstractConnection implements Connection
{
try
{
_endp.shutdownOutput();
LOG.debug("onIdleExpired {} {}",this,_endp);
if (_endp.isInputShutdown() || _endp.isOutputShutdown())
_endp.close();
else
_endp.shutdownOutput();
}
catch(IOException e)
{
@ -52,13 +56,18 @@ public abstract class AbstractConnection implements Connection
catch(IOException e2)
{
LOG.ignore(e2);
}
}
}
public String toString()
{
return this.getClass().getSimpleName()+"@"+_endp.getLocalAddr()+":"+_endp.getLocalPort()+"<->"+_endp.getRemoteAddr()+":"+_endp.getRemotePort();
return String.format("%s@%x//%s:%d<->%s:%d",
getClass().getSimpleName(),
hashCode(),
_endp.getLocalAddr(),
_endp.getLocalPort(),
_endp.getRemoteAddr(),
_endp.getRemotePort());
}
}

View File

@ -29,18 +29,26 @@ public interface AsyncEndPoint extends ConnectedEndPoint
* Set the endpoint to not be writable and schedule a dispatch when
* it becomes writable.
*/
public void scheduleWrite();
/* ------------------------------------------------------------ */
/** Schedule a call to the idle timeout
*/
public void scheduleIdle();
/* ------------------------------------------------------------ */
/** Cancel a call to the idle timeout
*/
public void cancelIdle();
public void scheduleWrite();
/* ------------------------------------------------------------ */
/** Callback when idle.
* <p>An endpoint is idle if there has been no IO activity for
* {@link #getMaxIdleTime()} and {@link #isCheckForIdle()} is true.
*/
public void onIdleExpired();
/* ------------------------------------------------------------ */
/** Set if the endpoint should be checked for idleness
*/
public void setCheckForIdle(boolean check);
/* ------------------------------------------------------------ */
/** Get if the endpoint should be checked for idleness
*/
public boolean isCheckForIdle();
/* ------------------------------------------------------------ */
public boolean isWritable();

View File

@ -24,11 +24,6 @@ import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
/**
*
* To change the template for this generated type comment go to
* Window - Preferences - Java - Code Generation - Code and Comments
*/
public class SocketEndPoint extends StreamEndPoint
{
private static final Logger LOG = Log.getLogger(SocketEndPoint.class);
@ -88,13 +83,13 @@ public class SocketEndPoint extends StreamEndPoint
/* ------------------------------------------------------------ */
@Override
public boolean isOutputShutdown()
{
{
if (_socket instanceof SSLSocket)
return super.isOutputShutdown();
return _socket.isClosed() || _socket.isOutputShutdown();
}
/* ------------------------------------------------------------ */
/*
@ -137,7 +132,7 @@ public class SocketEndPoint extends StreamEndPoint
_socket.close();
}
}
/* ------------------------------------------------------------ */
/*
* @see org.eclipse.jetty.io.bio.StreamEndPoint#shutdownOutput()
@ -278,4 +273,9 @@ public class SocketEndPoint extends StreamEndPoint
}
}
@Override
public String toString()
{
return _local + " <--> " + _remote;
}
}

View File

@ -43,8 +43,9 @@ public class ChannelEndPoint implements EndPoint
protected final Socket _socket;
protected final InetSocketAddress _local;
protected final InetSocketAddress _remote;
protected int _maxIdleTime;
private boolean _ishut;
protected volatile int _maxIdleTime;
private volatile boolean _ishut;
private volatile boolean _oshut;
public ChannelEndPoint(ByteChannel channel) throws IOException
{
@ -109,34 +110,32 @@ public class ChannelEndPoint implements EndPoint
*/
protected final void shutdownChannelInput() throws IOException
{
LOG.debug("ishut {}",this);
LOG.debug("ishut {}", this);
_ishut = true;
if (_channel.isOpen())
{
if (_socket!=null)
if (_socket != null)
{
try
{
if (!_socket.isInputShutdown())
{
// System.err.println("ISHUT "+_socket);
_socket.shutdownInput();
}
}
catch(SocketException e)
{
// System.err.println(e);
catch (SocketException e)
{
LOG.debug(e.toString());
LOG.ignore(e);
}
finally
{
_ishut=true;
if(_socket.isOutputShutdown() && !_socket.isClosed())
if (_oshut)
{
close();
}
}
}
else
_ishut=true;
}
}
@ -151,33 +150,31 @@ public class ChannelEndPoint implements EndPoint
protected final void shutdownChannelOutput() throws IOException
{
LOG.debug("oshut {}",this);
_oshut = true;
if (_channel.isOpen())
{
if (_socket!=null)
if (_socket != null)
{
try
{
if (!_socket.isOutputShutdown())
{
// System.err.println("OSHUT "+_socket);
_socket.shutdownOutput();
}
}
catch(SocketException e)
catch (SocketException e)
{
LOG.debug(e.toString());
LOG.ignore(e);
if (!_socket.isClosed())
close();
}
finally
{
if ((_ishut||_socket.isInputShutdown()) && !_socket.isClosed())
if (_ishut)
{
close();
}
}
}
else
close();
}
}
@ -191,12 +188,12 @@ public class ChannelEndPoint implements EndPoint
public boolean isOutputShutdown()
{
return !_channel.isOpen() || _socket!=null && _socket.isOutputShutdown();
return _oshut || !_channel.isOpen() || _socket != null && _socket.isOutputShutdown();
}
public boolean isInputShutdown()
{
return !_channel.isOpen() || _ishut || _socket!=null && _socket.isInputShutdown();
return _ishut || !_channel.isOpen() || _socket != null && _socket.isInputShutdown();
}
/* (non-Javadoc)
@ -205,8 +202,6 @@ public class ChannelEndPoint implements EndPoint
public void close() throws IOException
{
LOG.debug("close {}",this);
// System.err.println("CLOSE "+_socket);
_channel.close();
}
@ -359,7 +354,7 @@ public class ChannelEndPoint implements EndPoint
trailer!=null && trailer.length()>0)
length+=flush(trailer);
}
return length;
}

View File

@ -36,7 +36,7 @@ import org.eclipse.jetty.util.thread.Timeout.Task;
public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPoint, ConnectedEndPoint
{
public static final Logger LOG=Log.getLogger("org.eclipse.jetty.io.nio");
private final SelectorManager.SelectSet _selectSet;
private final SelectorManager _manager;
private SelectionKey _key;
@ -47,38 +47,38 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
/** The desired value for {@link SelectionKey#interestOps()} */
private int _interestOps;
/**
* The connection instance is the handler for any IO activity on the endpoint.
* There is a different type of connection for HTTP, AJP, WebSocket and
* ProxyConnect. The connection may change for an SCEP as it is upgraded
* There is a different type of connection for HTTP, AJP, WebSocket and
* ProxyConnect. The connection may change for an SCEP as it is upgraded
* from HTTP to proxy connect or websocket.
*/
private volatile AsyncConnection _connection;
/** true if a thread has been dispatched to handle this endpoint */
private boolean _dispatched = false;
/** true if a non IO dispatch (eg async resume) is outstanding */
private boolean _asyncDispatch = false;
/** true if the last write operation succeed and wrote all offered bytes */
private volatile boolean _writable = true;
/** True if a thread has is blocked in {@link #blockReadable(long)} */
private boolean _readBlocked;
/** True if a thread has is blocked in {@link #blockWritable(long)} */
private boolean _writeBlocked;
/** true if {@link SelectSet#destroyEndPoint(SelectChannelEndPoint)} has not been called */
private boolean _open;
private volatile long _idleTimestamp;
private boolean _ishut;
/* ------------------------------------------------------------ */
public SelectChannelEndPoint(SocketChannel channel, SelectSet selectSet, SelectionKey key, int maxIdleTime)
throws IOException
@ -92,9 +92,9 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
_open=true;
_key = key;
scheduleIdle();
setCheckForIdle(true);
}
/* ------------------------------------------------------------ */
public SelectionKey getSelectionKey()
{
@ -130,7 +130,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
{
return _idleTimestamp;
}
/* ------------------------------------------------------------ */
/** Called by selectSet to schedule handling
*
@ -148,7 +148,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
return;
}
// If there are threads dispatched reading and writing
// If there are threads dispatched reading and writing
if (_readBlocked || _writeBlocked)
{
// assert _dispatched;
@ -199,7 +199,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
dispatch();
}
}
/* ------------------------------------------------------------ */
public void dispatch()
{
@ -256,39 +256,59 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
{
getSelectSet().scheduleTimeout(task,timeoutMs);
}
/* ------------------------------------------------------------ */
public void setCheckForIdle(boolean check)
{
_idleTimestamp=check?System.currentTimeMillis():0;
}
/* ------------------------------------------------------------ */
public void scheduleIdle()
public boolean isCheckForIdle()
{
_idleTimestamp=System.currentTimeMillis();
return _idleTimestamp!=0;
}
/* ------------------------------------------------------------ */
public void cancelIdle()
protected void notIdle()
{
_idleTimestamp=0;
if (_idleTimestamp!=0)
_idleTimestamp=System.currentTimeMillis();
}
/* ------------------------------------------------------------ */
public void checkIdleTimestamp(long now)
{
long idleTimestamp=_idleTimestamp;
if (!getChannel().isOpen() || idleTimestamp!=0 && _maxIdleTime>0 && now>(idleTimestamp+_maxIdleTime))
idleExpired();
{
onIdleExpired();
_idleTimestamp=now;
}
}
/* ------------------------------------------------------------ */
protected void idleExpired()
public void onIdleExpired()
{
_connection.onIdleExpired();
}
/* ------------------------------------------------------------ */
@Override
public int fill(Buffer buffer) throws IOException
{
int fill=super.fill(buffer);
if (fill>0)
notIdle();
return fill;
}
/* ------------------------------------------------------------ */
@Override
public int flush(Buffer header, Buffer buffer, Buffer trailer) throws IOException
{
int l = super.flush(header, buffer, trailer);
// If there was something to write and it wasn't written, then we are not writable.
if (l==0 && ( header!=null && header.hasContent() || buffer!=null && buffer.hasContent() || trailer!=null && trailer.hasContent()))
{
@ -302,6 +322,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
else if (l>0)
{
_writable=true;
notIdle();
}
return l;
}
@ -313,7 +334,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
public int flush(Buffer buffer) throws IOException
{
int l = super.flush(buffer);
// If there was something to write and it wasn't written, then we are not writable.
if (l==0 && buffer!=null && buffer.hasContent())
{
@ -327,8 +348,9 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
else if (l>0)
{
_writable=true;
notIdle();
}
return l;
}
@ -343,9 +365,11 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
{
if (isInputShutdown())
throw new EofException();
long now=_selectSet.getNow();
long end=now+timeoutMs;
boolean check=isCheckForIdle();
setCheckForIdle(true);
try
{
_readBlocked=true;
@ -372,6 +396,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
finally
{
_readBlocked=false;
setCheckForIdle(check);
}
}
return true;
@ -388,9 +413,11 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
{
if (isOutputShutdown())
throw new EofException();
long now=_selectSet.getNow();
long end=now+timeoutMs;
boolean check=isCheckForIdle();
setCheckForIdle(true);
try
{
_writeBlocked=true;
@ -416,8 +443,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
finally
{
_writeBlocked=false;
if (_idleTimestamp!=-1)
scheduleIdle();
setCheckForIdle(check);
}
}
return true;
@ -429,7 +455,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
{
_writable=false;
}
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.io.AsyncEndPoint#scheduleWrite()
@ -438,11 +464,11 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
{
if (_writable==true)
LOG.debug("Required scheduleWrite {}",this);
_writable=false;
updateKey();
}
/* ------------------------------------------------------------ */
public boolean isWritable()
{
@ -471,7 +497,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
{
boolean read_interest = _readBlocked || (!_dispatched && !_connection.isSuspended());
boolean write_interest= _writeBlocked || (!_dispatched && !_writable);
_interestOps =
((!_socket.isInputShutdown() && read_interest ) ? SelectionKey.OP_READ : 0)
| ((!_socket.isOutputShutdown()&& write_interest) ? SelectionKey.OP_WRITE : 0);
@ -494,7 +520,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
_selectSet.wakeup();
}
}
/* ------------------------------------------------------------ */
/**
@ -528,7 +554,6 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
{
_key.cancel();
}
cancelIdle();
if (_open)
{
@ -557,7 +582,6 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
if (_key!=null && _key.isValid())
_key.cancel();
cancelIdle();
if (_open)
{
_open=false;
@ -626,10 +650,6 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
{
_connection.onInputShutdown();
}
catch (ThreadDeath e)
{
throw e;
}
catch(Throwable x)
{
LOG.warn("onInputShutdown failed", x);
@ -686,20 +706,21 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
{
synchronized(this)
{
return "SCEP@" + hashCode() +
"{"+_socket.getRemoteSocketAddress()+"->"+_socket.getLocalSocketAddress()+
(_dispatched?",D":"") +
(isOpen()?",open":"") +
(isInputShutdown()?",ishut":"") +
(isOutputShutdown()?",oshut":"") +
(_readBlocked?",RB":"") +
(_writeBlocked?",WB":"") +
(_writable?"":",!W") +
","+_interestOps +
((_key==null || !_key.isValid())?"!":(
(_key.isReadable()?"R":"")+
(_key.isWritable()?"W":"")))+
"}";
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}",
hashCode(),
_socket.getRemoteSocketAddress(),
_socket.getLocalSocketAddress(),
_dispatched,
isOpen(),
isInputShutdown(),
isOutputShutdown(),
_readBlocked,
_writeBlocked,
_writable,
_interestOps,
_key != null && _key.isValid() ? "" : "!",
_key != null && _key.isValid() && _key.isReadable() ? "r" : "",
_key != null && _key.isValid() && _key.isWritable() ? "w" : "");
}
}

View File

@ -283,10 +283,6 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
{
set.doSelect();
}
catch(ThreadDeath e)
{
throw e;
}
catch(IOException e)
{
LOG.ignore(e);
@ -444,7 +440,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
// Stopped concurrently ?
if (selector == null)
return;
// Make any key changes required
Object change;
int changes=_changes.size();
@ -507,10 +503,6 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
{
LOG.ignore(e);
}
catch (ThreadDeath e)
{
throw e;
}
catch (Throwable e)
{
if (isRunning())
@ -578,7 +570,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
{
// Start injecting pauses
_pausing=true;
// if this is the first pause
if (!_paused)
{
@ -715,16 +707,16 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
}
public String toString() {return "Idle-"+super.toString();}
});
}
// Reset busy select monitor counts
if (__MONITOR_PERIOD>0 && now>_monitorNext)
{
_busySelects=0;
_pausing=false;
_monitorNext=now+__MONITOR_PERIOD;
}
}
catch (ClosedSelectorException e)
@ -977,20 +969,21 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
for (SelectionKey key: selector.keys())
{
if (key.isValid())
dumpto.add(key.attachment()+" "+key.interestOps()+" "+key.readyOps());
dumpto.add(key.attachment()+" iOps="+key.interestOps()+" rOps="+key.readyOps());
else
dumpto.add(key.attachment()+" - - ");
dumpto.add(key.attachment()+" iOps=-1 rOps=-1");
}
}
/* ------------------------------------------------------------ */
public String toString()
{
String s=super.toString()+" "+SelectorManager.this.getState();
Selector selector=_selector;
if (selector!=null && selector.isOpen())
s+=",k="+selector.keys().size()+",s="+selector.selectedKeys().size();
return s;
return String.format("%s %s keys=%d selected=%d",
super.toString(),
SelectorManager.this.getState(),
selector != null && selector.isOpen() ? selector.keys().size() : -1,
selector != null && selector.isOpen() ? selector.selectedKeys().size() : -1);
}
}

View File

@ -16,6 +16,7 @@ package org.eclipse.jetty.io.nio;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLEngineResult;
import javax.net.ssl.SSLEngineResult.HandshakeStatus;
@ -178,7 +179,9 @@ public class SslConnection extends AbstractConnection implements AsyncConnection
// If we are handshook let the delegate connection
if (_engine.getHandshakeStatus()!=HandshakeStatus.NOT_HANDSHAKING)
progress|=process(null,null);
{
progress=process(null,null);
}
else
{
// handle the delegate connection
@ -204,10 +207,6 @@ public class SslConnection extends AbstractConnection implements AsyncConnection
{
_connection.onInputShutdown();
}
catch (ThreadDeath e)
{
throw e;
}
catch(Throwable x)
{
LOG.warn("onInputShutdown failed", x);
@ -251,7 +250,7 @@ public class SslConnection extends AbstractConnection implements AsyncConnection
super.onIdleExpired();
}
}
/* ------------------------------------------------------------ */
public void onInputShutdown() throws IOException
{
@ -393,7 +392,8 @@ public class SslConnection extends AbstractConnection implements AsyncConnection
finally
{
releaseBuffers();
_progressed.set(some_progress);
if (some_progress)
_progressed.set(true);
}
return some_progress;
}
@ -586,11 +586,6 @@ public class SslConnection extends AbstractConnection implements AsyncConnection
return _engine;
}
public SslConnection getSslConnection()
{
return SslConnection.this;
}
public void shutdownOutput() throws IOException
{
synchronized (SslConnection.this)
@ -647,10 +642,9 @@ public class SslConnection extends AbstractConnection implements AsyncConnection
public int flush(Buffer buffer) throws IOException
{
int size=buffer.length();
process(null,buffer);
int flushed=size-buffer.length();
return flushed;
int size = buffer.length();
process(null, buffer);
return size-buffer.length();
}
public int flush(Buffer header, Buffer buffer, Buffer trailer) throws IOException
@ -710,14 +704,19 @@ public class SslConnection extends AbstractConnection implements AsyncConnection
_aEndp.scheduleWrite();
}
public void scheduleIdle()
public void onIdleExpired()
{
_aEndp.scheduleIdle();
_aEndp.onIdleExpired();
}
public void cancelIdle()
public void setCheckForIdle(boolean check)
{
_aEndp.cancelIdle();
_aEndp.setCheckForIdle(check);
}
public boolean isCheckForIdle()
{
return _aEndp.isCheckForIdle();
}
public void scheduleTimeout(Task task, long timeoutMs)
@ -797,20 +796,20 @@ public class SslConnection extends AbstractConnection implements AsyncConnection
public String toString()
{
Buffer i;
Buffer o;
Buffer u;
int i;
int o;
int u;
synchronized(SslConnection.this)
{
i=_inbound;
o=_outbound;
u=_unwrapBuf;
i=_inbound==null?-1:_inbound.length();
o=_outbound==null?-1:_outbound.length();
u=_unwrapBuf==null?-1:_unwrapBuf.length();
}
return "SSL:"+_endp+" "+_engine.getHandshakeStatus()+" i/u/o="+(i==null?0:i.length())+"/"+(u==null?0:u.length())+"/"+(o==null?0:o.length()+(_ishut?" ishut":"")+(_oshut?" oshut":""));
return String.format("SSL:%s %s i/u/o=%d/%d/%d ishut=%b oshut=%b",
_endp,
_engine.getHandshakeStatus(),
i, u, o,
_ishut, _oshut);
}
}
}

View File

@ -27,7 +27,6 @@ import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import org.eclipse.jetty.util.IO;
import org.junit.Assert;
import org.junit.Test;
/**

View File

@ -6,7 +6,6 @@ import java.nio.channels.SocketChannel;
import org.eclipse.jetty.io.EndPointTest;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
public class ChannelEndPointTest extends EndPointTest<ChannelEndPoint>
{

View File

@ -0,0 +1,131 @@
// ========================================================================
// Copyright (c) 2004-2009 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
package org.eclipse.jetty.io.nio;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import org.junit.Test;
/**
*
*/
public class NIOTest
{
@Test
public void testSelector() throws Exception
{
ServerSocket acceptor = new ServerSocket(0);
Selector selector = Selector.open();
// Create client server socket pair
SocketChannel client = SocketChannel.open(acceptor.getLocalSocketAddress());
Socket server = acceptor.accept();
server.setTcpNoDelay(true);
// Make the client non blocking and register it with selector for reads
client.configureBlocking(false);
SelectionKey key = client.register(selector,SelectionKey.OP_READ);
// assert it is not selected
assertTrue(key.isValid());
assertFalse(key.isReadable());
assertEquals(0,key.readyOps());
// try selecting and assert nothing selected
int selected = selector.selectNow();
assertEquals(0,selected);
assertEquals(0,selector.selectedKeys().size());
assertTrue(key.isValid());
assertFalse(key.isReadable());
assertEquals(0,key.readyOps());
// Write a byte from server to client
server.getOutputStream().write(42);
server.getOutputStream().flush();
// select again and assert selection found for read
selected = selector.select(1000);
assertEquals(1,selected);
assertEquals(1,selector.selectedKeys().size());
assertTrue(key.isValid());
assertTrue(key.isReadable());
assertEquals(1,key.readyOps());
// select again and see that it is not reselect, but stays selected
selected = selector.select(100);
assertEquals(0,selected);
assertEquals(1,selector.selectedKeys().size());
assertTrue(key.isValid());
assertTrue(key.isReadable());
assertEquals(1,key.readyOps());
// read the byte
ByteBuffer buf = ByteBuffer.allocate(1024);
int len=client.read(buf);
assertEquals(1,len);
buf.flip();
assertEquals(42,buf.get());
buf.clear();
// But this does not change the key
assertTrue(key.isValid());
assertTrue(key.isReadable());
assertEquals(1,key.readyOps());
// Even if we select again ?
selected = selector.select(100);
assertEquals(0,selected);
assertEquals(1,selector.selectedKeys().size());
assertTrue(key.isValid());
assertTrue(key.isReadable());
assertEquals(1,key.readyOps());
// Unless we remove the key from the select set
// and then it is still flagged as isReadable()
selector.selectedKeys().clear();
assertEquals(0,selector.selectedKeys().size());
assertTrue(key.isValid());
assertTrue(key.isReadable());
assertEquals(1,key.readyOps());
// Now if we select again - it is still flagged as readable!!!
selected = selector.select(100);
assertEquals(0,selected);
assertEquals(0,selector.selectedKeys().size());
assertTrue(key.isValid());
assertTrue(key.isReadable());
assertEquals(1,key.readyOps());
// Only when it is selected for something else does that state change.
key.interestOps(SelectionKey.OP_READ|SelectionKey.OP_WRITE);
selected = selector.select(1000);
assertEquals(1,selected);
assertEquals(1,selector.selectedKeys().size());
assertTrue(key.isValid());
assertTrue(key.isWritable());
assertFalse(key.isReadable());
assertEquals(SelectionKey.OP_WRITE,key.readyOps());
}
}

View File

@ -8,8 +8,8 @@ import java.nio.channels.SocketChannel;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLEngineResult;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLEngineResult.HandshakeStatus;
import javax.net.ssl.SSLSocket;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;

View File

@ -1,5 +1,10 @@
package org.eclipse.jetty.io.nio;
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
@ -22,12 +27,9 @@ import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
public class SelectChannelEndPointTest
{
protected SelectChannelEndPoint _lastEndp;
protected ServerSocketChannel _connector;
protected QueuedThreadPool _threadPool = new QueuedThreadPool();
protected SelectorManager _manager = new SelectorManager()
@ -64,6 +66,7 @@ public class SelectChannelEndPointTest
{
SelectChannelEndPoint endp = new SelectChannelEndPoint(channel,selectSet,key,2000);
endp.setConnection(selectSet.getManager().newConnection(channel,endp, key.attachment()));
_lastEndp=endp;
return endp;
}
};
@ -116,10 +119,7 @@ public class SelectChannelEndPointTest
progress=false;
_in.compact();
if (_in.space()>0 && _endp.fill(_in)>0)
{
progress=true;
((AsyncEndPoint)_endp).cancelIdle();
}
while (_blockAt>0 && _in.length()>0 && _in.length()<_blockAt)
{
@ -210,7 +210,7 @@ public class SelectChannelEndPointTest
assertEquals(c,(char)b);
}
client.close();
int i=0;
while (server.isOpen())
{
@ -325,6 +325,54 @@ public class SelectChannelEndPointTest
assertEquals(c,(char)b);
}
}
@Test
public void testIdle() throws Exception
{
Socket client = newClient();
client.setSoTimeout(3000);
SocketChannel server = _connector.accept();
server.configureBlocking(false);
_manager.register(server);
// Write client to server
client.getOutputStream().write("HelloWorld".getBytes("UTF-8"));
// Verify echo server to client
for (char c : "HelloWorld".toCharArray())
{
int b = client.getInputStream().read();
assertTrue(b>0);
assertEquals(c,(char)b);
}
// Set Max idle
_lastEndp.setMaxIdleTime(500);
// read until idle shutdown received
long start=System.currentTimeMillis();
int b=client.getInputStream().read();
assertEquals(-1,b);
long idle=System.currentTimeMillis()-start;
assertTrue(idle>400);
assertTrue(idle<2000);
// But endpoint is still open.
assertTrue(_lastEndp.isOpen());
// Wait for another idle callback
Thread.sleep(1000);
// endpoint is closed.
assertFalse(_lastEndp.isOpen());
}
@Test
public void testStress() throws Exception
@ -338,8 +386,12 @@ public class SelectChannelEndPointTest
_manager.register(server);
int writes = 100000;
final byte[] bytes="HelloWorld".getBytes("UTF-8");
final CountDownLatch latch = new CountDownLatch(writes);
final InputStream in = new BufferedInputStream(client.getInputStream());
final long start = System.currentTimeMillis();
client.getOutputStream().write(bytes);
client.getOutputStream().flush();
new Thread()
{
@ -350,29 +402,33 @@ public class SelectChannelEndPointTest
while (latch.getCount()>0)
{
// Verify echo server to client
for (char c : "HelloWorld".toCharArray())
for (byte b0 : bytes)
{
int b = in.read();
assertTrue(b>0);
assertEquals(c,(char)b);
assertEquals(0xff&b0,b);
}
latch.countDown();
}
}
catch(Exception e)
catch(Throwable e)
{
System.err.println("latch="+latch.getCount());
System.err.println("time="+(System.currentTimeMillis()-start));
e.printStackTrace();
}
}
}.start();
byte[] bytes="HelloWorld".getBytes("UTF-8");
// Write client to server
for (int i=0;i<writes;i++)
for (int i=1;i<writes;i++)
{
client.getOutputStream().write(bytes);
Thread.yield();
}
client.getOutputStream().flush();
assertTrue(latch.await(100,TimeUnit.SECONDS));
}
}

View File

@ -25,8 +25,8 @@ import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;
import org.eclipse.jetty.http.PathMap;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.AbstractHttpConnection;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Response;
import org.eclipse.jetty.server.UserIdentity;

View File

@ -32,9 +32,9 @@ import org.eclipse.jetty.http.HttpMethods;
import org.eclipse.jetty.http.MimeTypes;
import org.eclipse.jetty.security.ServerAuthException;
import org.eclipse.jetty.security.UserAuthentication;
import org.eclipse.jetty.server.AbstractHttpConnection;
import org.eclipse.jetty.server.Authentication;
import org.eclipse.jetty.server.Authentication.User;
import org.eclipse.jetty.server.AbstractHttpConnection;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.UserIdentity;
import org.eclipse.jetty.util.MultiMap;

View File

@ -48,8 +48,8 @@ import org.eclipse.jetty.util.thread.ThreadPool;
* <li>Base acceptor thread</li>
* <li>Optional reverse proxy headers checking</li>
* </ul>
*
*
*
*
*/
public abstract class AbstractConnector extends HttpBuffers implements Connector, Dumpable
{
@ -181,7 +181,7 @@ public abstract class AbstractConnector extends HttpBuffers implements Connector
* <p>
* Previously, Jetty supported separate idle timeouts and IO operation timeouts, however the expense of changing the value of soTimeout was significant, so
* these timeouts were merged. With the advent of NIO, it may be possible to again differentiate these values (if there is demand).
*
*
* @param maxIdleTime
* The maxIdleTime to set.
*/
@ -414,13 +414,13 @@ public abstract class AbstractConnector extends HttpBuffers implements Connector
request.setScheme(HttpSchemes.HTTPS);
}
}
// Retrieving headers from the request
String forwardedHost = getLeftMostFieldValue(httpFields,getForwardedHostHeader());
String forwardedServer = getLeftMostFieldValue(httpFields,getForwardedServerHeader());
String forwardedFor = getLeftMostFieldValue(httpFields,getForwardedForHeader());
String forwardedProto = getLeftMostFieldValue(httpFields,getForwardedProtoHeader());
if (_hostHeader != null)
{
// Update host header
@ -462,7 +462,7 @@ public abstract class AbstractConnector extends HttpBuffers implements Connector
request.setRemoteHost(inetAddress == null?forwardedFor:inetAddress.getHostName());
}
if (forwardedProto != null)
{
request.setScheme(forwardedProto);
@ -615,7 +615,7 @@ public abstract class AbstractConnector extends HttpBuffers implements Connector
/* ------------------------------------------------------------ */
/**
* Is reverse proxy handling on?
*
*
* @return true if this connector is checking the x-forwarded-for/host/server headers
*/
public boolean isForwarded()
@ -627,7 +627,7 @@ public abstract class AbstractConnector extends HttpBuffers implements Connector
/**
* Set reverse proxy handling. If set to true, then the X-Forwarded headers (or the headers set in their place) are looked for to set the request protocol,
* host, server and client ip.
*
*
* @param check
* true if this connector is checking the x-forwarded-for/host/server headers
* @set {@link #setForwardedForHeader(String)}
@ -652,7 +652,7 @@ public abstract class AbstractConnector extends HttpBuffers implements Connector
/**
* Set a forced valued for the host header to control what is returned by {@link ServletRequest#getServerName()} and {@link ServletRequest#getServerPort()}.
* This value is only used if {@link #isForwarded()} is true.
*
*
* @param hostHeader
* The value of the host header to force.
*/
@ -663,7 +663,7 @@ public abstract class AbstractConnector extends HttpBuffers implements Connector
/* ------------------------------------------------------------ */
/*
*
*
* @see #setForwarded(boolean)
*/
public String getForwardedHostHeader()
@ -726,7 +726,7 @@ public abstract class AbstractConnector extends HttpBuffers implements Connector
/* ------------------------------------------------------------ */
/**
* Get the forwardedProtoHeader.
*
*
* @return the forwardedProtoHeader (default X-Forwarded-For)
* @see #setForwarded(boolean)
*/
@ -738,7 +738,7 @@ public abstract class AbstractConnector extends HttpBuffers implements Connector
/* ------------------------------------------------------------ */
/**
* Set the forwardedProtoHeader.
*
*
* @param forwardedProtoHeader
* the forwardedProtoHeader to set (default X-Forwarded-For)
* @see #setForwarded(boolean)
@ -849,10 +849,6 @@ public abstract class AbstractConnector extends HttpBuffers implements Connector
// Connector has been stopped
LOG.ignore(x);
}
catch (ThreadDeath e)
{
throw e;
}
catch (Throwable e)
{
LOG.warn(e);
@ -1075,7 +1071,7 @@ public abstract class AbstractConnector extends HttpBuffers implements Connector
/**
* Set the priority offset of the acceptor threads. The priority is adjusted by this amount (default 0) to either favour the acceptance of new threads and
* newly active connections or to favour the handling of already dispatched connections.
*
*
* @param offset
* the amount to alter the priority of the acceptor threads.
*/

View File

@ -39,7 +39,6 @@ import org.eclipse.jetty.http.HttpVersions;
import org.eclipse.jetty.http.MimeTypes;
import org.eclipse.jetty.http.Parser;
import org.eclipse.jetty.io.AbstractConnection;
import org.eclipse.jetty.io.AsyncEndPoint;
import org.eclipse.jetty.io.Buffer;
import org.eclipse.jetty.io.BufferCache.CachedBuffer;
import org.eclipse.jetty.io.Buffers;
@ -56,7 +55,6 @@ import org.eclipse.jetty.util.URIUtil;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.thread.Timeout;
/**
* <p>A HttpConnection represents the connection of a HTTP client to the server
@ -370,24 +368,6 @@ public abstract class AbstractHttpConnection extends AbstractConnection
return _generator.isCommitted();
}
/* ------------------------------------------------------------ */
/**
* @deprecated
*/
public final void scheduleTimeout(Timeout.Task task, long timeoutMs)
{
throw new UnsupportedOperationException();
}
/* ------------------------------------------------------------ */
/**
* @deprecated
*/
public final void cancelTimeout(Timeout.Task task)
{
throw new UnsupportedOperationException();
}
/* ------------------------------------------------------------ */
public void reset()
{
@ -481,10 +461,6 @@ public abstract class AbstractHttpConnection extends AbstractConnection
_request.setHandled(true);
_response.sendError(e.getStatus(), e.getReason());
}
catch (ThreadDeath e)
{
throw e;
}
catch (Throwable e)
{
async_exception=e;
@ -704,7 +680,11 @@ public abstract class AbstractHttpConnection extends AbstractConnection
/* ------------------------------------------------------------ */
public String toString()
{
return super.toString()+" "+_parser+" "+_generator+" "+_requests;
return String.format("%s,g=%s,p=%s,r=%d",
super.toString(),
_generator,
_parser,
_requests);
}
/* ------------------------------------------------------------ */
@ -850,8 +830,6 @@ public abstract class AbstractHttpConnection extends AbstractConnection
@Override
public void headerComplete() throws IOException
{
if (_endp instanceof AsyncEndPoint)
((AsyncEndPoint)_endp).scheduleIdle();
_requests++;
_generator.setVersion(_version);
switch (_version)
@ -927,8 +905,6 @@ public abstract class AbstractHttpConnection extends AbstractConnection
@Override
public void content(Buffer ref) throws IOException
{
if (_endp instanceof AsyncEndPoint)
((AsyncEndPoint)_endp).scheduleIdle();
if (_delayedHandling)
{
_delayedHandling=false;

View File

@ -79,7 +79,6 @@ public class AsyncHttpConnection extends AbstractHttpConnection implements Async
// Has any IO been done by the endpoint itself since last loop
if (_asyncEndp.hasProgressed())
progress=true;
}
catch (HttpException e)
{
@ -122,6 +121,7 @@ public class AsyncHttpConnection extends AbstractHttpConnection implements Async
{
// The request is suspended, so even though progress has been made, break the while loop
LOG.debug("suspended {}",this);
// TODO: breaking inside finally blocks is bad: rethink how we should exit from here
break;
}
}
@ -131,11 +131,11 @@ public class AsyncHttpConnection extends AbstractHttpConnection implements Async
{
setCurrentConnection(null);
if (!_request.isAsyncStarted())
{
{
_parser.returnBuffers();
_generator.returnBuffers();
}
// Safety net to catch spinning
if (some_progress)
_total_no_progress=0;

View File

@ -31,32 +31,26 @@ public class BlockingHttpConnection extends AbstractHttpConnection
{
private static final Logger LOG = Log.getLogger(BlockingHttpConnection.class);
private volatile boolean _handling;
public BlockingHttpConnection(Connector connector, EndPoint endpoint, Server server)
{
super(connector,endpoint,server);
}
public BlockingHttpConnection(Connector connector, EndPoint endpoint, Server server, Parser parser, Generator generator, Request request)
{
super(connector,endpoint,server,parser,generator,request);
}
@Override
protected void handleRequest() throws IOException
{
super.handleRequest();
}
public Connection handle() throws IOException
{
Connection connection = this;
boolean progress=true;
try
{
setCurrentConnection(this);
@ -67,17 +61,16 @@ public class BlockingHttpConnection extends AbstractHttpConnection
{
try
{
progress=false;
// If we are not ended then parse available
if (!_parser.isComplete() && !_endp.isInputShutdown())
progress |= _parser.parseAvailable();
_parser.parseAvailable();
// Do we have more generating to do?
// Loop here because some writes may take multiple steps and
// we need to flush them all before potentially blocking in the
// next loop.
if (_generator.isCommitted() && !_generator.isComplete() && !_endp.isOutputShutdown())
progress |= _generator.flushBuffer()>0;
_generator.flushBuffer();
// Flush buffers
_endp.flush();
@ -100,9 +93,7 @@ public class BlockingHttpConnection extends AbstractHttpConnection
if (_parser.isComplete() && _generator.isComplete())
{
// Reset the parser/generator
progress=true;
reset();
_endp.flush();
// look for a switched connection instance?
if (_response.getStatus()==HttpStatus.SWITCHING_PROTOCOLS_101)
@ -121,6 +112,8 @@ public class BlockingHttpConnection extends AbstractHttpConnection
}
}
}
return connection;
}
finally
{
@ -128,7 +121,5 @@ public class BlockingHttpConnection extends AbstractHttpConnection
_parser.returnBuffers();
_generator.returnBuffers();
}
return connection;
}
}

View File

@ -54,6 +54,7 @@ public class Response implements HttpServletResponse
{
private static final Logger LOG = Log.getLogger(Response.class);
public static final int
NONE=0,
STREAM=1,
@ -66,6 +67,12 @@ public class Response implements HttpServletResponse
*/
public final static String SET_INCLUDE_HEADER_PREFIX = "org.eclipse.jetty.server.include.";
/**
* If this string is found within the comment of a cookie added with {@link #addCookie(Cookie)}, then the cookie
* will be set as HTTP ONLY.
*/
public final static String HTTP_ONLY_COMMENT="__HTTP_ONLY__";
private final AbstractHttpConnection _connection;
private int _status=SC_OK;
private String _reason;
@ -121,14 +128,28 @@ public class Response implements HttpServletResponse
*/
public void addCookie(Cookie cookie)
{
String comment=cookie.getComment();
boolean http_only=false;
if (comment!=null)
{
int i=comment.indexOf(HTTP_ONLY_COMMENT);
if (i>=0)
{
http_only=true;
comment=comment.substring(i,i+HTTP_ONLY_COMMENT.length()).trim();
if (comment.length()==0)
comment=null;
}
}
_connection.getResponseFields().addSetCookie(cookie.getName(),
cookie.getValue(),
cookie.getDomain(),
cookie.getPath(),
cookie.getMaxAge(),
cookie.getComment(),
comment,
cookie.getSecure(),
cookie.isHttpOnly(),
http_only || cookie.isHttpOnly(),
cookie.getVersion());
}

View File

@ -19,7 +19,6 @@ import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import org.eclipse.jetty.http.HttpException;
@ -30,9 +29,10 @@ import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.io.EofException;
import org.eclipse.jetty.io.bio.SocketEndPoint;
import org.eclipse.jetty.server.AbstractConnector;
import org.eclipse.jetty.server.BlockingHttpConnection;
import org.eclipse.jetty.server.AbstractHttpConnection;
import org.eclipse.jetty.server.BlockingHttpConnection;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.util.component.AggregateLifeCycle;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
@ -156,21 +156,30 @@ public class SocketConnector extends AbstractConnector
protected void doStop() throws Exception
{
super.doStop();
Set set=null;
Set<EndPoint> set = new HashSet<EndPoint>();
synchronized(_connections)
{
set= new HashSet(_connections);
set.addAll(_connections);
}
Iterator iter=set.iterator();
while(iter.hasNext())
for (EndPoint endPoint : set)
{
ConnectorEndPoint connection = (ConnectorEndPoint)iter.next();
ConnectorEndPoint connection = (ConnectorEndPoint)endPoint;
connection.close();
}
}
@Override
public void dump(Appendable out, String indent) throws IOException
{
super.dump(out, indent);
Set<EndPoint> connections = new HashSet<EndPoint>();
synchronized (_connections)
{
connections.addAll(_connections);
}
AggregateLifeCycle.dump(out, indent, connections);
}
/* ------------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------------- */

View File

@ -26,8 +26,8 @@ import org.eclipse.jetty.io.nio.AsyncConnection;
import org.eclipse.jetty.io.nio.IndirectNIOBuffer;
import org.eclipse.jetty.io.nio.SelectChannelEndPoint;
import org.eclipse.jetty.io.nio.SelectorManager;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.AbstractHttpConnection;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.util.HostMap;

View File

@ -58,10 +58,10 @@ import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.http.HttpException;
import org.eclipse.jetty.http.MimeTypes;
import org.eclipse.jetty.io.Buffer;
import org.eclipse.jetty.server.AbstractHttpConnection;
import org.eclipse.jetty.server.Dispatcher;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.HandlerContainer;
import org.eclipse.jetty.server.AbstractHttpConnection;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.util.Attributes;

View File

@ -29,7 +29,6 @@ import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.util.ByteArrayISO8859Writer;
import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;

View File

@ -29,8 +29,8 @@ import org.eclipse.jetty.http.MimeTypes;
import org.eclipse.jetty.io.Buffer;
import org.eclipse.jetty.io.ByteArrayBuffer;
import org.eclipse.jetty.io.WriterOutputStream;
import org.eclipse.jetty.server.Dispatcher;
import org.eclipse.jetty.server.AbstractHttpConnection;
import org.eclipse.jetty.server.Dispatcher;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Response;
import org.eclipse.jetty.server.handler.ContextHandler.Context;

View File

@ -4,13 +4,13 @@
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
package org.eclipse.jetty.server.nio;
import java.io.IOException;
@ -39,25 +39,25 @@ import org.eclipse.jetty.util.log.Logger;
/** Blocking NIO connector.
* This connector uses efficient NIO buffers with a traditional blocking thread model.
* Direct NIO buffers are used and a thread is allocated per connections.
*
*
* This connector is best used when there are a few very active connections.
*
*
* @org.apache.xbean.XBean element="blockingNioConnector" description="Creates a blocking NIO based socket connector"
*
*
*
*
*
*/
public class BlockingChannelConnector extends AbstractNIOConnector
public class BlockingChannelConnector extends AbstractNIOConnector
{
private static final Logger LOG = Log.getLogger(BlockingChannelConnector.class);
private transient ServerSocketChannel _acceptChannel;
private final Set<BlockingChannelEndPoint> _endpoints = new ConcurrentHashSet<BlockingChannelEndPoint>();
/* ------------------------------------------------------------ */
/** Constructor.
*
*
*/
public BlockingChannelConnector()
{
@ -103,12 +103,12 @@ public class BlockingChannelConnector extends AbstractNIOConnector
}
}
}
});
}
/* ------------------------------------------------------------ */
public void open() throws IOException
{
@ -128,12 +128,12 @@ public class BlockingChannelConnector extends AbstractNIOConnector
_acceptChannel.close();
_acceptChannel=null;
}
/* ------------------------------------------------------------ */
@Override
public void accept(int acceptorID)
throws IOException, InterruptedException
{
{
SocketChannel channel = _acceptChannel.accept();
channel.configureBlocking(true);
Socket socket=channel.socket();
@ -142,7 +142,7 @@ public class BlockingChannelConnector extends AbstractNIOConnector
BlockingChannelEndPoint connection=new BlockingChannelEndPoint(channel);
connection.dispatch();
}
/* ------------------------------------------------------------------------------- */
@Override
public void customize(EndPoint endpoint, Request request)
@ -161,7 +161,7 @@ public class BlockingChannelConnector extends AbstractNIOConnector
return -1;
return _acceptChannel.socket().getLocalPort();
}
/* ------------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------------- */
@ -170,14 +170,14 @@ public class BlockingChannelConnector extends AbstractNIOConnector
private Connection _connection;
private int _timeout;
private volatile long _idleTimestamp;
BlockingChannelEndPoint(ByteChannel channel)
BlockingChannelEndPoint(ByteChannel channel)
throws IOException
{
super(channel,BlockingChannelConnector.this._maxIdleTime);
_connection = new BlockingHttpConnection(BlockingChannelConnector.this,this,getServer());
}
/* ------------------------------------------------------------ */
/** Get the connection.
* @return the connection
@ -186,7 +186,7 @@ public class BlockingChannelConnector extends AbstractNIOConnector
{
return _connection;
}
/* ------------------------------------------------------------ */
public void setConnection(Connection connection)
{
@ -214,7 +214,7 @@ public class BlockingChannelConnector extends AbstractNIOConnector
LOG.ignore(e);
}
}
/* ------------------------------------------------------------ */
void dispatch() throws IOException
{
@ -224,7 +224,7 @@ public class BlockingChannelConnector extends AbstractNIOConnector
super.close();
}
}
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.io.nio.ChannelEndPoint#fill(org.eclipse.jetty.io.Buffer)
@ -288,9 +288,9 @@ public class BlockingChannelConnector extends AbstractNIOConnector
_timeout=getMaxIdleTime();
}
}
_connection = _connection.handle();
}
}
catch (EofException e)
@ -305,10 +305,6 @@ public class BlockingChannelConnector extends AbstractNIOConnector
try{super.close();}
catch(IOException e2){LOG.ignore(e2);}
}
catch(ThreadDeath e)
{
throw e;
}
catch(Throwable e)
{
LOG.warn("handle failed",e);
@ -319,14 +315,14 @@ public class BlockingChannelConnector extends AbstractNIOConnector
{
connectionClosed(_connection);
_endpoints.remove(this);
// wait for client to close, but if not, close ourselves.
try
{
if (!_socket.isClosed())
{
long timestamp=System.currentTimeMillis();
int max_idle=getMaxIdleTime();
int max_idle=getMaxIdleTime();
_socket.setSoTimeout(getMaxIdleTime());
int c=0;

View File

@ -122,7 +122,7 @@ public class SelectChannelConnector extends AbstractNIOConnector
public void customize(EndPoint endpoint, Request request) throws IOException
{
AsyncEndPoint aEndp = ((AsyncEndPoint)endpoint);
aEndp.cancelIdle();
aEndp.setCheckForIdle(false);
request.setTimeStamp(System.currentTimeMillis());
endpoint.setMaxIdleTime(_maxIdleTime);
super.customize(endpoint, request);
@ -132,7 +132,8 @@ public class SelectChannelConnector extends AbstractNIOConnector
@Override
public void persist(EndPoint endpoint) throws IOException
{
((AsyncEndPoint)endpoint).scheduleIdle();
AsyncEndPoint aEndp = ((AsyncEndPoint)endpoint);
aEndp.setCheckForIdle(true);
super.persist(endpoint);
}
@ -300,7 +301,7 @@ public class SelectChannelConnector extends AbstractNIOConnector
/* ------------------------------------------------------------ */
public void dump(Appendable out, String indent) throws IOException
{
out.append(String.valueOf(this)).append("\n");
super.dump(out, indent);
ServerSocketChannel channel;
synchronized (this)
{

View File

@ -4,11 +4,11 @@
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
package org.eclipse.jetty.server.session;
@ -43,12 +43,12 @@ import org.eclipse.jetty.util.log.Logger;
* <p>
* This manager will create it's own Timer instance to scavenge threads, unless it discovers a shared Timer instance
* set as the "org.eclipse.jetty.server.session.timer" attribute of the ContextHandler.
*
*
*/
public class HashSessionManager extends AbstractSessionManager
{
final static Logger __log = SessionHandler.LOG;
protected final ConcurrentMap<String,HashedSession> _sessions=new ConcurrentHashMap<String,HashedSession>();
private static int __id;
private Timer _timer;
@ -61,7 +61,7 @@ public class HashSessionManager extends AbstractSessionManager
File _storeDir;
private boolean _lazyLoad=false;
private volatile boolean _sessionsLoaded=false;
/* ------------------------------------------------------------ */
public HashSessionManager()
{
@ -86,7 +86,7 @@ public class HashSessionManager extends AbstractSessionManager
_timerStop=true;
_timer=new Timer("HashSessionScavenger-"+__id++, true);
}
setScavengePeriod(getScavengePeriod());
if (_storeDir!=null)
@ -97,7 +97,7 @@ public class HashSessionManager extends AbstractSessionManager
if (!_lazyLoad)
restoreSessions();
}
setSavePeriod(getSavePeriod());
}
@ -107,7 +107,7 @@ public class HashSessionManager extends AbstractSessionManager
*/
@Override
public void doStop() throws Exception
{
{
// stop the scavengers
synchronized(this)
{
@ -121,16 +121,16 @@ public class HashSessionManager extends AbstractSessionManager
_timer.cancel();
_timer=null;
}
// This will callback invalidate sessions - where we decide if we will save
// This will callback invalidate sessions - where we decide if we will save
super.doStop();
_sessions.clear();
}
/* ------------------------------------------------------------ */
/**
/**
* @return the period in seconds at which a check is made for sessions to be invalidated.
*/
public int getScavengePeriod()
@ -154,7 +154,7 @@ public class HashSessionManager extends AbstractSessionManager
/* ------------------------------------------------------------ */
/**
* @return seconds Idle period after which a session is saved
* @return seconds Idle period after which a session is saved
*/
public int getIdleSavePeriod()
{
@ -163,15 +163,15 @@ public class HashSessionManager extends AbstractSessionManager
return _idleSavePeriodMs / 1000;
}
/* ------------------------------------------------------------ */
/**
* Configures the period in seconds after which a session is deemed idle and saved
* to save on session memory.
*
* The session is persisted, the values attribute map is cleared and the session set to idled.
*
* @param seconds Idle period after which a session is saved
* Configures the period in seconds after which a session is deemed idle and saved
* to save on session memory.
*
* The session is persisted, the values attribute map is cleared and the session set to idled.
*
* @param seconds Idle period after which a session is saved
*/
public void setIdleSavePeriod(int seconds)
{
@ -197,7 +197,7 @@ public class HashSessionManager extends AbstractSessionManager
if (period < 0)
period=0;
_savePeriodMs=period;
if (_timer!=null)
{
synchronized (this)
@ -219,7 +219,7 @@ public class HashSessionManager extends AbstractSessionManager
{
__log.warn(e);
}
}
}
};
_timer.schedule(_saveTask,_savePeriodMs,_savePeriodMs);
}
@ -235,10 +235,10 @@ public class HashSessionManager extends AbstractSessionManager
{
if (_savePeriodMs<=0)
return 0;
return _savePeriodMs/1000;
}
/* ------------------------------------------------------------ */
/**
* @param seconds the period in seconds at which a check is made for sessions to be invalidated.
@ -268,13 +268,13 @@ public class HashSessionManager extends AbstractSessionManager
public void run()
{
scavenge();
}
}
};
_timer.schedule(_task,_scavengePeriodMs,_scavengePeriodMs);
}
}
}
/* -------------------------------------------------------------- */
/**
* Find sessions that have timed out and invalidate them. This runs in the
@ -285,14 +285,14 @@ public class HashSessionManager extends AbstractSessionManager
//don't attempt to scavenge if we are shutting down
if (isStopping() || isStopped())
return;
Thread thread=Thread.currentThread();
ClassLoader old_loader=thread.getContextClassLoader();
try
{
if (_loader!=null)
thread.setContextClassLoader(_loader);
// For each session
long now=System.currentTimeMillis();
for (Iterator<HashedSession> i=_sessions.values().iterator(); i.hasNext();)
@ -306,14 +306,10 @@ public class HashSessionManager extends AbstractSessionManager
}
else if (_idleSavePeriodMs>0&&session.getAccessed()+_idleSavePeriodMs<now)
{
session.idle();
session.idle();
}
}
}
catch (ThreadDeath e)
{
throw e;
}
catch (Throwable t)
{
__log.warn("Problem scavenging sessions", t);
@ -323,7 +319,7 @@ public class HashSessionManager extends AbstractSessionManager
thread.setContextClassLoader(old_loader);
}
}
/* ------------------------------------------------------------ */
@Override
protected void addSession(AbstractSession session)
@ -331,7 +327,7 @@ public class HashSessionManager extends AbstractSessionManager
if (isRunning())
_sessions.put(session.getClusterId(),(HashedSession)session);
}
/* ------------------------------------------------------------ */
@Override
public AbstractSession getSession(String idInCluster)
@ -351,7 +347,7 @@ public class HashSessionManager extends AbstractSessionManager
Map<String,HashedSession> sessions=_sessions;
if (sessions==null)
return null;
HashedSession session = sessions.get(idInCluster);
if (session == null && _lazyLoad)
@ -361,7 +357,7 @@ public class HashSessionManager extends AbstractSessionManager
if (_idleSavePeriodMs!=0)
session.deIdle();
return session;
}
@ -389,7 +385,7 @@ public class HashSessionManager extends AbstractSessionManager
for (HashedSession session : sessions)
session.invalidate();
}
// check that no new sessions were created while we were iterating
sessions=new ArrayList<HashedSession>(_sessions.values());
}
@ -401,13 +397,13 @@ public class HashSessionManager extends AbstractSessionManager
{
return new HashedSession(this, request);
}
/* ------------------------------------------------------------ */
protected AbstractSession newSession(long created, long accessed, String clusterId)
{
return new HashedSession(this, created,accessed, clusterId);
}
/* ------------------------------------------------------------ */
@Override
protected boolean removeSession(String clusterId)
@ -432,7 +428,7 @@ public class HashSessionManager extends AbstractSessionManager
{
_lazyLoad = lazyLoad;
}
/* ------------------------------------------------------------ */
public boolean isLazyLoad()
{
@ -443,7 +439,7 @@ public class HashSessionManager extends AbstractSessionManager
public void restoreSessions () throws Exception
{
_sessionsLoaded = true;
if (_storeDir==null || !_storeDir.exists())
{
return;
@ -470,9 +466,9 @@ public class HashSessionManager extends AbstractSessionManager
File file = new File(_storeDir,idInCuster);
if (file.exists())
{
FileInputStream in = new FileInputStream(file);
FileInputStream in = new FileInputStream(file);
HashedSession session = restoreSession(in, null);
in.close();
in.close();
addSession(session, false);
session.didActivate();
file.delete();
@ -485,7 +481,7 @@ public class HashSessionManager extends AbstractSessionManager
}
return null;
}
/* ------------------------------------------------------------ */
public void saveSessions(boolean reactivate) throws Exception
{
@ -493,7 +489,7 @@ public class HashSessionManager extends AbstractSessionManager
{
return;
}
if (!_storeDir.canWrite())
{
__log.warn ("Unable to save Sessions: Session persistence storage directory "+_storeDir.getAbsolutePath()+ " is not writeable");
@ -508,7 +504,7 @@ public class HashSessionManager extends AbstractSessionManager
public HashedSession restoreSession (InputStream is, HashedSession session) throws Exception
{
/*
* Take care of this class's fields first by calling
* Take care of this class's fields first by calling
* defaultReadObject
*/
DataInputStream in = new DataInputStream(is);
@ -517,7 +513,7 @@ public class HashSessionManager extends AbstractSessionManager
long created = in.readLong();
long accessed = in.readLong();
int requests = in.readInt();
if (session == null)
session = (HashedSession)newSession(created, accessed, clusterId);
session.setRequests(requests);
@ -538,7 +534,7 @@ public class HashSessionManager extends AbstractSessionManager
return session;
}
/* ------------------------------------------------------------ */
/* ------------------------------------------------------------ */
protected class ClassLoadingObjectInputStream extends ObjectInputStream

View File

@ -4,11 +4,11 @@
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
@ -46,9 +46,9 @@ import org.eclipse.jetty.util.log.Logger;
* JDBCSessionManager
*
* SessionManager that persists sessions to a database to enable clustering.
*
*
* Session data is persisted to the JettySessions table:
*
*
* rowId (unique in cluster: webapp name/path + virtualhost + sessionId)
* contextPath (of the context owning the session)
* sessionId (unique in a context)
@ -60,7 +60,7 @@ import org.eclipse.jetty.util.log.Logger;
* lastSavedTime (last time in milliseconds session access times were saved)
* expiryTime (time in milliseconds that the session is due to expire)
* map (attribute map)
*
*
* As an optimization, to prevent thrashing the database, we do not persist
* the accessTime and lastAccessTime every time the session is accessed. Rather,
* we write it out every so often. The frequency is controlled by the saveIntervalSec
@ -69,18 +69,18 @@ import org.eclipse.jetty.util.log.Logger;
public class JDBCSessionManager extends AbstractSessionManager
{
private static final Logger LOG = Log.getLogger(JDBCSessionManager.class);
protected String __insertSession;
protected String __deleteSession;
protected String __selectSession;
protected String __updateSession;
protected String __updateSessionNode;
protected String __insertSession;
protected String __deleteSession;
protected String __selectSession;
protected String __updateSession;
protected String __updateSessionNode;
protected String __updateSessionAccessTime;
protected String __sessionTableRowId;
private ConcurrentHashMap<String, AbstractSession> _sessions;
protected long _saveIntervalSec = 60; //only persist changes to session access times every 60 secs
/**
* SessionData
*
@ -110,7 +110,7 @@ public class JDBCSessionManager extends AbstractSessionManager
_attributes = new HashMap<String,Object>();
_lastNode = getSessionIdManager().getWorkerName();
}
public SessionData (String sessionId,Map<String,Object> attributes)
{
_id=sessionId;
@ -129,23 +129,23 @@ public class JDBCSessionManager extends AbstractSessionManager
{
return _created;
}
protected synchronized void setCreated (long ms)
{
_created = ms;
}
public synchronized long getAccessed ()
{
return _accessed;
}
protected synchronized void setAccessed (long ms)
{
_accessed = ms;
}
public synchronized void setMaxIdleMs (long ms)
{
_maxIdleMs = ms;
@ -175,77 +175,77 @@ public class JDBCSessionManager extends AbstractSessionManager
{
return _cookieSet;
}
public synchronized void setRowId (String rowId)
{
_rowId=rowId;
}
protected synchronized String getRowId()
{
return _rowId;
}
protected synchronized Map<String,Object> getAttributeMap ()
{
return _attributes;
}
protected synchronized void setAttributeMap (Map<String,Object> map)
{
_attributes = map;
}
}
public synchronized void setLastNode (String node)
{
_lastNode=node;
}
public synchronized String getLastNode ()
{
return _lastNode;
}
public synchronized void setCanonicalContext(String str)
{
_canonicalContext=str;
}
public synchronized String getCanonicalContext ()
{
return _canonicalContext;
}
public synchronized long getLastSaved ()
{
return _lastSaved;
}
public synchronized void setLastSaved (long time)
{
_lastSaved=time;
}
public synchronized void setExpiryTime (long time)
{
_expiryTime=time;
_expiryTime=time;
}
public synchronized long getExpiryTime ()
{
return _expiryTime;
}
public synchronized void setVirtualHost (String vhost)
{
_virtualHost=vhost;
}
public synchronized String getVirtualHost ()
{
return _virtualHost;
}
@Override
public String toString ()
{
@ -256,8 +256,8 @@ public class JDBCSessionManager extends AbstractSessionManager
}
}
/**
* Session
*
@ -271,12 +271,12 @@ public class JDBCSessionManager extends AbstractSessionManager
/**
* Session from a request.
*
*
* @param request
*/
protected Session (HttpServletRequest request)
{
super(JDBCSessionManager.this,request);
super(JDBCSessionManager.this,request);
_data = new SessionData(getClusterId(),_jdbcAttributes);
if (_dftMaxIdleSecs>0)
_data.setMaxIdleMs(_dftMaxIdleSecs*1000);
@ -299,7 +299,7 @@ public class JDBCSessionManager extends AbstractSessionManager
_jdbcAttributes.putAll(_data.getAttributeMap());
_data.setAttributeMap(_jdbcAttributes);
}
@Override
public void setAttribute (String name, Object value)
{
@ -310,20 +310,20 @@ public class JDBCSessionManager extends AbstractSessionManager
@Override
public void removeAttribute (String name)
{
super.removeAttribute(name);
super.removeAttribute(name);
_dirty=true;
}
@Override
protected void cookieSet()
{
_data.setCookieSet(_data.getAccessed());
}
/**
/**
* Entry to session.
* Called by SessionHandler on inbound request and the session already exists in this node's memory.
*
*
* @see org.eclipse.jetty.server.session.AbstractSession#access(long)
*/
@Override
@ -341,7 +341,7 @@ public class JDBCSessionManager extends AbstractSessionManager
return false;
}
/**
/**
* Exit from session
* @see org.eclipse.jetty.server.session.AbstractSession#complete()
*/
@ -352,7 +352,7 @@ public class JDBCSessionManager extends AbstractSessionManager
try
{
if (_dirty)
{
{
//The session attributes have changed, write to the db, ensuring
//http passivation/activation listeners called
willPassivate();
@ -360,7 +360,7 @@ public class JDBCSessionManager extends AbstractSessionManager
didActivate();
}
else if ((_data._accessed - _data._lastSaved) >= (getSaveInterval() * 1000))
{
{
updateSessionAccessTime(_data);
}
}
@ -373,19 +373,19 @@ public class JDBCSessionManager extends AbstractSessionManager
_dirty=false;
}
}
@Override
protected void timeout() throws IllegalStateException
{
if (LOG.isDebugEnabled())
if (LOG.isDebugEnabled())
LOG.debug("Timing out session id="+getClusterId());
super.timeout();
}
}
/**
* ClassLoadingObjectInputStream
*
@ -416,46 +416,46 @@ public class JDBCSessionManager extends AbstractSessionManager
}
}
}
/**
* Set the time in seconds which is the interval between
* saving the session access time to the database.
*
*
* This is an optimization that prevents the database from
* being overloaded when a session is accessed very frequently.
*
*
* On session exit, if the session attributes have NOT changed,
* the time at which we last saved the accessed
* time is compared to the current accessed time. If the interval
* is at least saveIntervalSecs, then the access time will be
* persisted to the database.
*
*
* If any session attribute does change, then the attributes and
* the accessed time are persisted.
*
*
* @param sec
*/
public void setSaveInterval (long sec)
{
_saveIntervalSec=sec;
}
public long getSaveInterval ()
{
return _saveIntervalSec;
}
/**
* A method that can be implemented in subclasses to support
* distributed caching of sessions. This method will be
* called whenever the session is written to the database
* because the session data has changed.
*
*
* This could be used eg with a JMS backplane to notify nodes
* that the session has changed and to delete the session from
* the node's cache, and re-read it from the database.
@ -463,46 +463,46 @@ public class JDBCSessionManager extends AbstractSessionManager
*/
public void cacheInvalidate (Session session)
{
}
/**
/**
* A session has been requested by it's id on this node.
*
*
* Load the session by id AND context path from the database.
* Multiple contexts may share the same session id (due to dispatching)
* but they CANNOT share the same contents.
*
*
* Check if last node id is my node id, if so, then the session we have
* in memory cannot be stale. If another node used the session last, then
* we need to refresh from the db.
*
* NOTE: this method will go to the database, so if you only want to check
*
* NOTE: this method will go to the database, so if you only want to check
* for the existence of a Session in memory, use _sessions.get(id) instead.
*
*
* @see org.eclipse.jetty.server.session.AbstractSessionManager#getSession(java.lang.String)
*/
@Override
public Session getSession(String idInCluster)
{
Session session = (Session)_sessions.get(idInCluster);
synchronized (this)
{
{
try
{
//check if we need to reload the session -
{
//check if we need to reload the session -
//as an optimization, don't reload on every access
//to reduce the load on the database. This introduces a window of
//to reduce the load on the database. This introduces a window of
//possibility that the node may decide that the session is local to it,
//when the session has actually been live on another node, and then
//re-migrated to this node. This should be an extremely rare occurrence,
//as load-balancers are generally well-behaved and consistently send
//sessions to the same node, changing only iff that node fails.
//as load-balancers are generally well-behaved and consistently send
//sessions to the same node, changing only iff that node fails.
SessionData data = null;
long now = System.currentTimeMillis();
if (LOG.isDebugEnabled())
if (LOG.isDebugEnabled())
{
if (session==null)
LOG.debug("getSession("+idInCluster+"): not in session map,"+
@ -518,9 +518,9 @@ public class JDBCSessionManager extends AbstractSessionManager
" thisNode="+getSessionIdManager().getWorkerName()+
" difference="+(now - session._data._lastSaved));
}
if (session==null || ((now - session._data._lastSaved) >= (_saveIntervalSec * 1000)))
{
{
LOG.debug("getSession("+idInCluster+"): no session in session map or stale session. Reloading session data from db.");
data = loadSession(idInCluster, canonicalize(_context.getContextPath()), getVirtualHost(_context));
}
@ -531,10 +531,10 @@ public class JDBCSessionManager extends AbstractSessionManager
}
else
{
LOG.debug("getSession("+idInCluster+"): session in session map");
LOG.debug("getSession("+idInCluster+"): session in session map");
data = session._data;
}
if (data != null)
{
if (!data.getLastNode().equals(getSessionIdManager().getWorkerName()) || session==null)
@ -554,7 +554,7 @@ public class JDBCSessionManager extends AbstractSessionManager
}
else
if (LOG.isDebugEnabled()) LOG.debug("getSession("+idInCluster+"): Session has expired");
}
else
if (LOG.isDebugEnabled()) LOG.debug("getSession("+idInCluster+"): Session not stale "+session._data);
@ -566,7 +566,7 @@ public class JDBCSessionManager extends AbstractSessionManager
session=null;
if (LOG.isDebugEnabled()) LOG.debug("getSession("+idInCluster+"): No session in database matching id="+idInCluster);
}
return session;
}
catch (Exception e)
@ -576,10 +576,10 @@ public class JDBCSessionManager extends AbstractSessionManager
}
}
}
/**
/**
* Get the number of sessions.
*
*
* @see org.eclipse.jetty.server.session.AbstractSessionManager#getSessions()
*/
@Override
@ -594,9 +594,9 @@ public class JDBCSessionManager extends AbstractSessionManager
}
/**
/**
* Start the session manager.
*
*
* @see org.eclipse.jetty.server.session.AbstractSessionManager#doStart()
*/
@Override
@ -604,17 +604,17 @@ public class JDBCSessionManager extends AbstractSessionManager
{
if (_sessionIdManager==null)
throw new IllegalStateException("No session id manager defined");
prepareTables();
_sessions = new ConcurrentHashMap<String, AbstractSession>();
super.doStart();
}
/**
/**
* Stop the session manager.
*
*
* @see org.eclipse.jetty.server.session.AbstractSessionManager#doStop()
*/
@Override
@ -622,10 +622,10 @@ public class JDBCSessionManager extends AbstractSessionManager
{
_sessions.clear();
_sessions = null;
super.doStop();
}
}
@Override
protected void invalidateSessions()
{
@ -637,10 +637,10 @@ public class JDBCSessionManager extends AbstractSessionManager
//any other nodes
}
/**
* Invalidate a session.
*
*
* @param idInCluster
*/
protected void invalidateSession (String idInCluster)
@ -650,24 +650,24 @@ public class JDBCSessionManager extends AbstractSessionManager
{
session = (Session)_sessions.get(idInCluster);
}
if (session != null)
{
session.invalidate();
}
}
/**
/**
* Delete an existing session, both from the in-memory map and
* the database.
*
*
* @see org.eclipse.jetty.server.session.AbstractSessionManager#removeSession(java.lang.String)
*/
@Override
protected boolean removeSession(String idInCluster)
{
synchronized (this)
{
{
Session session = (Session)_sessions.remove(idInCluster);
try
{
@ -683,9 +683,9 @@ public class JDBCSessionManager extends AbstractSessionManager
}
/**
/**
* Add a newly created session to our in-memory list for this node and persist it.
*
*
* @see org.eclipse.jetty.server.session.AbstractSessionManager#addSession(org.eclipse.jetty.server.session.AbstractSession)
*/
@Override
@ -698,7 +698,7 @@ public class JDBCSessionManager extends AbstractSessionManager
{
_sessions.put(session.getClusterId(), session);
}
//TODO or delay the store until exit out of session? If we crash before we store it
//then session data will be lost.
try
@ -714,9 +714,9 @@ public class JDBCSessionManager extends AbstractSessionManager
}
/**
/**
* Make a new Session.
*
*
* @see org.eclipse.jetty.server.session.AbstractSessionManager#newSession(javax.servlet.http.HttpServletRequest)
*/
@Override
@ -724,9 +724,9 @@ public class JDBCSessionManager extends AbstractSessionManager
{
return new Session(request);
}
/* ------------------------------------------------------------ */
/** Remove session from manager
/** Remove session from manager
* @param session The session to remove
* @param invalidate True if {@link HttpSessionListener#sessionDestroyed(HttpSessionEvent)} and
* {@link SessionIdManager#invalidateAll(String)} should be called.
@ -736,7 +736,7 @@ public class JDBCSessionManager extends AbstractSessionManager
{
// Remove session from context and global maps
boolean removed = false;
synchronized (this)
{
//take this session out of the map of sessions for this context
@ -751,10 +751,10 @@ public class JDBCSessionManager extends AbstractSessionManager
{
// Remove session from all context and global id maps
_sessionIdManager.removeSession(session);
if (invalidate)
_sessionIdManager.invalidateAll(session.getClusterId());
if (invalidate && !_sessionListeners.isEmpty())
{
HttpSessionEvent event=new HttpSessionEvent(session);
@ -767,16 +767,16 @@ public class JDBCSessionManager extends AbstractSessionManager
}
}
}
/**
* Expire any Sessions we have in memory matching the list of
* expired Session ids.
*
*
* @param sessionIds
*/
protected void expire (List<?> sessionIds)
{
{
//don't attempt to scavenge if we are shutting down
if (isStopping() || isStopped())
return;
@ -791,9 +791,9 @@ public class JDBCSessionManager extends AbstractSessionManager
while (itor.hasNext())
{
String sessionId = (String)itor.next();
if (LOG.isDebugEnabled())
if (LOG.isDebugEnabled())
LOG.debug("Expiring session id "+sessionId);
Session session = (Session)_sessions.get(sessionId);
if (session != null)
{
@ -802,15 +802,11 @@ public class JDBCSessionManager extends AbstractSessionManager
}
else
{
if (LOG.isDebugEnabled())
if (LOG.isDebugEnabled())
LOG.debug("Unrecognized session id="+sessionId);
}
}
}
catch (ThreadDeath e)
{
throw e;
}
catch (Throwable t)
{
LOG.warn("Problem expiring sessions", t);
@ -820,12 +816,12 @@ public class JDBCSessionManager extends AbstractSessionManager
thread.setContextClassLoader(old_loader);
}
}
protected void prepareTables ()
{
__sessionTableRowId = ((JDBCSessionIdManager)_sessionIdManager)._sessionTableRowId;
__insertSession = "insert into "+((JDBCSessionIdManager)_sessionIdManager)._sessionTable+
" ("+__sessionTableRowId+", sessionId, contextPath, virtualHost, lastNode, accessTime, lastAccessTime, createTime, cookieTime, lastSavedTime, expiryTime, map) "+
" values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
@ -845,7 +841,7 @@ public class JDBCSessionManager extends AbstractSessionManager
__updateSessionAccessTime = "update "+((JDBCSessionIdManager)_sessionIdManager)._sessionTable+
" set lastNode = ?, accessTime = ?, lastAccessTime = ?, lastSavedTime = ?, expiryTime = ? where "+__sessionTableRowId+" = ?";
}
/**
* Load a session from the database
* @param id
@ -866,7 +862,7 @@ public class JDBCSessionManager extends AbstractSessionManager
Connection connection=null;
PreparedStatement statement = null;
try
{
{
connection = getConnection();
statement = connection.prepareStatement(__selectSession);
statement.setString(1, id);
@ -909,24 +905,24 @@ public class JDBCSessionManager extends AbstractSessionManager
try { connection.close();}
catch(Exception e) { LOG.warn(e); }
}
}
}
}
};
if (_context==null)
load.run();
else
_context.getContextHandler().handle(load);
if (_exception.get()!=null)
throw _exception.get();
return _reference.get();
}
/**
* Insert a session into the database.
*
*
* @param data
* @throws Exception
*/
@ -935,14 +931,14 @@ public class JDBCSessionManager extends AbstractSessionManager
{
if (data==null)
return;
//put into the database
//put into the database
Connection connection = getConnection();
PreparedStatement statement = null;
try
{
{
String rowId = calculateRowId(data);
long now = System.currentTimeMillis();
connection.setAutoCommit(true);
statement = connection.prepareStatement(__insertSession);
@ -957,34 +953,34 @@ public class JDBCSessionManager extends AbstractSessionManager
statement.setLong(9, data.getCookieSet());//time cookie was set
statement.setLong(10, now); //last saved time
statement.setLong(11, data.getExpiryTime());
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(data.getAttributeMap());
byte[] bytes = baos.toByteArray();
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
statement.setBinaryStream(12, bais, bytes.length);//attribute map as blob
statement.executeUpdate();
data.setRowId(rowId); //set it on the in-memory data as well as in db
data.setLastSaved(now);
if (LOG.isDebugEnabled())
LOG.debug("Stored session "+data);
}
}
finally
{
if (connection!=null)
connection.close();
}
}
/**
* Update data on an existing persisted session.
*
*
* @param data
* @throws Exception
*/
@ -993,30 +989,30 @@ public class JDBCSessionManager extends AbstractSessionManager
{
if (data==null)
return;
Connection connection = getConnection();
PreparedStatement statement = null;
try
{
{
long now = System.currentTimeMillis();
connection.setAutoCommit(true);
statement = connection.prepareStatement(__updateSession);
statement = connection.prepareStatement(__updateSession);
statement.setString(1, getSessionIdManager().getWorkerName());//my node id
statement.setLong(2, data.getAccessed());//accessTime
statement.setLong(3, data.getLastAccessed()); //lastAccessTime
statement.setLong(4, now); //last saved time
statement.setLong(5, data.getExpiryTime());
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(data.getAttributeMap());
byte[] bytes = baos.toByteArray();
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
statement.setBinaryStream(6, bais, bytes.length);//attribute map as blob
statement.setBinaryStream(6, bais, bytes.length);//attribute map as blob
statement.setString(7, data.getRowId()); //rowId
statement.executeUpdate();
data.setLastSaved(now);
if (LOG.isDebugEnabled())
LOG.debug("Updated session "+data);
@ -1027,11 +1023,11 @@ public class JDBCSessionManager extends AbstractSessionManager
connection.close();
}
}
/**
* Update the node on which the session was last seen to be my node.
*
*
* @param data
* @throws Exception
*/
@ -1042,7 +1038,7 @@ public class JDBCSessionManager extends AbstractSessionManager
Connection connection = getConnection();
PreparedStatement statement = null;
try
{
{
connection.setAutoCommit(true);
statement = connection.prepareStatement(__updateSessionNode);
statement.setString(1, nodeId);
@ -1058,10 +1054,10 @@ public class JDBCSessionManager extends AbstractSessionManager
connection.close();
}
}
/**
* Persist the time the session was last accessed.
*
*
* @param data
* @throws Exception
*/
@ -1071,7 +1067,7 @@ public class JDBCSessionManager extends AbstractSessionManager
Connection connection = getConnection();
PreparedStatement statement = null;
try
{
{
long now = System.currentTimeMillis();
connection.setAutoCommit(true);
statement = connection.prepareStatement(__updateSessionAccessTime);
@ -1093,14 +1089,14 @@ public class JDBCSessionManager extends AbstractSessionManager
connection.close();
}
}
/**
* Delete a session from the database. Should only be called
* when the session has been invalidated.
*
*
* @param data
* @throws Exception
*/
@ -1122,11 +1118,11 @@ public class JDBCSessionManager extends AbstractSessionManager
{
if (connection!=null)
connection.close();
}
}
}
/**
* Get a connection from the driver.
* @return
@ -1134,13 +1130,13 @@ public class JDBCSessionManager extends AbstractSessionManager
*/
private Connection getConnection ()
throws SQLException
{
{
return ((JDBCSessionIdManager)getSessionIdManager()).getConnection();
}
/**
* Calculate a unique id for this session across the cluster.
*
*
* Unique id is composed of: contextpath_virtualhost0_sessionid
* @param data
* @return
@ -1152,31 +1148,31 @@ public class JDBCSessionManager extends AbstractSessionManager
rowId = rowId+"_"+data.getId();
return rowId;
}
/**
* Get the first virtual host for the context.
*
*
* Used to help identify the exact session/contextPath.
*
*
* @return 0.0.0.0 if no virtual host is defined
*/
private String getVirtualHost (ContextHandler.Context context)
{
String vhost = "0.0.0.0";
if (context==null)
return vhost;
String [] vhosts = context.getContextHandler().getVirtualHosts();
if (vhosts==null || vhosts.length==0 || vhosts[0]==null)
return vhost;
return vhosts[0];
}
/**
* Make an acceptable file name from a context path.
*
*
* @param path
* @return
*/
@ -1184,7 +1180,7 @@ public class JDBCSessionManager extends AbstractSessionManager
{
if (path==null)
return "";
return path.replace('/', '_').replace('.','_').replace('\\','_');
}
}

View File

@ -15,6 +15,7 @@ package org.eclipse.jetty.server.ssl;
import java.io.IOException;
import java.nio.channels.SocketChannel;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLSession;

View File

@ -22,7 +22,6 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Arrays;
import java.util.Random;
import java.util.concurrent.Exchanger;
import java.util.concurrent.TimeUnit;
@ -35,6 +34,7 @@ import org.eclipse.jetty.continuation.ContinuationSupport;
import org.eclipse.jetty.server.handler.AbstractHandler;
import org.eclipse.jetty.server.nio.SelectChannelConnector;
import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.StringUtil;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
@ -75,12 +75,16 @@ public class AsyncRequestReadTest
Arrays.fill(content, (byte)120);
OutputStream out = socket.getOutputStream();
out.write("POST / HTTP/1.1\r\n".getBytes());
out.write("Host: localhost\r\n".getBytes());
out.write(("Content-Length: "+content.length+"\r\n").getBytes());
out.write("Content-Type: bytes\r\n".getBytes());
out.write("Connection: close\r\n".getBytes());
out.write("\r\n".getBytes());
String header=
"POST / HTTP/1.1\r\n"+
"Host: localhost\r\n"+
"Content-Length: "+content.length+"\r\n"+
"Content-Type: bytes\r\n"+
"Connection: close\r\n"+
"\r\n";
byte[] h=header.getBytes(StringUtil.__ISO_8859_1);
out.write(h);
out.flush();
out.write(content,0,4*4096);
@ -98,7 +102,7 @@ public class AsyncRequestReadTest
long total=__total.exchange(0L,30,TimeUnit.SECONDS);
assertEquals(content.length, total);
}
@Test
public void tests() throws Exception
{
@ -114,7 +118,7 @@ public class AsyncRequestReadTest
public void runTest(int contentSize, int chunkSize, int chunks, int delayMS) throws Exception
{
String tst=contentSize+","+chunkSize+","+chunks+","+delayMS;
System.err.println(tst);
//System.err.println(tst);
final Socket socket = new Socket("localhost",connector.getLocalPort());

View File

@ -30,6 +30,7 @@ import java.util.Map;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSessionContext;
@ -487,6 +488,24 @@ public class ResponseTest
}
}
@Test
public void testAddCookie() throws Exception
{
Response response = new Response(new TestHttpConnection(connector,new ByteArrayEndPoint(), connector.getServer()));
Cookie cookie=new Cookie("name","value");
cookie.setDomain("domain");
cookie.setPath("/path");
cookie.setSecure(true);
cookie.setComment("comment__HTTP_ONLY__");
response.addCookie(cookie);
String set = response.getHttpFields().getStringField("Set-Cookie");
assertEquals("name=value;Path=/path;Domain=domain;Secure;HttpOnly",set);
}
private Response newResponse()
{
ByteArrayEndPoint endPoint = new ByteArrayEndPoint();

View File

@ -19,7 +19,6 @@ import java.io.OutputStream;
import java.net.Socket;
import java.security.KeyStore;
import java.util.Arrays;
import java.util.Random;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;

View File

@ -23,7 +23,6 @@ import javax.net.ssl.TrustManagerFactory;
import org.eclipse.jetty.server.ConnectorTimeoutTest;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.junit.BeforeClass;
import org.junit.Test;
public class SslSelectChannelTimeoutTest extends ConnectorTimeoutTest
{

View File

@ -38,7 +38,6 @@ import org.eclipse.jetty.server.handler.AbstractHandler;
import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;

View File

@ -40,9 +40,9 @@ import org.eclipse.jetty.http.MimeTypes;
import org.eclipse.jetty.io.Buffer;
import org.eclipse.jetty.io.ByteArrayBuffer;
import org.eclipse.jetty.io.WriterOutputStream;
import org.eclipse.jetty.server.AbstractHttpConnection;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.Dispatcher;
import org.eclipse.jetty.server.AbstractHttpConnection;
import org.eclipse.jetty.server.HttpOutput;
import org.eclipse.jetty.server.InclusiveByteRange;
import org.eclipse.jetty.server.ResourceCache;

View File

@ -25,8 +25,8 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.http.HttpMethods;
import org.eclipse.jetty.server.Dispatcher;
import org.eclipse.jetty.server.AbstractHttpConnection;
import org.eclipse.jetty.server.Dispatcher;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.server.handler.ErrorHandler;

View File

@ -26,9 +26,9 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.server.AbstractHttpConnection;
import org.eclipse.jetty.server.Dispatcher;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.AbstractHttpConnection;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.server.handler.HandlerWrapper;

View File

@ -50,8 +50,10 @@ import org.eclipse.jetty.io.EofException;
import org.eclipse.jetty.io.RuntimeIOException;
import org.eclipse.jetty.security.IdentityService;
import org.eclipse.jetty.security.SecurityHandler;
import org.eclipse.jetty.server.AbstractHttpConnection;
import org.eclipse.jetty.server.Dispatcher;
import org.eclipse.jetty.server.AbstractHttpConnection;
import org.eclipse.jetty.server.DispatcherType;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServletRequestHttpWrapper;

View File

@ -134,7 +134,7 @@ public abstract class Utf8Appendable
protected void appendByte(byte b) throws IOException
{
if (b > 0 && isUtf8SequenceComplete())
if (b > 0 && _state == UTF8_ACCEPT)
{
_appendable.append((char)(b & 0xFF));
}
@ -142,41 +142,48 @@ public abstract class Utf8Appendable
{
int i = b & 0xFF;
int type = BYTE_TABLE[i];
_codep = isUtf8SequenceComplete() ? (0xFF >> type) & i : (i & 0x3F) | (_codep << 6);
_state = TRANS_TABLE[_state + type];
_codep = _state == UTF8_ACCEPT ? (0xFF >> type) & i : (i & 0x3F) | (_codep << 6);
int next = TRANS_TABLE[_state + type];
if (isUtf8SequenceComplete())
switch(next)
{
if (_codep < Character.MIN_HIGH_SURROGATE)
{
_appendable.append((char)_codep);
}
else
{
for (char c : Character.toChars(_codep))
_appendable.append(c);
}
}
else if (_state == UTF8_REJECT)
{
_codep=0;
_state = UTF8_ACCEPT;
_appendable.append(REPLACEMENT);
throw new NotUtf8Exception();
case UTF8_ACCEPT:
_state=next;
if (_codep < Character.MIN_HIGH_SURROGATE)
{
_appendable.append((char)_codep);
}
else
{
for (char c : Character.toChars(_codep))
_appendable.append(c);
}
break;
case UTF8_REJECT:
String reason = "byte "+TypeUtil.toHexString(b)+" in state "+(_state/12);
_codep=0;
_state = UTF8_ACCEPT;
_appendable.append(REPLACEMENT);
throw new NotUtf8Exception(reason);
default:
_state=next;
}
}
}
protected boolean isUtf8SequenceComplete()
public boolean isUtf8SequenceComplete()
{
return _state == UTF8_ACCEPT;
}
public static class NotUtf8Exception extends IllegalArgumentException
{
public NotUtf8Exception()
public NotUtf8Exception(String reason)
{
super("Not valid UTF8!");
super("Not valid UTF8! "+reason);
}
}
}

View File

@ -142,11 +142,6 @@ public class Log
LOG.debug("Logging to {} via {}", LOG, log_class.getName());
}
}
catch(ThreadDeath e)
{
// Let ThreadDeath pass through
throw e;
}
catch(Throwable e)
{
// Unable to load specified Logger implementation, default to standard logging.
@ -163,7 +158,7 @@ public class Log
{
e.printStackTrace();
}
if (LOG == null)
{
log_class = StdErrLog.class;
@ -186,7 +181,7 @@ public class Log
initialized();
return LOG;
}
/**
* Get the root logger.
* @return the root logger
@ -397,10 +392,10 @@ public class Log
return;
LOG.warn(EXCEPTION, th);
}
/**
* Obtain a named Logger based on the fully qualified class name.
*
*
* @param clazz
* the class to base the Logger name off of
* @return the Logger with the given name

View File

@ -1,6 +1,6 @@
package org.eclipse.jetty.util.log;
import static org.hamcrest.Matchers.*;
import static org.hamcrest.Matchers.containsString;
import java.io.PrintWriter;
import java.io.StringWriter;

View File

@ -1,6 +1,6 @@
package org.eclipse.jetty.util.log;
import static org.hamcrest.Matchers.*;
import static org.hamcrest.Matchers.is;
import java.io.PrintWriter;
import java.io.StringWriter;

View File

@ -13,7 +13,7 @@
package org.eclipse.jetty.util.log;
import static org.hamcrest.Matchers.*;
import static org.hamcrest.Matchers.is;
import org.junit.AfterClass;
import org.junit.Assert;

View File

@ -1,6 +1,7 @@
package org.eclipse.jetty.util.log;
import static org.hamcrest.Matchers.*;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.not;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;

View File

@ -13,7 +13,8 @@
package org.eclipse.jetty.util.log;
import static org.hamcrest.Matchers.*;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.is;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;

View File

@ -6,7 +6,6 @@ import java.io.FileInputStream;
import java.io.IOException;
import java.security.KeyStore;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.eclipse.jetty.util.component.AbstractLifeCycle;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.StdErrLog;

View File

@ -30,7 +30,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.io.nio.SelectChannelEndPoint;
import org.eclipse.jetty.util.QuotedStringTokenizer;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.log.Log;
@ -44,7 +43,6 @@ public class WebSocketConnectionD00 extends AbstractConnection implements WebSoc
public final static byte LENGTH_FRAME=(byte)0x80;
public final static byte SENTINEL_FRAME=(byte)0x00;
final IdleCheck _idle;
final WebSocketParser _parser;
final WebSocketGenerator _generator;
final WebSocket _websocket;
@ -57,8 +55,6 @@ public class WebSocketConnectionD00 extends AbstractConnection implements WebSoc
throws IOException
{
super(endpoint,timestamp);
if (endpoint instanceof AsyncEndPoint)
((AsyncEndPoint)endpoint).cancelIdle();
_endp.setMaxIdleTime(maxIdleTime);
@ -67,28 +63,6 @@ public class WebSocketConnectionD00 extends AbstractConnection implements WebSoc
_generator = new WebSocketGeneratorD00(buffers, _endp);
_parser = new WebSocketParserD00(buffers, endpoint, new FrameHandlerD00(_websocket));
if (_endp instanceof SelectChannelEndPoint)
{
final SelectChannelEndPoint scep=(SelectChannelEndPoint)_endp;
scep.cancelIdle();
_idle=new IdleCheck()
{
public void access(EndPoint endp)
{
scep.scheduleIdle();
}
};
scep.scheduleIdle();
}
else
{
_idle = new IdleCheck()
{
public void access(EndPoint endp)
{}
};
}
}
/* ------------------------------------------------------------ */
@ -190,8 +164,6 @@ public class WebSocketConnectionD00 extends AbstractConnection implements WebSoc
{
if (_endp.isOpen())
{
_idle.access(_endp);
if (_endp.isInputShutdown() && _generator.isBufferEmpty())
_endp.close();
else
@ -253,7 +225,6 @@ public class WebSocketConnectionD00 extends AbstractConnection implements WebSoc
_generator.addFrame((byte)0,SENTINEL_FRAME,data,0,data.length);
_generator.flush();
checkWriteable();
_idle.access(_endp);
}
/* ------------------------------------------------------------ */
@ -262,7 +233,6 @@ public class WebSocketConnectionD00 extends AbstractConnection implements WebSoc
_generator.addFrame((byte)0,LENGTH_FRAME,data,offset,length);
_generator.flush();
checkWriteable();
_idle.access(_endp);
}
/* ------------------------------------------------------------ */
@ -285,7 +255,6 @@ public class WebSocketConnectionD00 extends AbstractConnection implements WebSoc
_generator.addFrame((byte)0,opcode,content,offset,length);
_generator.flush();
checkWriteable();
_idle.access(_endp);
}
/* ------------------------------------------------------------ */
@ -299,7 +268,7 @@ public class WebSocketConnectionD00 extends AbstractConnection implements WebSoc
{
close();
}
/* ------------------------------------------------------------ */
public void close()
{
@ -371,11 +340,6 @@ public class WebSocketConnectionD00 extends AbstractConnection implements WebSoc
}
}
private interface IdleCheck
{
void access(EndPoint endp);
}
public void handshake(HttpServletRequest request, HttpServletResponse response, String subprotocol) throws IOException
{
String uri=request.getRequestURI();
@ -490,10 +454,6 @@ public class WebSocketConnectionD00 extends AbstractConnection implements WebSoc
((WebSocket.OnBinaryMessage)_websocket).onMessage(array,buffer.getIndex(),buffer.length());
}
}
catch(ThreadDeath th)
{
throw th;
}
catch(Throwable th)
{
LOG.warn(th);

View File

@ -28,7 +28,6 @@ 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;
@ -76,7 +75,6 @@ public class WebSocketConnectionD06 extends AbstractConnection implements WebSoc
private final static byte[] MAGIC;
private final IdleCheck _idle;
private final WebSocketParser _parser;
private final WebSocketGenerator _generator;
private final WebSocket _webSocket;
@ -116,9 +114,6 @@ public class WebSocketConnectionD06 extends AbstractConnection implements WebSoc
{
super(endpoint,timestamp);
if (endpoint instanceof AsyncEndPoint)
((AsyncEndPoint)endpoint).cancelIdle();
_endp.setMaxIdleTime(maxIdleTime);
_webSocket = websocket;
@ -130,28 +125,6 @@ public class WebSocketConnectionD06 extends AbstractConnection implements WebSoc
_parser = new WebSocketParserD06(buffers, endpoint, _frameHandler,true);
_protocol=protocol;
if (_endp instanceof SelectChannelEndPoint)
{
final SelectChannelEndPoint scep=(SelectChannelEndPoint)_endp;
scep.cancelIdle();
_idle=new IdleCheck()
{
public void access(EndPoint endp)
{
scep.scheduleIdle();
}
};
scep.scheduleIdle();
}
else
{
_idle = new IdleCheck()
{
public void access(EndPoint endp)
{}
};
}
_maxTextMessageSize=buffers.getBufferSize();
_maxBinaryMessageSize=-1;
}
@ -200,7 +173,6 @@ public class WebSocketConnectionD06 extends AbstractConnection implements WebSoc
{
if (_endp.isOpen())
{
_idle.access(_endp);
if (_closedIn && _closedOut && _generator.isBufferEmpty())
_endp.close();
else if (_endp.isInputShutdown() && !_closedIn)
@ -334,7 +306,6 @@ public class WebSocketConnectionD06 extends AbstractConnection implements WebSoc
_generator.addFrame((byte)0x8,WebSocketConnectionD06.OP_TEXT,data,0,data.length);
_generator.flush();
checkWriteable();
_idle.access(_endp);
}
/* ------------------------------------------------------------ */
@ -345,7 +316,6 @@ public class WebSocketConnectionD06 extends AbstractConnection implements WebSoc
_generator.addFrame((byte)0x8,WebSocketConnectionD06.OP_BINARY,content,offset,length);
_generator.flush();
checkWriteable();
_idle.access(_endp);
}
/* ------------------------------------------------------------ */
@ -356,7 +326,6 @@ public class WebSocketConnectionD06 extends AbstractConnection implements WebSoc
_generator.addFrame(flags,opcode,content,offset,length);
_generator.flush();
checkWriteable();
_idle.access(_endp);
}
/* ------------------------------------------------------------ */
@ -367,7 +336,6 @@ public class WebSocketConnectionD06 extends AbstractConnection implements WebSoc
_generator.addFrame((byte)0x8,control,data,offset,length);
_generator.flush();
checkWriteable();
_idle.access(_endp);
}
/* ------------------------------------------------------------ */
@ -511,7 +479,7 @@ public class WebSocketConnectionD06 extends AbstractConnection implements WebSoc
{
close();
}
/* ------------------------------------------------------------ */
public void close()
{
@ -713,10 +681,6 @@ public class WebSocketConnectionD06 extends AbstractConnection implements WebSoc
}
}
}
catch(ThreadDeath th)
{
throw th;
}
catch(Throwable th)
{
LOG.warn(th);
@ -735,12 +699,6 @@ public class WebSocketConnectionD06 extends AbstractConnection implements WebSoc
}
}
/* ------------------------------------------------------------ */
private interface IdleCheck
{
void access(EndPoint endp);
}
/* ------------------------------------------------------------ */
public void handshake(HttpServletRequest request, HttpServletResponse response, String subprotocol) throws IOException
{

View File

@ -77,7 +77,6 @@ public class WebSocketConnectionD08 extends AbstractConnection implements WebSoc
}
private final static byte[] MAGIC;
private final IdleCheck _idle;
private final List<Extension> _extensions;
private final WebSocketParserD08 _parser;
private final WebSocketParser.FrameHandler _inbound;
@ -130,9 +129,6 @@ public class WebSocketConnectionD08 extends AbstractConnection implements WebSoc
_context=Thread.currentThread().getContextClassLoader();
if (endpoint instanceof AsyncEndPoint)
((AsyncEndPoint)endpoint).cancelIdle();
_draft=draft;
_endp.setMaxIdleTime(maxIdleTime);
@ -164,27 +160,6 @@ public class WebSocketConnectionD08 extends AbstractConnection implements WebSoc
_protocol=protocol;
if (_endp instanceof SelectChannelEndPoint)
{
final SelectChannelEndPoint scep=(SelectChannelEndPoint)_endp;
scep.cancelIdle();
_idle=new IdleCheck()
{
public void access(EndPoint endp)
{
scep.scheduleIdle();
}
};
scep.scheduleIdle();
}
else
{
_idle = new IdleCheck()
{
public void access(EndPoint endp)
{}
};
}
}
/* ------------------------------------------------------------ */
@ -246,7 +221,6 @@ public class WebSocketConnectionD08 extends AbstractConnection implements WebSoc
_generator.returnBuffer();
if (_endp.isOpen())
{
_idle.access(_endp);
if (_closedIn && _closedOut && _outbound.isBufferEmpty())
_endp.close();
else if (_endp.isInputShutdown() && !_closedIn)
@ -417,7 +391,6 @@ public class WebSocketConnectionD08 extends AbstractConnection implements WebSoc
byte[] data = content.getBytes(StringUtil.__UTF8);
_outbound.addFrame((byte)FLAG_FIN,WebSocketConnectionD08.OP_TEXT,data,0,data.length);
checkWriteable();
_idle.access(_endp);
}
/* ------------------------------------------------------------ */
@ -427,7 +400,6 @@ public class WebSocketConnectionD08 extends AbstractConnection implements WebSoc
throw new IOException("closedOut "+_closeCode+":"+_closeMessage);
_outbound.addFrame((byte)FLAG_FIN,WebSocketConnectionD08.OP_BINARY,content,offset,length);
checkWriteable();
_idle.access(_endp);
}
/* ------------------------------------------------------------ */
@ -437,7 +409,6 @@ public class WebSocketConnectionD08 extends AbstractConnection implements WebSoc
throw new IOException("closedOut "+_closeCode+":"+_closeMessage);
_outbound.addFrame(flags,opcode,content,offset,length);
checkWriteable();
_idle.access(_endp);
}
/* ------------------------------------------------------------ */
@ -447,7 +418,6 @@ public class WebSocketConnectionD08 extends AbstractConnection implements WebSoc
throw new IOException("closedOut "+_closeCode+":"+_closeMessage);
_outbound.addFrame((byte)FLAG_FIN,ctrl,data,offset,length);
checkWriteable();
_idle.access(_endp);
}
/* ------------------------------------------------------------ */
@ -585,13 +555,13 @@ public class WebSocketConnectionD08 extends AbstractConnection implements WebSoc
{
return opcode==OP_PONG;
}
/* ------------------------------------------------------------ */
public void disconnect()
{
close();
}
/* ------------------------------------------------------------ */
public void close()
{
@ -786,10 +756,6 @@ public class WebSocketConnectionD08 extends AbstractConnection implements WebSoc
}
}
}
catch(ThreadDeath th)
{
throw th;
}
catch(Throwable th)
{
LOG.warn(th);
@ -834,12 +800,6 @@ public class WebSocketConnectionD08 extends AbstractConnection implements WebSoc
}
}
/* ------------------------------------------------------------ */
private interface IdleCheck
{
void access(EndPoint endp);
}
/* ------------------------------------------------------------ */
public void handshake(HttpServletRequest request, HttpServletResponse response, String subprotocol) throws IOException
{

View File

@ -67,7 +67,7 @@ import org.eclipse.jetty.websocket.WebSocket.OnTextMessage;
public class WebSocketConnectionD13 extends AbstractConnection implements WebSocketConnection
{
private static final Logger LOG = Log.getLogger(WebSocketConnectionD13.class);
final static byte OP_CONTINUATION = 0x00;
final static byte OP_TEXT = 0x01;
final static byte OP_BINARY = 0x02;
@ -106,7 +106,6 @@ public class WebSocketConnectionD13 extends AbstractConnection implements WebSoc
}
private final static byte[] MAGIC;
private final IdleCheck _idle;
private final List<Extension> _extensions;
private final WebSocketParserD13 _parser;
private final WebSocketGeneratorD13 _generator;
@ -156,9 +155,6 @@ public class WebSocketConnectionD13 extends AbstractConnection implements WebSoc
_context=Thread.currentThread().getContextClassLoader();
if (endpoint instanceof AsyncEndPoint)
((AsyncEndPoint)endpoint).cancelIdle();
_draft=draft;
_endp.setMaxIdleTime(maxIdleTime);
@ -191,28 +187,6 @@ public class WebSocketConnectionD13 extends AbstractConnection implements WebSoc
_protocol=protocol;
// TODO should these be AsyncEndPoint checks/calls?
if (_endp instanceof SelectChannelEndPoint)
{
final SelectChannelEndPoint scep=(SelectChannelEndPoint)_endp;
scep.cancelIdle();
_idle=new IdleCheck()
{
public void access(EndPoint endp)
{
scep.scheduleIdle();
}
};
scep.scheduleIdle();
}
else
{
_idle = new IdleCheck()
{
public void access(EndPoint endp)
{}
};
}
}
/* ------------------------------------------------------------ */
@ -247,7 +221,9 @@ public class WebSocketConnectionD13 extends AbstractConnection implements WebSoc
int filled=_parser.parseNext();
progress = flushed>0 || filled>0;
_endp.flush();
if (_endp instanceof AsyncEndPoint && ((AsyncEndPoint)_endp).hasProgressed())
progress=true;
}
@ -272,7 +248,6 @@ public class WebSocketConnectionD13 extends AbstractConnection implements WebSoc
_generator.returnBuffer();
if (_endp.isOpen())
{
_idle.access(_endp);
if (_closedIn && _closedOut && _outbound.isBufferEmpty())
_endp.close();
else if (_endp.isInputShutdown() && !_closedIn)
@ -290,7 +265,7 @@ public class WebSocketConnectionD13 extends AbstractConnection implements WebSoc
if (!_closedIn)
_endp.close();
}
/* ------------------------------------------------------------ */
public boolean isIdle()
{
@ -388,12 +363,12 @@ public class WebSocketConnectionD13 extends AbstractConnection implements WebSoc
{
// Close code 1005/1006 are never to be sent as a status over
// a Close control frame. Code<-1 also means no node.
if (code<0 || (code == WebSocketConnectionD13.CLOSE_NO_CODE) || code==WebSocketConnectionD13.CLOSE_NO_CLOSE)
code=-1;
else if (code==0)
code=WebSocketConnectionD13.CLOSE_NORMAL;
byte[] bytes = ("xx"+(message==null?"":message)).getBytes(StringUtil.__ISO_8859_1);
bytes[0]=(byte)(code/0x100);
bytes[1]=(byte)(code%0x100);
@ -438,7 +413,6 @@ public class WebSocketConnectionD13 extends AbstractConnection implements WebSoc
byte[] data = content.getBytes(StringUtil.__UTF8);
_outbound.addFrame((byte)FLAG_FIN,WebSocketConnectionD13.OP_TEXT,data,0,data.length);
checkWriteable();
_idle.access(_endp);
}
/* ------------------------------------------------------------ */
@ -448,7 +422,6 @@ public class WebSocketConnectionD13 extends AbstractConnection implements WebSoc
throw new IOException("closedOut "+_closeCode+":"+_closeMessage);
_outbound.addFrame((byte)FLAG_FIN,WebSocketConnectionD13.OP_BINARY,content,offset,length);
checkWriteable();
_idle.access(_endp);
}
/* ------------------------------------------------------------ */
@ -458,18 +431,16 @@ public class WebSocketConnectionD13 extends AbstractConnection implements WebSoc
throw new IOException("closedOut "+_closeCode+":"+_closeMessage);
_outbound.addFrame(flags,opcode,content,offset,length);
checkWriteable();
_idle.access(_endp);
}
/* ------------------------------------------------------------ */
public void sendControl(byte ctrl, byte[] data, int offset, int length) throws IOException
{
// TODO: section 5.5 states that control frames MUST never be length > 125 bytes and MUST NOT be fragmented
// TODO: section 5.5 states that control frames MUST never be length > 125 bytes and MUST NOT be fragmented
if (_closedOut)
throw new IOException("closedOut "+_closeCode+":"+_closeMessage);
_outbound.addFrame((byte)FLAG_FIN,ctrl,data,offset,length);
checkWriteable();
_idle.access(_endp);
}
/* ------------------------------------------------------------ */
@ -613,7 +584,7 @@ public class WebSocketConnectionD13 extends AbstractConnection implements WebSoc
{
close(CLOSE_NORMAL,null);
}
/* ------------------------------------------------------------ */
public void close()
{
@ -653,7 +624,7 @@ public class WebSocketConnectionD13 extends AbstractConnection implements WebSoc
public void onFrame(final byte flags, final byte opcode, final Buffer buffer)
{
boolean lastFrame = isLastFrame(flags);
synchronized(WebSocketConnectionD13.this)
{
// Ignore incoming after a close
@ -682,7 +653,7 @@ public class WebSocketConnectionD13 extends AbstractConnection implements WebSoc
{
return;
}
// Deliver frame if websocket is a FrameWebSocket
if (_onFrame!=null)
{
@ -695,7 +666,7 @@ public class WebSocketConnectionD13 extends AbstractConnection implements WebSoc
if (_onControl.onControl(opcode,array,buffer.getIndex(),buffer.length()))
return;
}
switch(opcode)
{
case WebSocketConnectionD13.OP_CONTINUATION:
@ -705,7 +676,7 @@ public class WebSocketConnectionD13 extends AbstractConnection implements WebSoc
errorClose(WebSocketConnectionD13.CLOSE_PROTOCOL,"Bad Continuation");
return;
}
// If text, append to the message buffer
if (_onTextMessage!=null && _opcode==WebSocketConnectionD13.OP_TEXT)
{
@ -750,7 +721,7 @@ public class WebSocketConnectionD13 extends AbstractConnection implements WebSoc
case WebSocketConnectionD13.OP_PING:
{
LOG.debug("PING {}",this);
if (!_closedOut)
if (!_closedOut)
{
_connection.sendControl(WebSocketConnectionD13.OP_PONG,buffer.array(),buffer.getIndex(),buffer.length());
}
@ -770,10 +741,10 @@ public class WebSocketConnectionD13 extends AbstractConnection implements WebSoc
if (buffer.length()>=2)
{
code=(0xff&buffer.array()[buffer.getIndex()])*0x100+(0xff&buffer.array()[buffer.getIndex()+1]);
// Validate close status codes.
if (code < WebSocketConnectionD13.CLOSE_NORMAL ||
code == WebSocketConnectionD13.CLOSE_UNDEFINED ||
code == WebSocketConnectionD13.CLOSE_UNDEFINED ||
code == WebSocketConnectionD13.CLOSE_NO_CLOSE ||
code == WebSocketConnectionD13.CLOSE_NO_CODE ||
( code > 1010 && code <= 2999 ) ||
@ -782,8 +753,8 @@ public class WebSocketConnectionD13 extends AbstractConnection implements WebSoc
errorClose(WebSocketConnectionD13.CLOSE_PROTOCOL,"Invalid close code " + code);
return;
}
if (buffer.length()>2)
if (buffer.length()>2)
{
if(_utf8.append(buffer.array(),buffer.getIndex()+2,buffer.length()-2,_connection.getMaxTextMessageSize()))
{
@ -791,10 +762,10 @@ public class WebSocketConnectionD13 extends AbstractConnection implements WebSoc
_utf8.reset();
}
}
}
}
else if(buffer.length() == 1)
{
// Invalid length. use status code 1002 (Protocol error)
// Invalid length. use status code 1002 (Protocol error)
errorClose(WebSocketConnectionD13.CLOSE_PROTOCOL,"Invalid payload length of 1");
return;
}
@ -809,7 +780,7 @@ public class WebSocketConnectionD13 extends AbstractConnection implements WebSoc
errorClose(WebSocketConnectionD13.CLOSE_PROTOCOL,"Expected Continuation"+Integer.toHexString(opcode));
return;
}
if(_onTextMessage!=null)
{
if (_connection.getMaxTextMessageSize()<=0)
@ -842,7 +813,7 @@ public class WebSocketConnectionD13 extends AbstractConnection implements WebSoc
}
break;
}
case WebSocketConnectionD13.OP_BINARY:
{
if (_opcode!=-1)
@ -850,7 +821,7 @@ public class WebSocketConnectionD13 extends AbstractConnection implements WebSoc
errorClose(WebSocketConnectionD13.CLOSE_PROTOCOL,"Expected Continuation"+Integer.toHexString(opcode));
return;
}
if (_onBinaryMessage!=null && checkBinaryMessageSize(0,buffer.length()))
{
if (lastFrame)
@ -876,13 +847,9 @@ public class WebSocketConnectionD13 extends AbstractConnection implements WebSoc
default:
errorClose(WebSocketConnectionD13.CLOSE_PROTOCOL,"Bad opcode 0x"+Integer.toHexString(opcode));
return;
break;
}
}
catch(ThreadDeath th)
{
throw th;
}
catch(Utf8Appendable.NotUtf8Exception notUtf8)
{
LOG.warn("{} for {}",notUtf8,_endp);
@ -900,7 +867,7 @@ public class WebSocketConnectionD13 extends AbstractConnection implements WebSoc
private void errorClose(int code, String message)
{
_connection.close(code,message);
// Brutally drop the connection
try
{
@ -912,7 +879,7 @@ public class WebSocketConnectionD13 extends AbstractConnection implements WebSoc
LOG.debug(e);
}
}
private boolean checkBinaryMessageSize(int bufferLen, int length)
{
int max = _connection.getMaxBinaryMessageSize();
@ -950,13 +917,7 @@ public class WebSocketConnectionD13 extends AbstractConnection implements WebSoc
return WebSocketConnectionD13.this.toString()+"FH";
}
}
/* ------------------------------------------------------------ */
private interface IdleCheck
{
void access(EndPoint endp);
}
/* ------------------------------------------------------------ */
public void handshake(HttpServletRequest request, HttpServletResponse response, String subprotocol) throws IOException
{

View File

@ -28,6 +28,7 @@ import org.eclipse.jetty.http.HttpException;
import org.eclipse.jetty.http.HttpParser;
import org.eclipse.jetty.io.ConnectedEndPoint;
import org.eclipse.jetty.server.AbstractHttpConnection;
import org.eclipse.jetty.server.BlockingHttpConnection;
import org.eclipse.jetty.util.QuotedStringTokenizer;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
@ -195,6 +196,8 @@ public class WebSocketFactory
if (draft < 0)
draft = request.getIntHeader("Sec-WebSocket-Draft");
AbstractHttpConnection http = AbstractHttpConnection.getCurrentConnection();
if (http instanceof BlockingHttpConnection)
throw new IllegalStateException("Websockets not supported on blocking connectors");
ConnectedEndPoint endp = (ConnectedEndPoint)http.getEndPoint();
List<String> extensions_requested = new ArrayList<String>();

View File

@ -18,7 +18,6 @@ import java.io.IOException;
import org.eclipse.jetty.io.Buffer;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.io.EofException;
import org.eclipse.jetty.util.TypeUtil;
/* ------------------------------------------------------------ */

View File

@ -18,7 +18,6 @@ import java.io.IOException;
import org.eclipse.jetty.io.Buffer;
import org.eclipse.jetty.io.Buffers;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.util.TypeUtil;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;

View File

@ -1,6 +1,6 @@
package org.eclipse.jetty.websocket;
import static org.hamcrest.Matchers.*;
import static org.hamcrest.Matchers.greaterThan;
import java.io.BufferedReader;
import java.io.IOException;

View File

@ -1,6 +1,8 @@
package org.eclipse.jetty.websocket;
import static org.junit.Assert.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.io.EOFException;
import java.io.IOException;
@ -19,7 +21,6 @@ import javax.servlet.http.HttpServletRequest;
import org.eclipse.jetty.io.Buffer;
import org.eclipse.jetty.io.ByteArrayEndPoint;
import org.eclipse.jetty.io.nio.ChannelEndPoint;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.DefaultHandler;

View File

@ -4,11 +4,11 @@
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
package org.eclipse.jetty.xml;
@ -53,11 +53,11 @@ import org.xml.sax.SAXException;
/**
* Configure Objects from XML. This class reads an XML file conforming to the configure.dtd DTD and uses it to configure and object by calling set, put or other
* methods on the object.
*
*
* <p>
* The actual XML file format may be changed (eg to spring XML) by implementing the {@link ConfigurationProcessorFactory} interfaces to be found by the
* <code>ServiceLoader</code> by using the DTD and first tag element in the file. Note that DTD will be null if validation is off.
*
*
*/
public class XmlConfiguration
{
@ -69,7 +69,7 @@ public class XmlConfiguration
private static final Class<?>[] __primitiveHolders =
{ Boolean.class, Character.class, Byte.class, Short.class, Integer.class, Long.class, Float.class, Double.class, Void.class };
private static final Integer ZERO = new Integer(0);
private static final Iterable<?> __factoryLoader;
static
{
@ -77,7 +77,7 @@ public class XmlConfiguration
try
{
// Use reflection to look up 1.6 service loader
// loader=ServiceLoader.load(ConfigurationProcessorFactory.class);
// loader=ServiceLoader.load(ConfigurationProcessorFactory.class);
Class<?> slc = ClassLoader.getSystemClassLoader().loadClass("java.util.ServiceLoader");
Method load = slc.getMethod("load",Class.class);
loader=(Iterable<?>)load.invoke(null,ConfigurationProcessorFactory.class);
@ -90,7 +90,7 @@ public class XmlConfiguration
{
__factoryLoader=loader;
}
}
}
/* ------------------------------------------------------------ */
private static XmlParser __parser;
@ -135,7 +135,7 @@ public class XmlConfiguration
/* ------------------------------------------------------------ */
/**
* Constructor. Reads the XML configuration file.
*
*
* @param configuration
*/
public XmlConfiguration(URL configuration) throws SAXException, IOException
@ -152,7 +152,7 @@ public class XmlConfiguration
/* ------------------------------------------------------------ */
/**
* Constructor.
*
*
* @param configuration
* String of XML configuration commands excluding the normal XML preamble. The String should start with a " <Configure ...." element.
* @exception SAXException
@ -170,11 +170,11 @@ public class XmlConfiguration
_dtd=__parser.getDTD();
}
}
/* ------------------------------------------------------------ */
/**
* Constructor.
*
*
* @param configuration
* An input stream containing a complete e.g. configuration file
* @exception SAXException
@ -217,7 +217,7 @@ public class XmlConfiguration
if (_processor!=null)
break;
}
if (_processor==null)
throw new IllegalStateException("Unknown configuration type: "+config.getTag()+" in "+this);
}
@ -227,7 +227,7 @@ public class XmlConfiguration
}
_processor.init(_url,_config,_idMap, _propertyMap);
}
/* ------------------------------------------------------------ */
public Map<String, Object> getIdMap()
@ -263,13 +263,13 @@ public class XmlConfiguration
/* ------------------------------------------------------------ */
/**
* Configure an object.
* Configure an object.
*
* <p>Apply the XML configuration script to the passed object.</p>
*
*
* @param obj
* The object to be configured, which must be of a type or super type of the class attribute of the Configure element.
* @exception Exception
* @exception Exception
*/
public Object configure(Object obj) throws Exception
{
@ -279,7 +279,7 @@ public class XmlConfiguration
/* ------------------------------------------------------------ */
/**
* Configure an object. If the configuration has an ID, an object is looked up by ID and it's type check. Otherwise a new object is created.
*
*
* @return The newly created configured object.
* @exception Exception
*/
@ -335,7 +335,7 @@ public class XmlConfiguration
configure(obj,_config,0);
return obj;
}
/* ------------------------------------------------------------ */
private Class<?> nodeClass(XmlParser.Node node) throws ClassNotFoundException
{
@ -345,11 +345,11 @@ public class XmlConfiguration
return Loader.loadClass(XmlConfiguration.class,className,true);
}
/* ------------------------------------------------------------ */
/**
* Recursive configuration step. This method applies the remaining Set, Put and Call elements to the current object.
*
*
* @param obj
* @param cfg
* @param i
@ -403,7 +403,7 @@ public class XmlConfiguration
* Call a set method. This method makes a best effort to find a matching set method. The type of the value is used to find a suitable set method by 1.
* Trying for a trivial type match. 2. Looking for a native type match. 3. Trying all correctly named methods for an auto conversion. 4. Attempting to
* construct a suitable value from original value. @param obj
*
*
* @param node
*/
private void set(Object obj, XmlParser.Node node) throws Exception
@ -583,7 +583,7 @@ public class XmlConfiguration
/* ------------------------------------------------------------ */
/*
* Call a put method.
*
*
* @param obj @param node
*/
private void put(Object obj, XmlParser.Node node) throws Exception
@ -602,7 +602,7 @@ public class XmlConfiguration
/* ------------------------------------------------------------ */
/*
* Call a get method. Any object returned from the call is passed to the configure method to consume the remaining elements. @param obj @param node
*
*
* @return @exception Exception
*/
private Object get(Object obj, XmlParser.Node node) throws Exception
@ -648,7 +648,7 @@ public class XmlConfiguration
* Call a method. A method is selected by trying all methods with matching names and number of arguments. Any object returned from the call is passed to
* the configure method to consume the remaining elements. Note that if this is a static call we consider only methods declared directly in the given
* class. i.e. we ignore any static methods in superclasses. @param obj
*
*
* @param node @return @exception Exception
*/
private Object call(Object obj, XmlParser.Node node) throws Exception
@ -710,7 +710,7 @@ public class XmlConfiguration
/* ------------------------------------------------------------ */
/*
* Create a new value object.
*
*
* @param obj @param node @return @exception Exception
*/
private Object newObj(Object obj, XmlParser.Node node) throws Exception
@ -785,7 +785,7 @@ public class XmlConfiguration
/* ------------------------------------------------------------ */
/*
* Reference an id value object.
*
*
* @param obj @param node @return @exception NoSuchMethodException @exception ClassNotFoundException @exception InvocationTargetException
*/
private Object refObj(Object obj, XmlParser.Node node) throws Exception
@ -903,7 +903,7 @@ public class XmlConfiguration
/* ------------------------------------------------------------ */
/*
* Create a new value object.
*
*
* @param obj @param node @return @exception Exception
*/
private Object propertyObj(Object obj, XmlParser.Node node) throws Exception
@ -1113,7 +1113,7 @@ public class XmlConfiguration
* <p>
* Any IDs created in a configuration are passed to the next configuration file on the command line using {@link #getIdMap()} and {@link #setIdMap(Map)} .
* This allows objects with IDs created in one config file to be referenced in subsequent config files on the command line.
*
*
* @param args
* array of property and xml configuration filenames or {@link Resource}s.
*/
@ -1221,16 +1221,13 @@ public class XmlConfiguration
Throwable th = exception.get();
if (th != null)
{
if (th instanceof Exception)
if (th instanceof RuntimeException)
throw (RuntimeException)th;
else if (th instanceof Exception)
throw (Exception)th;
else if (th instanceof Error)
throw (Error)th;
else if (th instanceof RuntimeException)
throw (RuntimeException)th;
else if (th instanceof ThreadDeath)
throw (ThreadDeath)th;
throw new Error(th);
}
}
}

View File

@ -26,6 +26,7 @@ import org.eclipse.jetty.http.HttpVersions;
import org.eclipse.jetty.http.MimeTypes;
import org.eclipse.jetty.io.Buffer;
import org.eclipse.jetty.io.ByteArrayBuffer;
import org.eclipse.jetty.io.EofException;
import org.eclipse.jetty.io.SimpleBuffers;
import org.eclipse.jetty.io.View;
import org.eclipse.jetty.io.bio.StringEndPoint;
@ -130,15 +131,32 @@ public class HttpTester
* @return Any unparsed data in the rawHTTP (eg pipelined requests)
* @throws IOException
*/
public String parse(String rawHTTP) throws IOException
public String parse(String rawHTTP, boolean isHeadResponse) throws IOException
{
_charset = _defaultCharset;
ByteArrayBuffer buf = new ByteArrayBuffer(getByteArray(rawHTTP));
View view = new View(buf);
HttpParser parser = new HttpParser(view,new PH());
PH ph = new PH();
HttpParser parser = new HttpParser(view,ph);
parser.setHeadResponse(isHeadResponse);
parser.parse();
if (ph.isEarlyEOF())
throw new EofException();
return getString(view.asArray());
}
/* ------------------------------------------------------------ */
/**
* Parse one HTTP request or response
* @param rawHTTP Raw HTTP to parse
* @return Any unparsed data in the rawHTTP (eg pipelined requests)
* @throws IOException
*/
public String parse(String rawHTTP) throws IOException
{
return parse(rawHTTP, false);
}
/* ------------------------------------------------------------ */
/**
@ -147,16 +165,32 @@ public class HttpTester
* @return Any unparsed data in the rawHTTP (eg pipelined requests)
* @throws IOException
*/
public byte[] parse(byte[] rawHTTP) throws IOException
public byte[] parse(byte[] rawHTTP, boolean isHeadResponse) throws IOException
{
_charset = _defaultCharset;
ByteArrayBuffer buf = new ByteArrayBuffer(rawHTTP);
View view = new View(buf);
HttpParser parser = new HttpParser(view,new PH());
PH ph = new PH();
HttpParser parser = new HttpParser(view,ph);
parser.setHeadResponse(isHeadResponse);
parser.parse();
if (ph.isEarlyEOF())
throw new EofException();
return view.asArray();
}
/* ------------------------------------------------------------ */
/**
* Parse one HTTP request or response
* @param rawHTTP Raw HTTP to parse
* @return Any unparsed data in the rawHTTP (eg pipelined requests)
* @throws IOException
*/
public byte[] parse(byte[] rawHTTP) throws IOException
{
return parse(rawHTTP, false);
}
/* ------------------------------------------------------------ */
public String generate() throws IOException
{
@ -484,6 +518,8 @@ public class HttpTester
/* ------------------------------------------------------------ */
private class PH extends HttpParser.EventHandler
{
private volatile boolean _earlyEOF;
@Override
public void startRequest(Buffer method, Buffer url, Buffer version) throws IOException
{
@ -532,6 +568,18 @@ public class HttpTester
_parsedContent=new ByteArrayOutputStream2();
_parsedContent.write(ref.asArray());
}
@Override
public void earlyEOF()
{
_earlyEOF = true;
}
public boolean isEarlyEOF()
{
return _earlyEOF;
}
}
}

View File

@ -36,5 +36,21 @@ public class HttpTesterTest extends TestCase
assertEquals("utf-8",tester.getCharacterEncoding());
assertEquals("123456789\uA74A",tester.getContent());
}
public void testHead() throws Exception
{
String headResponse = "HTTP/1.1 200 OK\r\n"+
"Content-Type: text/html\r\n"+
"Content-Length: 22\r\n"+
"\r\n";
HttpTester tester = new HttpTester();
tester.parse(headResponse, true);
assertEquals(200, tester.getStatus());
assertEquals("22", tester.getHeader("Content-Length"));
assertEquals("text/html",tester.getContentType());
System.err.println(tester.getContent());
}
}

View File

@ -28,6 +28,8 @@ import java.util.Collection;
import java.util.Date;
import java.util.Enumeration;
import java.util.Locale;
import java.util.Timer;
import java.util.TimerTask;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
@ -64,6 +66,7 @@ public class Dump extends HttpServlet
private static final Logger LOG = Log.getLogger(Dump.class);
boolean fixed;
Timer _timer;
/* ------------------------------------------------------------ */
@Override
@ -77,6 +80,8 @@ public class Dump extends HttpServlet
fixed=true;
throw new UnavailableException("Unavailable test",Integer.parseInt(config.getInitParameter("unavailable")));
}
_timer=new Timer(true);
}
/* ------------------------------------------------------------ */
@ -180,40 +185,26 @@ public class Dump extends HttpServlet
request.setAttribute("RESUME",Boolean.TRUE);
final long resume=Long.parseLong(request.getParameter("resume"));
new Thread(new Runnable()
final Continuation continuation = ContinuationSupport.getContinuation(request);
_timer.schedule(new TimerTask()
{
@Override
public void run()
{
try
{
Thread.sleep(resume);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
Continuation continuation = ContinuationSupport.getContinuation(request);
continuation.resume();
}
}).start();
},resume);
}
if (request.getParameter("complete")!=null)
{
final long complete=Long.parseLong(request.getParameter("complete"));
new Thread(new Runnable()
_timer.schedule(new TimerTask()
{
@Override
public void run()
{
try
{
Thread.sleep(complete);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
try
{
response.setContentType("text/html");
@ -221,13 +212,12 @@ public class Dump extends HttpServlet
Continuation continuation = ContinuationSupport.getContinuation(request);
continuation.complete();
}
catch (IOException e)
catch(Exception e)
{
e.printStackTrace();
}
}
}).start();
},complete);
}
if (request.getParameter("suspend")!=null && request.getAttribute("SUSPEND")!=Boolean.TRUE)
@ -808,7 +798,7 @@ public class Dump extends HttpServlet
}
catch (Exception e)
{
getServletContext().log("dump", e);
getServletContext().log("dump "+e);
}
String lines= request.getParameter("lines");
@ -851,6 +841,7 @@ public class Dump extends HttpServlet
@Override
public synchronized void destroy()
{
_timer.cancel();
}
/* ------------------------------------------------------------ */