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:
commit
55d5020980
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -40,9 +40,9 @@ public class AsyncSslHttpExchangeTest extends SslHttpExchangeTest
|
|||
|
||||
|
||||
@Override
|
||||
public void testGetWithContentExchange() throws Exception
|
||||
public void testBigPostWithContentExchange() throws Exception
|
||||
{
|
||||
super.testGetWithContentExchange();
|
||||
super.testBigPostWithContentExchange();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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[] =
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
{}
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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" : "");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
/**
|
||||
|
|
|
@ -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>
|
||||
{
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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));
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------------- */
|
||||
/* ------------------------------------------------------------------------------- */
|
||||
/* ------------------------------------------------------------------------------- */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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('\\','_');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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());
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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>();
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
|
Loading…
Reference in New Issue