Merge remote-tracking branch 'origin/master' into jetty-8
This commit is contained in:
commit
127a5af8d7
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>example-async-rest</artifactId>
|
||||
<version>8.0.5-SNAPSHOT</version>
|
||||
<version>8.1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.eclipse.jetty.example-async-rest</groupId>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>example-async-rest</artifactId>
|
||||
<version>8.0.5-SNAPSHOT</version>
|
||||
<version>8.1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.eclipse.jetty.example-async-rest</groupId>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>8.0.5-SNAPSHOT</version>
|
||||
<version>8.1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>8.0.5-SNAPSHOT</version>
|
||||
<version>8.1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>example-jetty-embedded</artifactId>
|
||||
|
|
|
@ -15,11 +15,9 @@ package org.eclipse.jetty.embedded;
|
|||
|
||||
import java.lang.management.ManagementFactory;
|
||||
|
||||
import org.eclipse.jetty.ajp.Ajp13SocketConnector;
|
||||
import org.eclipse.jetty.deploy.DeploymentManager;
|
||||
import org.eclipse.jetty.deploy.providers.ContextProvider;
|
||||
import org.eclipse.jetty.deploy.providers.WebAppProvider;
|
||||
import org.eclipse.jetty.http.ssl.SslContextFactory;
|
||||
import org.eclipse.jetty.jmx.MBeanContainer;
|
||||
import org.eclipse.jetty.security.HashLoginService;
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
|
@ -33,8 +31,8 @@ import org.eclipse.jetty.server.handler.RequestLogHandler;
|
|||
import org.eclipse.jetty.server.handler.StatisticsHandler;
|
||||
import org.eclipse.jetty.server.nio.SelectChannelConnector;
|
||||
import org.eclipse.jetty.server.ssl.SslSelectChannelConnector;
|
||||
import org.eclipse.jetty.server.ssl.SslSocketConnector;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
import org.eclipse.jetty.util.thread.QueuedThreadPool;
|
||||
|
||||
public class LikeJettyXml
|
||||
|
@ -52,7 +50,7 @@ public class LikeJettyXml
|
|||
MBeanContainer mbContainer=new MBeanContainer(ManagementFactory.getPlatformMBeanServer());
|
||||
server.getContainer().addEventListener(mbContainer);
|
||||
server.addBean(mbContainer);
|
||||
mbContainer.addBean(Log.getLog());
|
||||
mbContainer.addBean(Log.getRootLogger());
|
||||
|
||||
|
||||
// Setup Threadpool
|
||||
|
@ -88,19 +86,19 @@ public class LikeJettyXml
|
|||
"SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA",
|
||||
"SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA"
|
||||
});
|
||||
cf.setProtocol("TLSv1.1");
|
||||
cf.addExcludeProtocols(new String[]{"TLSv1","SSLv3"});
|
||||
ssl_connector.setStatsOn(true);
|
||||
server.addConnector(ssl_connector);
|
||||
ssl_connector.open();
|
||||
|
||||
|
||||
|
||||
/*
|
||||
|
||||
Ajp13SocketConnector ajp = new Ajp13SocketConnector();
|
||||
ajp.setPort(8009);
|
||||
server.addConnector(ajp);
|
||||
|
||||
*/
|
||||
|
||||
HandlerCollection handlers = new HandlerCollection();
|
||||
ContextHandlerCollection contexts = new ContextHandlerCollection();
|
||||
RequestLogHandler requestLogHandler = new RequestLogHandler();
|
||||
|
@ -143,10 +141,9 @@ public class LikeJettyXml
|
|||
server.setStopAtShutdown(true);
|
||||
server.setSendServerVersion(true);
|
||||
|
||||
|
||||
|
||||
server.start();
|
||||
|
||||
server.join();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -13,11 +13,11 @@
|
|||
|
||||
package org.eclipse.jetty.embedded;
|
||||
|
||||
import org.eclipse.jetty.http.ssl.SslContextFactory;
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.nio.SelectChannelConnector;
|
||||
import org.eclipse.jetty.server.ssl.SslSelectChannelConnector;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
import org.eclipse.jetty.util.thread.QueuedThreadPool;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
|
|
@ -17,13 +17,13 @@ import java.util.Collections;
|
|||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jetty.http.security.Constraint;
|
||||
import org.eclipse.jetty.security.ConstraintMapping;
|
||||
import org.eclipse.jetty.security.ConstraintSecurityHandler;
|
||||
import org.eclipse.jetty.security.HashLoginService;
|
||||
import org.eclipse.jetty.security.LoginService;
|
||||
import org.eclipse.jetty.security.authentication.BasicAuthenticator;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.util.security.Constraint;
|
||||
|
||||
public class SecuredHelloHandler
|
||||
{
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.aggregate</groupId>
|
||||
<artifactId>jetty-aggregate-project</artifactId>
|
||||
<version>8.0.5-SNAPSHOT</version>
|
||||
<version>8.1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.eclipse.jetty.aggregate</groupId>
|
||||
|
|
|
@ -2,12 +2,11 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.aggregate</groupId>
|
||||
<artifactId>jetty-aggregate-project</artifactId>
|
||||
<version>8.0.5-SNAPSHOT</version>
|
||||
<version>8.1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-all</artifactId>
|
||||
<name>Jetty :: Aggregate :: All core Jetty</name>
|
||||
|
||||
<build>
|
||||
<sourceDirectory>${project.build.directory}/sources</sourceDirectory>
|
||||
<plugins>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.aggregate</groupId>
|
||||
<artifactId>jetty-aggregate-project</artifactId>
|
||||
<version>8.0.5-SNAPSHOT</version>
|
||||
<version>8.1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.eclipse.jetty.aggregate</groupId>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.aggregate</groupId>
|
||||
<artifactId>jetty-aggregate-project</artifactId>
|
||||
<version>8.0.5-SNAPSHOT</version>
|
||||
<version>8.1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-plus</artifactId>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.aggregate</groupId>
|
||||
<artifactId>jetty-aggregate-project</artifactId>
|
||||
<version>8.0.5-SNAPSHOT</version>
|
||||
<version>8.1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-server</artifactId>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.aggregate</groupId>
|
||||
<artifactId>jetty-aggregate-project</artifactId>
|
||||
<version>8.0.5-SNAPSHOT</version>
|
||||
<version>8.1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-servlet</artifactId>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.aggregate</groupId>
|
||||
<artifactId>jetty-aggregate-project</artifactId>
|
||||
<version>8.0.5-SNAPSHOT</version>
|
||||
<version>8.1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-webapp</artifactId>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>8.0.5-SNAPSHOT</version>
|
||||
<version>8.1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<groupId>org.eclipse.jetty.aggregate</groupId>
|
||||
<artifactId>jetty-aggregate-project</artifactId>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>8.0.5-SNAPSHOT</version>
|
||||
<version>8.1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-ajp</artifactId>
|
||||
|
|
|
@ -133,9 +133,9 @@ public class Ajp13Generator extends AbstractGenerator
|
|||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public void reset(boolean returnBuffers)
|
||||
public void reset()
|
||||
{
|
||||
super.reset(returnBuffers);
|
||||
super.reset();
|
||||
|
||||
_needEOC = false;
|
||||
_needMore = false;
|
||||
|
@ -487,7 +487,7 @@ public class Ajp13Generator extends AbstractGenerator
|
|||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public long flushBuffer() throws IOException
|
||||
public int flushBuffer() throws IOException
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -819,7 +819,7 @@ public class Ajp13Generator extends AbstractGenerator
|
|||
while (buff.length() > 0);
|
||||
_buffers.returnBuffer(buff);
|
||||
|
||||
reset(true);
|
||||
reset();
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -148,21 +148,16 @@ public class Ajp13Parser implements Parser
|
|||
}
|
||||
|
||||
/* ------------------------------------------------------------------------------- */
|
||||
public int parseAvailable() throws IOException
|
||||
public boolean parseAvailable() throws IOException
|
||||
{
|
||||
int len = parseNext();
|
||||
int total = len > 0 ? len : 0;
|
||||
|
||||
boolean progress=parseNext()>0;
|
||||
|
||||
// continue parsing
|
||||
while (!isComplete() && _buffer != null && _buffer.length() > 0)
|
||||
while (!isComplete() && _buffer!=null && _buffer.length()>0)
|
||||
{
|
||||
len = parseNext();
|
||||
if (len > 0)
|
||||
total += len;
|
||||
else
|
||||
break;
|
||||
progress |= parseNext()>0;
|
||||
}
|
||||
return total;
|
||||
return progress;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------------- */
|
||||
|
@ -876,6 +871,15 @@ public class Ajp13Parser implements Parser
|
|||
|
||||
return _content.length() > 0;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isPersistent()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public void setPersistent(boolean persistent)
|
||||
{
|
||||
LOG.warn("AJP13.setPersistent is not IMPLEMENTED!");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
|
||||
package org.eclipse.jetty.ajp;
|
||||
|
||||
import org.eclipse.jetty.server.HttpConnection;
|
||||
import org.eclipse.jetty.server.AbstractHttpConnection;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
|
||||
public class Ajp13Request extends Request
|
||||
|
@ -24,7 +24,7 @@ public class Ajp13Request extends Request
|
|||
protected boolean _sslSecure;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public Ajp13Request(HttpConnection connection)
|
||||
public Ajp13Request(AbstractHttpConnection connection)
|
||||
{
|
||||
super(connection);
|
||||
}
|
||||
|
|
|
@ -13,10 +13,10 @@
|
|||
|
||||
package org.eclipse.jetty.ajp;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketTimeoutException;
|
||||
|
@ -39,8 +39,6 @@ import org.junit.Before;
|
|||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class Ajp13ConnectionTest
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(Ajp13ConnectionTest.class);
|
||||
|
|
|
@ -13,6 +13,9 @@
|
|||
|
||||
package org.eclipse.jetty.ajp;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.eclipse.jetty.io.Buffer;
|
||||
|
@ -23,9 +26,6 @@ import org.eclipse.jetty.io.SimpleBuffers;
|
|||
import org.eclipse.jetty.util.TypeUtil;
|
||||
import org.junit.Test;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class TestAjpParser
|
||||
{
|
||||
@Test
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>8.0.5-SNAPSHOT</version>
|
||||
<version>8.1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-annotations</artifactId>
|
||||
|
|
|
@ -23,7 +23,6 @@ import javax.servlet.annotation.ServletSecurity.EmptyRoleSemantic;
|
|||
import javax.servlet.annotation.ServletSecurity.TransportGuarantee;
|
||||
|
||||
import org.eclipse.jetty.annotations.AnnotationIntrospector.AbstractIntrospectableAnnotationHandler;
|
||||
import org.eclipse.jetty.http.security.Constraint;
|
||||
import org.eclipse.jetty.security.ConstraintAware;
|
||||
import org.eclipse.jetty.security.ConstraintMapping;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
|
@ -31,6 +30,7 @@ import org.eclipse.jetty.servlet.ServletMapping;
|
|||
import org.eclipse.jetty.util.LazyList;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.util.security.Constraint;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
|
||||
/**
|
||||
|
|
|
@ -25,7 +25,6 @@ import javax.servlet.annotation.ServletSecurity.TransportGuarantee;
|
|||
import javax.servlet.annotation.ServletSecurity.EmptyRoleSemantic;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
|
||||
import org.eclipse.jetty.http.security.Constraint;
|
||||
import org.eclipse.jetty.security.ConstraintAware;
|
||||
import org.eclipse.jetty.security.ConstraintMapping;
|
||||
import org.eclipse.jetty.servlet.Holder;
|
||||
|
@ -33,6 +32,7 @@ import org.eclipse.jetty.security.ConstraintSecurityHandler;
|
|||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.eclipse.jetty.servlet.ServletMapping;
|
||||
import org.eclipse.jetty.util.LazyList;
|
||||
import org.eclipse.jetty.util.security.Constraint;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>8.0.5-SNAPSHOT</version>
|
||||
<version>8.1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// ========================================================================
|
||||
// Copyright (c) 2006-2009 Mort Bay Consulting Pty. Ltd.
|
||||
// Copyright (c) 2006-2011 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
|
||||
|
@ -13,10 +13,8 @@
|
|||
|
||||
package org.eclipse.jetty.client;
|
||||
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InterruptedIOException;
|
||||
import java.util.Collections;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
|
@ -39,7 +37,6 @@ import org.eclipse.jetty.io.Connection;
|
|||
import org.eclipse.jetty.io.EndPoint;
|
||||
import org.eclipse.jetty.io.EofException;
|
||||
import org.eclipse.jetty.io.View;
|
||||
import org.eclipse.jetty.io.nio.SslSelectChannelEndPoint;
|
||||
import org.eclipse.jetty.util.component.AggregateLifeCycle;
|
||||
import org.eclipse.jetty.util.component.Dumpable;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
|
@ -50,28 +47,26 @@ import org.eclipse.jetty.util.thread.Timeout;
|
|||
*
|
||||
* @version $Revision: 879 $ $Date: 2009-09-11 16:13:28 +0200 (Fri, 11 Sep 2009) $
|
||||
*/
|
||||
public class HttpConnection extends AbstractConnection implements Dumpable
|
||||
public abstract class AbstractHttpConnection extends AbstractConnection implements Dumpable
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(HttpConnection.class);
|
||||
private static final Logger LOG = Log.getLogger(AbstractHttpConnection.class);
|
||||
|
||||
private HttpDestination _destination;
|
||||
private HttpGenerator _generator;
|
||||
private HttpParser _parser;
|
||||
private boolean _http11 = true;
|
||||
private int _status;
|
||||
private Buffer _connectionHeader;
|
||||
private Buffer _requestContentChunk;
|
||||
private boolean _requestComplete;
|
||||
private boolean _reserved;
|
||||
protected HttpDestination _destination;
|
||||
protected HttpGenerator _generator;
|
||||
protected HttpParser _parser;
|
||||
protected boolean _http11 = true;
|
||||
protected int _status;
|
||||
protected Buffer _connectionHeader;
|
||||
protected boolean _reserved;
|
||||
|
||||
// The current exchange waiting for a response
|
||||
private volatile HttpExchange _exchange;
|
||||
private HttpExchange _pipeline;
|
||||
protected volatile HttpExchange _exchange;
|
||||
protected HttpExchange _pipeline;
|
||||
private final Timeout.Task _idleTimeout = new ConnectionIdleTask();
|
||||
private AtomicBoolean _idle = new AtomicBoolean(false);
|
||||
|
||||
|
||||
HttpConnection(Buffers requestBuffers, Buffers responseBuffers, EndPoint endp)
|
||||
AbstractHttpConnection(Buffers requestBuffers, Buffers responseBuffers, EndPoint endp)
|
||||
{
|
||||
super(endp);
|
||||
|
||||
|
@ -101,6 +96,7 @@ public class HttpConnection extends AbstractConnection implements Dumpable
|
|||
|
||||
public boolean send(HttpExchange ex) throws IOException
|
||||
{
|
||||
LOG.debug("Send {} on {}",ex,this);
|
||||
synchronized (this)
|
||||
{
|
||||
if (_exchange != null)
|
||||
|
@ -124,16 +120,6 @@ public class HttpConnection extends AbstractConnection implements Dumpable
|
|||
|
||||
_exchange.setStatus(HttpExchange.STATUS_WAITING_FOR_COMMIT);
|
||||
|
||||
if (_endp.isBlocking())
|
||||
{
|
||||
this.notify();
|
||||
}
|
||||
else
|
||||
{
|
||||
AsyncEndPoint scep = (AsyncEndPoint)_endp;
|
||||
scep.scheduleWrite();
|
||||
}
|
||||
|
||||
adjustIdleTimeout();
|
||||
|
||||
return true;
|
||||
|
@ -162,301 +148,8 @@ public class HttpConnection extends AbstractConnection implements Dumpable
|
|||
}
|
||||
}
|
||||
|
||||
public Connection handle() throws IOException
|
||||
{
|
||||
try
|
||||
{
|
||||
int no_progress = 0;
|
||||
|
||||
boolean failed = false;
|
||||
while (_endp.isBufferingInput() || _endp.isOpen())
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
while (_exchange == null)
|
||||
{
|
||||
if (_endp.isBlocking())
|
||||
{
|
||||
try
|
||||
{
|
||||
this.wait();
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
throw new InterruptedIOException();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
long filled = _parser.fill();
|
||||
if (filled < 0)
|
||||
{
|
||||
close();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Hopefully just space?
|
||||
_parser.skipCRLF();
|
||||
if (_parser.isMoreInBuffer())
|
||||
{
|
||||
LOG.warn("Unexpected data received but no request sent");
|
||||
close();
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (_exchange.getStatus() == HttpExchange.STATUS_WAITING_FOR_COMMIT)
|
||||
{
|
||||
no_progress = 0;
|
||||
commitRequest();
|
||||
}
|
||||
|
||||
long io = 0;
|
||||
_endp.flush();
|
||||
|
||||
if (_generator.isComplete())
|
||||
{
|
||||
if (!_requestComplete)
|
||||
{
|
||||
_requestComplete = true;
|
||||
_exchange.getEventListener().onRequestComplete();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Write as much of the request as possible
|
||||
synchronized (this)
|
||||
{
|
||||
if (_exchange == null)
|
||||
continue;
|
||||
}
|
||||
|
||||
long flushed = _generator.flushBuffer();
|
||||
io += flushed;
|
||||
|
||||
if (!_generator.isComplete())
|
||||
{
|
||||
if (_exchange!=null)
|
||||
{
|
||||
InputStream in = _exchange.getRequestContentSource();
|
||||
if (in != null)
|
||||
{
|
||||
if (_requestContentChunk == null || _requestContentChunk.length() == 0)
|
||||
{
|
||||
_requestContentChunk = _exchange.getRequestContentChunk();
|
||||
|
||||
if (_requestContentChunk != null)
|
||||
_generator.addContent(_requestContentChunk,false);
|
||||
else
|
||||
_generator.complete();
|
||||
|
||||
flushed = _generator.flushBuffer();
|
||||
io += flushed;
|
||||
}
|
||||
}
|
||||
else
|
||||
_generator.complete();
|
||||
}
|
||||
else
|
||||
_generator.complete();
|
||||
}
|
||||
}
|
||||
|
||||
if (_generator.isComplete() && !_requestComplete)
|
||||
{
|
||||
_requestComplete = true;
|
||||
_exchange.getEventListener().onRequestComplete();
|
||||
}
|
||||
|
||||
// If we are not ended then parse available
|
||||
if (!_parser.isComplete() && (_generator.isComplete() || _generator.isCommitted() && !_endp.isBlocking()))
|
||||
{
|
||||
long filled = _parser.parseAvailable();
|
||||
io += filled;
|
||||
|
||||
if (_parser.isIdle() && (_endp.isInputShutdown() || !_endp.isOpen()))
|
||||
throw new EofException();
|
||||
}
|
||||
|
||||
if (io > 0)
|
||||
no_progress = 0;
|
||||
else if (no_progress++ >= 1 && !_endp.isBlocking())
|
||||
{
|
||||
// SSL may need an extra flush as it may have made "no progress" while actually doing a handshake.
|
||||
if (_endp instanceof SslSelectChannelEndPoint && !_generator.isComplete() && !_generator.isEmpty())
|
||||
{
|
||||
long flushed = _generator.flushBuffer();
|
||||
if (flushed>0)
|
||||
continue;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
LOG.debug("Failure on " + _exchange, e);
|
||||
|
||||
if (e instanceof ThreadDeath)
|
||||
throw (ThreadDeath)e;
|
||||
|
||||
failed = true;
|
||||
|
||||
synchronized (this)
|
||||
{
|
||||
if (_exchange != null)
|
||||
{
|
||||
// Cancelling the exchange causes an exception as we close the connection,
|
||||
// but we don't report it as it is normal cancelling operation
|
||||
if (_exchange.getStatus() != HttpExchange.STATUS_CANCELLING &&
|
||||
_exchange.getStatus() != HttpExchange.STATUS_CANCELLED)
|
||||
{
|
||||
_exchange.setStatus(HttpExchange.STATUS_EXCEPTED);
|
||||
_exchange.getEventListener().onException(e);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (e instanceof IOException)
|
||||
throw (IOException)e;
|
||||
|
||||
if (e instanceof Error)
|
||||
throw (Error)e;
|
||||
|
||||
if (e instanceof RuntimeException)
|
||||
throw (RuntimeException)e;
|
||||
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
boolean complete = false;
|
||||
boolean close = failed; // always close the connection on error
|
||||
if (!failed)
|
||||
{
|
||||
// are we complete?
|
||||
if (_generator.isComplete())
|
||||
{
|
||||
if (!_requestComplete)
|
||||
{
|
||||
_requestComplete = true;
|
||||
_exchange.getEventListener().onRequestComplete();
|
||||
}
|
||||
|
||||
// we need to return the HttpConnection to a state that
|
||||
// it can be reused or closed out
|
||||
if (_parser.isComplete())
|
||||
{
|
||||
_exchange.cancelTimeout(_destination.getHttpClient());
|
||||
complete = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if the endpoint is closed, but the parser incomplete
|
||||
if ((!_endp.isOpen()||_endp.isInputShutdown()) && !(_parser.isComplete()||_parser.isIdle()))
|
||||
{
|
||||
// we wont be called again so let the parser see the close
|
||||
complete=true;
|
||||
_parser.parseAvailable();
|
||||
|
||||
// parsing again may have changed the parser state, so check again
|
||||
if (!(_parser.isComplete()||_parser.isIdle()))
|
||||
{
|
||||
LOG.warn("Incomplete {} {}",_parser,_endp);
|
||||
HttpExchange exchange = _exchange;
|
||||
if (exchange!=null && !exchange.isDone())
|
||||
{
|
||||
exchange.setStatus(HttpExchange.STATUS_EXCEPTED);
|
||||
exchange.getEventListener().onException(new EOFException("Incomplete"));
|
||||
}
|
||||
_endp.close();
|
||||
}
|
||||
}
|
||||
|
||||
if (complete || failed)
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
if (!close)
|
||||
close = shouldClose();
|
||||
|
||||
reset(true);
|
||||
|
||||
no_progress = 0;
|
||||
if (_exchange != null)
|
||||
{
|
||||
HttpExchange exchange=_exchange;
|
||||
_exchange = null;
|
||||
|
||||
// Reset the maxIdleTime because it may have been changed
|
||||
if (!close)
|
||||
_endp.setMaxIdleTime((int)_destination.getHttpClient().getIdleTimeout());
|
||||
|
||||
if (_status==HttpStatus.SWITCHING_PROTOCOLS_101)
|
||||
{
|
||||
Connection switched=exchange.onSwitchProtocol(_endp);
|
||||
if (switched!=null)
|
||||
{
|
||||
// switched protocol!
|
||||
exchange = _pipeline;
|
||||
_pipeline = null;
|
||||
if (exchange!=null)
|
||||
_destination.send(exchange);
|
||||
|
||||
return switched;
|
||||
}
|
||||
}
|
||||
|
||||
if (_pipeline == null)
|
||||
{
|
||||
if (!isReserved())
|
||||
_destination.returnConnection(this, close);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (close)
|
||||
{
|
||||
if (!isReserved())
|
||||
_destination.returnConnection(this,close);
|
||||
|
||||
exchange = _pipeline;
|
||||
_pipeline = null;
|
||||
_destination.send(exchange);
|
||||
}
|
||||
else
|
||||
{
|
||||
exchange = _pipeline;
|
||||
_pipeline = null;
|
||||
send(exchange);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
_parser.returnBuffers();
|
||||
|
||||
// Do we have more stuff to write?
|
||||
if (!_generator.isComplete() && _generator.getBytesBuffered()>0 && _endp.isOpen() && _endp instanceof AsyncEndPoint)
|
||||
{
|
||||
// Assume we are write blocked!
|
||||
((AsyncEndPoint)_endp).scheduleWrite();
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
public abstract Connection handle() throws IOException;
|
||||
|
||||
|
||||
public boolean isIdle()
|
||||
{
|
||||
|
@ -471,11 +164,11 @@ public class HttpConnection extends AbstractConnection implements Dumpable
|
|||
return false;
|
||||
}
|
||||
|
||||
public void closed()
|
||||
public void onClose()
|
||||
{
|
||||
}
|
||||
|
||||
private void commitRequest() throws IOException
|
||||
protected void commitRequest() throws IOException
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
|
@ -551,30 +244,14 @@ public class HttpConnection extends AbstractConnection implements Dumpable
|
|||
}
|
||||
}
|
||||
|
||||
protected void reset(boolean returnBuffers) throws IOException
|
||||
protected void reset() throws IOException
|
||||
{
|
||||
_requestComplete = false;
|
||||
_connectionHeader = null;
|
||||
_parser.reset();
|
||||
if (returnBuffers)
|
||||
_parser.returnBuffers();
|
||||
_generator.reset(returnBuffers);
|
||||
_generator.reset();
|
||||
_http11 = true;
|
||||
}
|
||||
|
||||
private boolean shouldClose()
|
||||
{
|
||||
if (_endp.isInputShutdown())
|
||||
return true;
|
||||
if (_connectionHeader!=null)
|
||||
{
|
||||
if (HttpHeaderValues.CLOSE_BUFFER.equals(_connectionHeader))
|
||||
return true;
|
||||
if (HttpHeaderValues.KEEP_ALIVE_BUFFER.equals(_connectionHeader))
|
||||
return false;
|
||||
}
|
||||
return !_http11;
|
||||
}
|
||||
|
||||
private class Handler extends HttpParser.EventHandler
|
||||
{
|
||||
|
@ -592,28 +269,33 @@ public class HttpConnection extends AbstractConnection implements Dumpable
|
|||
public void startResponse(Buffer version, int status, Buffer reason) throws IOException
|
||||
{
|
||||
HttpExchange exchange = _exchange;
|
||||
if (exchange!=null)
|
||||
if (exchange==null)
|
||||
{
|
||||
switch(status)
|
||||
{
|
||||
case HttpStatus.CONTINUE_100:
|
||||
case HttpStatus.PROCESSING_102:
|
||||
// TODO check if appropriate expect was sent in the request.
|
||||
exchange.setEventListener(new NonFinalResponseListener(exchange));
|
||||
break;
|
||||
|
||||
case HttpStatus.OK_200:
|
||||
// handle special case for CONNECT 200 responses
|
||||
if (HttpMethods.CONNECT.equalsIgnoreCase(exchange.getMethod()))
|
||||
_parser.setHeadResponse(true);
|
||||
break;
|
||||
}
|
||||
|
||||
_http11 = HttpVersions.HTTP_1_1_BUFFER.equals(version);
|
||||
_status=status;
|
||||
exchange.getEventListener().onResponseStatus(version,status,reason);
|
||||
exchange.setStatus(HttpExchange.STATUS_PARSING_HEADERS);
|
||||
LOG.warn("No exchange for response");
|
||||
_endp.close();
|
||||
return;
|
||||
}
|
||||
|
||||
switch(status)
|
||||
{
|
||||
case HttpStatus.CONTINUE_100:
|
||||
case HttpStatus.PROCESSING_102:
|
||||
// TODO check if appropriate expect was sent in the request.
|
||||
exchange.setEventListener(new NonFinalResponseListener(exchange));
|
||||
break;
|
||||
|
||||
case HttpStatus.OK_200:
|
||||
// handle special case for CONNECT 200 responses
|
||||
if (HttpMethods.CONNECT.equalsIgnoreCase(exchange.getMethod()))
|
||||
_parser.setHeadResponse(true);
|
||||
break;
|
||||
}
|
||||
|
||||
_http11 = HttpVersions.HTTP_1_1_BUFFER.equals(version);
|
||||
_status=status;
|
||||
exchange.getEventListener().onResponseStatus(version,status,reason);
|
||||
exchange.setStatus(HttpExchange.STATUS_PARSING_HEADERS);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -657,12 +339,30 @@ public class HttpConnection extends AbstractConnection implements Dumpable
|
|||
if (exchange!=null)
|
||||
exchange.setStatus(HttpExchange.STATUS_COMPLETED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void earlyEOF()
|
||||
{
|
||||
HttpExchange exchange = _exchange;
|
||||
if (exchange!=null)
|
||||
{
|
||||
if (!exchange.isDone())
|
||||
{
|
||||
if (exchange.setStatus(HttpExchange.STATUS_EXCEPTED))
|
||||
exchange.getEventListener().onException(new EofException("early EOF"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "HttpConnection@" + hashCode() + "//" + _destination.getAddress().getHost() + ":" + _destination.getAddress().getPort();
|
||||
return "HttpConnection@" + hashCode() + "//" +
|
||||
(_destination==null?"?.?.?.?:??":(_destination.getAddress().getHost() + ":" + _destination.getAddress().getPort()))+
|
||||
",g="+_generator.getState()+",p="+_parser.getState();
|
||||
}
|
||||
|
||||
public String toDetailString()
|
||||
|
@ -692,8 +392,8 @@ public class HttpConnection extends AbstractConnection implements Dumpable
|
|||
default:
|
||||
String exch= exchange.toString();
|
||||
String reason = _endp.isOpen()?(_endp.isInputShutdown()?"half closed: ":"local close: "):"closed: ";
|
||||
exchange.setStatus(HttpExchange.STATUS_EXCEPTED);
|
||||
exchange.getEventListener().onException(new EOFException(reason+exch));
|
||||
if (exchange.setStatus(HttpExchange.STATUS_EXCEPTED))
|
||||
exchange.getEventListener().onException(new EofException(reason+exch));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -777,7 +477,7 @@ public class HttpConnection extends AbstractConnection implements Dumpable
|
|||
// Connection idle, close it
|
||||
if (_idle.compareAndSet(true, false))
|
||||
{
|
||||
_destination.returnIdleConnection(HttpConnection.this);
|
||||
_destination.returnIdleConnection(AbstractHttpConnection.this);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,264 @@
|
|||
// ========================================================================
|
||||
// Copyright (c) 2006-2011 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.client;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.eclipse.jetty.http.AbstractGenerator;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.eclipse.jetty.io.AsyncEndPoint;
|
||||
import org.eclipse.jetty.io.Buffer;
|
||||
import org.eclipse.jetty.io.Buffers;
|
||||
import org.eclipse.jetty.io.Connection;
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
import org.eclipse.jetty.io.nio.AsyncConnection;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Asynchronous Client HTTP Connection
|
||||
*/
|
||||
public class AsyncHttpConnection extends AbstractHttpConnection implements AsyncConnection
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(AsyncHttpConnection.class);
|
||||
|
||||
private boolean _requestComplete;
|
||||
private Buffer _requestContentChunk;
|
||||
private final AsyncEndPoint _asyncEndp;
|
||||
|
||||
AsyncHttpConnection(Buffers requestBuffers, Buffers responseBuffers, EndPoint endp)
|
||||
{
|
||||
super(requestBuffers,responseBuffers,endp);
|
||||
_asyncEndp=(AsyncEndPoint)endp;
|
||||
}
|
||||
|
||||
protected void reset() throws IOException
|
||||
{
|
||||
_requestComplete = false;
|
||||
super.reset();
|
||||
}
|
||||
|
||||
public Connection handle() throws IOException
|
||||
{
|
||||
Connection connection = this;
|
||||
boolean progress=true;
|
||||
|
||||
try
|
||||
{
|
||||
boolean failed = false;
|
||||
|
||||
// While we are making progress and have not changed connection
|
||||
while (progress && connection==this)
|
||||
{
|
||||
LOG.debug("while open={} more={} progress={}",_endp.isOpen(),_parser.isMoreInBuffer(),progress);
|
||||
|
||||
progress=false;
|
||||
HttpExchange exchange=_exchange;
|
||||
|
||||
LOG.debug("exchange {} on {}",exchange,this);
|
||||
|
||||
try
|
||||
{
|
||||
// Should we commit the request?
|
||||
if (!_generator.isCommitted() && exchange!=null && exchange.getStatus() == HttpExchange.STATUS_WAITING_FOR_COMMIT)
|
||||
{
|
||||
LOG.debug("commit {}",exchange);
|
||||
progress=true;
|
||||
commitRequest();
|
||||
}
|
||||
|
||||
// Generate output
|
||||
if (_generator.isCommitted() && !_generator.isComplete())
|
||||
{
|
||||
if (_generator.flushBuffer()>0)
|
||||
{
|
||||
LOG.debug("flushed");
|
||||
progress=true;
|
||||
}
|
||||
|
||||
// Is there more content to send or should we complete the generator
|
||||
if (_generator.isState(AbstractGenerator.STATE_CONTENT))
|
||||
{
|
||||
// Look for more content to send.
|
||||
if (_requestContentChunk==null)
|
||||
_requestContentChunk = exchange.getRequestContentChunk(null);
|
||||
|
||||
if (_requestContentChunk==null)
|
||||
{
|
||||
LOG.debug("complete {}",exchange);
|
||||
progress=true;
|
||||
_generator.complete();
|
||||
}
|
||||
else if (_generator.isEmpty())
|
||||
{
|
||||
LOG.debug("addChunk");
|
||||
progress=true;
|
||||
Buffer chunk=_requestContentChunk;
|
||||
_requestContentChunk=exchange.getRequestContentChunk(null);
|
||||
_generator.addContent(chunk,_requestContentChunk==null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Signal request completion
|
||||
if (_generator.isComplete() && !_requestComplete)
|
||||
{
|
||||
LOG.debug("requestComplete {}",exchange);
|
||||
progress=true;
|
||||
_requestComplete = true;
|
||||
exchange.getEventListener().onRequestComplete();
|
||||
}
|
||||
|
||||
// Flush output
|
||||
_endp.flush();
|
||||
|
||||
// Read any input that is available
|
||||
if (!_parser.isComplete() && _parser.parseAvailable())
|
||||
{
|
||||
LOG.debug("parsed");
|
||||
progress=true;
|
||||
}
|
||||
|
||||
// Has any IO been done by the endpoint itself since last loop
|
||||
if (_asyncEndp.hasProgressed())
|
||||
{
|
||||
LOG.debug("hasProgressed {}",exchange);
|
||||
progress=true;
|
||||
}
|
||||
}
|
||||
catch (ThreadDeath e)
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
LOG.debug("Failure on " + _exchange, e);
|
||||
|
||||
failed = true;
|
||||
|
||||
synchronized (this)
|
||||
{
|
||||
if (exchange != null)
|
||||
{
|
||||
// Cancelling the exchange causes an exception as we close the connection,
|
||||
// but we don't report it as it is normal cancelling operation
|
||||
if (exchange.getStatus() != HttpExchange.STATUS_CANCELLING &&
|
||||
exchange.getStatus() != HttpExchange.STATUS_CANCELLED &&
|
||||
!exchange.isDone())
|
||||
{
|
||||
if (exchange.setStatus(HttpExchange.STATUS_EXCEPTED))
|
||||
exchange.getEventListener().onException(e);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (e instanceof IOException)
|
||||
throw (IOException)e;
|
||||
if (e instanceof Error)
|
||||
throw (Error)e;
|
||||
if (e instanceof RuntimeException)
|
||||
throw (RuntimeException)e;
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
LOG.debug("finally {} on {} progress={} {}",exchange,this,progress,_endp);
|
||||
|
||||
boolean complete = failed || _generator.isComplete() && _parser.isComplete();
|
||||
|
||||
if (complete)
|
||||
{
|
||||
boolean persistent = !failed && _parser.isPersistent() && _generator.isPersistent();
|
||||
_generator.setPersistent(persistent);
|
||||
reset();
|
||||
if (persistent)
|
||||
_endp.setMaxIdleTime((int)_destination.getHttpClient().getIdleTimeout());
|
||||
|
||||
synchronized (this)
|
||||
{
|
||||
exchange=_exchange;
|
||||
_exchange = null;
|
||||
|
||||
// Cancel the exchange
|
||||
if (exchange!=null)
|
||||
{
|
||||
exchange.cancelTimeout(_destination.getHttpClient());
|
||||
|
||||
// TODO should we check the exchange is done?
|
||||
}
|
||||
|
||||
// handle switched protocols
|
||||
if (_status==HttpStatus.SWITCHING_PROTOCOLS_101)
|
||||
{
|
||||
Connection switched=exchange.onSwitchProtocol(_endp);
|
||||
if (switched!=null)
|
||||
connection=switched;
|
||||
{
|
||||
// switched protocol!
|
||||
_pipeline = null;
|
||||
if (_pipeline!=null)
|
||||
_destination.send(_pipeline);
|
||||
_pipeline = null;
|
||||
|
||||
connection=switched;
|
||||
}
|
||||
}
|
||||
|
||||
// handle pipelined requests
|
||||
if (_pipeline!=null)
|
||||
{
|
||||
if (!persistent || connection!=this)
|
||||
_destination.send(_pipeline);
|
||||
else
|
||||
_exchange=_pipeline;
|
||||
_pipeline=null;
|
||||
}
|
||||
|
||||
if (_exchange==null && !isReserved()) // TODO how do we return switched connections?
|
||||
_destination.returnConnection(this, !persistent);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
_parser.returnBuffers();
|
||||
_generator.returnBuffers();
|
||||
LOG.debug("unhandle {} on {}",_exchange,_endp);
|
||||
}
|
||||
|
||||
return connection;
|
||||
}
|
||||
|
||||
public void onInputShutdown() throws IOException
|
||||
{
|
||||
if (_generator.isIdle())
|
||||
_endp.shutdownOutput();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean send(HttpExchange ex) throws IOException
|
||||
{
|
||||
boolean sent=super.send(ex);
|
||||
if (sent)
|
||||
_asyncEndp.asyncDispatch();
|
||||
return sent;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,273 @@
|
|||
// ========================================================================
|
||||
// Copyright (c) 2006-2011 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.client;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InterruptedIOException;
|
||||
|
||||
import org.eclipse.jetty.http.AbstractGenerator;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.eclipse.jetty.io.Buffer;
|
||||
import org.eclipse.jetty.io.Buffers;
|
||||
import org.eclipse.jetty.io.Connection;
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Blocking HTTP Connection
|
||||
*/
|
||||
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)
|
||||
{
|
||||
super(requestBuffers,responseBuffers,endp);
|
||||
}
|
||||
|
||||
protected void reset() throws IOException
|
||||
{
|
||||
_requestComplete = false;
|
||||
super.reset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Connection handle() throws IOException
|
||||
{
|
||||
Connection connection = this;
|
||||
|
||||
try
|
||||
{
|
||||
boolean failed = false;
|
||||
|
||||
|
||||
// While we are making progress and have not changed connection
|
||||
while (_endp.isOpen() && connection==this)
|
||||
{
|
||||
LOG.debug("open={} more={}",_endp.isOpen(),_parser.isMoreInBuffer());
|
||||
|
||||
HttpExchange exchange;
|
||||
synchronized (this)
|
||||
{
|
||||
exchange=_exchange;
|
||||
|
||||
while (exchange == null)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.wait();
|
||||
exchange=_exchange;
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
throw new InterruptedIOException();
|
||||
}
|
||||
}
|
||||
}
|
||||
LOG.debug("exchange {}",exchange);
|
||||
|
||||
try
|
||||
{
|
||||
// Should we commit the request?
|
||||
if (!_generator.isCommitted() && exchange!=null && exchange.getStatus() == HttpExchange.STATUS_WAITING_FOR_COMMIT)
|
||||
{
|
||||
LOG.debug("commit");
|
||||
commitRequest();
|
||||
}
|
||||
|
||||
// Generate output
|
||||
while (_generator.isCommitted() && !_generator.isComplete())
|
||||
{
|
||||
if (_generator.flushBuffer()>0)
|
||||
{
|
||||
LOG.debug("flushed");
|
||||
}
|
||||
|
||||
// Is there more content to send or should we complete the generator
|
||||
if (_generator.isState(AbstractGenerator.STATE_CONTENT))
|
||||
{
|
||||
// Look for more content to send.
|
||||
if (_requestContentChunk==null)
|
||||
_requestContentChunk = exchange.getRequestContentChunk(null);
|
||||
|
||||
if (_requestContentChunk==null)
|
||||
{
|
||||
LOG.debug("complete");
|
||||
_generator.complete();
|
||||
}
|
||||
else if (_generator.isEmpty())
|
||||
{
|
||||
LOG.debug("addChunk");
|
||||
Buffer chunk=_requestContentChunk;
|
||||
_requestContentChunk=exchange.getRequestContentChunk(null);
|
||||
_generator.addContent(chunk,_requestContentChunk==null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Signal request completion
|
||||
if (_generator.isComplete() && !_requestComplete)
|
||||
{
|
||||
LOG.debug("requestComplete");
|
||||
_requestComplete = true;
|
||||
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;
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
LOG.debug("Failure on " + _exchange, e);
|
||||
|
||||
failed = true;
|
||||
|
||||
synchronized (this)
|
||||
{
|
||||
if (exchange != null)
|
||||
{
|
||||
// Cancelling the exchange causes an exception as we close the connection,
|
||||
// but we don't report it as it is normal cancelling operation
|
||||
if (exchange.getStatus() != HttpExchange.STATUS_CANCELLING &&
|
||||
exchange.getStatus() != HttpExchange.STATUS_CANCELLED &&
|
||||
!exchange.isDone())
|
||||
{
|
||||
if(exchange.setStatus(HttpExchange.STATUS_EXCEPTED))
|
||||
exchange.getEventListener().onException(e);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (e instanceof IOException)
|
||||
throw (IOException)e;
|
||||
if (e instanceof Error)
|
||||
throw (Error)e;
|
||||
if (e instanceof RuntimeException)
|
||||
throw (RuntimeException)e;
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
LOG.debug("{} {}",_generator, _parser);
|
||||
LOG.debug("{}",_endp);
|
||||
|
||||
boolean complete = failed || _generator.isComplete() && _parser.isComplete();
|
||||
|
||||
if (complete)
|
||||
{
|
||||
boolean persistent = !failed && _parser.isPersistent() && _generator.isPersistent();
|
||||
_generator.setPersistent(persistent);
|
||||
reset();
|
||||
if (persistent)
|
||||
_endp.setMaxIdleTime((int)_destination.getHttpClient().getIdleTimeout());
|
||||
|
||||
synchronized (this)
|
||||
{
|
||||
exchange=_exchange;
|
||||
_exchange = null;
|
||||
|
||||
// Cancel the exchange
|
||||
if (exchange!=null)
|
||||
{
|
||||
exchange.cancelTimeout(_destination.getHttpClient());
|
||||
|
||||
// TODO should we check the exchange is done?
|
||||
}
|
||||
|
||||
// handle switched protocols
|
||||
if (_status==HttpStatus.SWITCHING_PROTOCOLS_101)
|
||||
{
|
||||
Connection switched=exchange.onSwitchProtocol(_endp);
|
||||
if (switched!=null)
|
||||
connection=switched;
|
||||
{
|
||||
// switched protocol!
|
||||
_pipeline = null;
|
||||
if (_pipeline!=null)
|
||||
_destination.send(_pipeline);
|
||||
_pipeline = null;
|
||||
|
||||
connection=switched;
|
||||
}
|
||||
}
|
||||
|
||||
// handle pipelined requests
|
||||
if (_pipeline!=null)
|
||||
{
|
||||
if (!persistent || connection!=this)
|
||||
_destination.send(_pipeline);
|
||||
else
|
||||
_exchange=_pipeline;
|
||||
_pipeline=null;
|
||||
}
|
||||
|
||||
if (_exchange==null && !isReserved()) // TODO how do we return switched connections?
|
||||
_destination.returnConnection(this, !persistent);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
_parser.returnBuffers();
|
||||
_generator.returnBuffers();
|
||||
}
|
||||
|
||||
return connection;
|
||||
}
|
||||
|
||||
|
||||
public void onInputShutdown() throws IOException
|
||||
{
|
||||
if (_generator.isIdle())
|
||||
_endp.shutdownOutput();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean send(HttpExchange ex) throws IOException
|
||||
{
|
||||
boolean sent=super.send(ex);
|
||||
if (sent)
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
notifyAll();
|
||||
}
|
||||
}
|
||||
return sent;
|
||||
}
|
||||
}
|
|
@ -29,13 +29,13 @@ import org.eclipse.jetty.client.security.RealmResolver;
|
|||
import org.eclipse.jetty.client.security.SecurityListener;
|
||||
import org.eclipse.jetty.http.HttpBuffers;
|
||||
import org.eclipse.jetty.http.HttpSchemes;
|
||||
import org.eclipse.jetty.http.ssl.SslContextFactory;
|
||||
import org.eclipse.jetty.io.Buffers.Type;
|
||||
import org.eclipse.jetty.util.Attributes;
|
||||
import org.eclipse.jetty.util.AttributesMap;
|
||||
import org.eclipse.jetty.util.component.AggregateLifeCycle;
|
||||
import org.eclipse.jetty.util.component.Dumpable;
|
||||
import org.eclipse.jetty.util.component.LifeCycle;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
import org.eclipse.jetty.util.thread.QueuedThreadPool;
|
||||
import org.eclipse.jetty.util.thread.ThreadPool;
|
||||
import org.eclipse.jetty.util.thread.Timeout;
|
||||
|
@ -52,11 +52,11 @@ import org.eclipse.jetty.util.thread.Timeout;
|
|||
* The an instance of {@link HttpExchange} is passed to the {@link #send(HttpExchange)} method
|
||||
* to send a request. The exchange contains both the headers and content (source) of the request
|
||||
* plus the callbacks to handle responses. A HttpClient can have many exchanges outstanding
|
||||
* and they may be queued on the {@link HttpDestination} waiting for a {@link HttpConnection},
|
||||
* queued in the {@link HttpConnection} waiting to be transmitted or pipelined on the actual
|
||||
* and they may be queued on the {@link HttpDestination} waiting for a {@link AbstractHttpConnection},
|
||||
* queued in the {@link AbstractHttpConnection} waiting to be transmitted or pipelined on the actual
|
||||
* TCP/IP connection waiting for a response.
|
||||
* <p/>
|
||||
* The {@link HttpDestination} class is an aggregation of {@link HttpConnection}s for the
|
||||
* The {@link HttpDestination} class is an aggregation of {@link AbstractHttpConnection}s for the
|
||||
* same host, port and protocol. A destination may limit the number of connections
|
||||
* open and they provide a pool of open connections that may be reused. Connections may also
|
||||
* be allocated from a destination, so that multiple request sources are not multiplexed
|
||||
|
@ -526,7 +526,7 @@ public class HttpClient extends HttpBuffers implements Attributes, Dumpable
|
|||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @return the period in milliseconds a {@link HttpConnection} can be idle for before it is closed.
|
||||
* @return the period in milliseconds a {@link AbstractHttpConnection} can be idle for before it is closed.
|
||||
*/
|
||||
public long getIdleTimeout()
|
||||
{
|
||||
|
@ -535,7 +535,7 @@ public class HttpClient extends HttpBuffers implements Attributes, Dumpable
|
|||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param ms the period in milliseconds a {@link HttpConnection} can be idle for before it is closed.
|
||||
* @param ms the period in milliseconds a {@link AbstractHttpConnection} can be idle for before it is closed.
|
||||
*/
|
||||
public void setIdleTimeout(long ms)
|
||||
{
|
||||
|
|
|
@ -48,9 +48,9 @@ public class HttpDestination implements Dumpable
|
|||
private static final Logger LOG = Log.getLogger(HttpDestination.class);
|
||||
|
||||
private final List<HttpExchange> _queue = new LinkedList<HttpExchange>();
|
||||
private final List<HttpConnection> _connections = new LinkedList<HttpConnection>();
|
||||
private final List<AbstractHttpConnection> _connections = new LinkedList<AbstractHttpConnection>();
|
||||
private final BlockingQueue<Object> _newQueue = new ArrayBlockingQueue<Object>(10, true);
|
||||
private final List<HttpConnection> _idle = new ArrayList<HttpConnection>();
|
||||
private final List<AbstractHttpConnection> _idle = new ArrayList<AbstractHttpConnection>();
|
||||
private final HttpClient _client;
|
||||
private final Address _address;
|
||||
private final boolean _ssl;
|
||||
|
@ -168,9 +168,9 @@ public class HttpDestination implements Dumpable
|
|||
* @return a HttpConnection for this destination
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
private HttpConnection getConnection(long timeout) throws IOException
|
||||
private AbstractHttpConnection getConnection(long timeout) throws IOException
|
||||
{
|
||||
HttpConnection connection = null;
|
||||
AbstractHttpConnection connection = null;
|
||||
|
||||
while ((connection == null) && (connection = getIdleConnection()) == null && timeout > 0)
|
||||
{
|
||||
|
@ -191,9 +191,9 @@ public class HttpDestination implements Dumpable
|
|||
try
|
||||
{
|
||||
Object o = _newQueue.take();
|
||||
if (o instanceof HttpConnection)
|
||||
if (o instanceof AbstractHttpConnection)
|
||||
{
|
||||
connection = (HttpConnection)o;
|
||||
connection = (AbstractHttpConnection)o;
|
||||
}
|
||||
else
|
||||
throw (IOException)o;
|
||||
|
@ -220,17 +220,17 @@ public class HttpDestination implements Dumpable
|
|||
return connection;
|
||||
}
|
||||
|
||||
public HttpConnection reserveConnection(long timeout) throws IOException
|
||||
public AbstractHttpConnection reserveConnection(long timeout) throws IOException
|
||||
{
|
||||
HttpConnection connection = getConnection(timeout);
|
||||
AbstractHttpConnection connection = getConnection(timeout);
|
||||
if (connection != null)
|
||||
connection.setReserved(true);
|
||||
return connection;
|
||||
}
|
||||
|
||||
public HttpConnection getIdleConnection() throws IOException
|
||||
public AbstractHttpConnection getIdleConnection() throws IOException
|
||||
{
|
||||
HttpConnection connection = null;
|
||||
AbstractHttpConnection connection = null;
|
||||
while (true)
|
||||
{
|
||||
synchronized (this)
|
||||
|
@ -246,12 +246,16 @@ public class HttpDestination implements Dumpable
|
|||
}
|
||||
|
||||
if (connection == null)
|
||||
{
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
// Check if the connection was idle,
|
||||
// but it expired just a moment ago
|
||||
if (connection.cancelIdleTimeout())
|
||||
{
|
||||
return connection;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -290,8 +294,8 @@ public class HttpDestination implements Dumpable
|
|||
else if (_queue.size() > 0)
|
||||
{
|
||||
HttpExchange ex = _queue.remove(0);
|
||||
ex.setStatus(HttpExchange.STATUS_EXCEPTED);
|
||||
ex.getEventListener().onConnectionFailed(throwable);
|
||||
if (ex.setStatus(HttpExchange.STATUS_EXCEPTED))
|
||||
ex.getEventListener().onConnectionFailed(throwable);
|
||||
|
||||
// Since an existing connection had failed, we need to create a
|
||||
// connection if the queue is not empty and client is running.
|
||||
|
@ -324,13 +328,13 @@ public class HttpDestination implements Dumpable
|
|||
if (_queue.size() > 0)
|
||||
{
|
||||
HttpExchange ex = _queue.remove(0);
|
||||
ex.setStatus(HttpExchange.STATUS_EXCEPTED);
|
||||
ex.getEventListener().onException(throwable);
|
||||
if(ex.setStatus(HttpExchange.STATUS_EXCEPTED))
|
||||
ex.getEventListener().onException(throwable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void onNewConnection(final HttpConnection connection) throws IOException
|
||||
public void onNewConnection(final AbstractHttpConnection connection) throws IOException
|
||||
{
|
||||
Connection q_connection = null;
|
||||
|
||||
|
@ -352,9 +356,9 @@ public class HttpDestination implements Dumpable
|
|||
else
|
||||
{
|
||||
EndPoint endPoint = connection.getEndPoint();
|
||||
if (isProxied() && endPoint instanceof SelectConnector.ProxySelectChannelEndPoint)
|
||||
if (isProxied() && endPoint instanceof SelectConnector.UpgradableEndPoint)
|
||||
{
|
||||
SelectConnector.ProxySelectChannelEndPoint proxyEndPoint = (SelectConnector.ProxySelectChannelEndPoint)endPoint;
|
||||
SelectConnector.UpgradableEndPoint proxyEndPoint = (SelectConnector.UpgradableEndPoint)endPoint;
|
||||
HttpExchange exchange = _queue.get(0);
|
||||
ConnectExchange connect = new ConnectExchange(getAddress(), proxyEndPoint, exchange);
|
||||
connect.setAddress(getProxy());
|
||||
|
@ -381,7 +385,7 @@ public class HttpDestination implements Dumpable
|
|||
}
|
||||
}
|
||||
|
||||
public void returnConnection(HttpConnection connection, boolean close) throws IOException
|
||||
public void returnConnection(AbstractHttpConnection connection, boolean close) throws IOException
|
||||
{
|
||||
if (connection.isReserved())
|
||||
connection.setReserved(false);
|
||||
|
@ -433,7 +437,7 @@ public class HttpDestination implements Dumpable
|
|||
}
|
||||
}
|
||||
|
||||
public void returnIdleConnection(HttpConnection connection)
|
||||
public void returnIdleConnection(AbstractHttpConnection connection)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -533,7 +537,7 @@ public class HttpDestination implements Dumpable
|
|||
// so that we count also the queue time in the timeout
|
||||
ex.scheduleTimeout(this);
|
||||
|
||||
HttpConnection connection = getIdleConnection();
|
||||
AbstractHttpConnection connection = getIdleConnection();
|
||||
if (connection != null)
|
||||
{
|
||||
send(connection, ex);
|
||||
|
@ -566,7 +570,7 @@ public class HttpDestination implements Dumpable
|
|||
}
|
||||
}
|
||||
|
||||
protected void send(HttpConnection connection, HttpExchange exchange) throws IOException
|
||||
protected void send(AbstractHttpConnection connection, HttpExchange exchange) throws IOException
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
|
@ -594,7 +598,7 @@ public class HttpDestination implements Dumpable
|
|||
b.append('\n');
|
||||
synchronized (this)
|
||||
{
|
||||
for (HttpConnection connection : _connections)
|
||||
for (AbstractHttpConnection connection : _connections)
|
||||
{
|
||||
b.append(connection.toDetailString());
|
||||
if (_idle.contains(connection))
|
||||
|
@ -637,7 +641,7 @@ public class HttpDestination implements Dumpable
|
|||
{
|
||||
synchronized (this)
|
||||
{
|
||||
for (HttpConnection connection : _connections)
|
||||
for (AbstractHttpConnection connection : _connections)
|
||||
{
|
||||
connection.close();
|
||||
}
|
||||
|
@ -668,10 +672,10 @@ public class HttpDestination implements Dumpable
|
|||
|
||||
private class ConnectExchange extends ContentExchange
|
||||
{
|
||||
private final SelectConnector.ProxySelectChannelEndPoint proxyEndPoint;
|
||||
private final SelectConnector.UpgradableEndPoint proxyEndPoint;
|
||||
private final HttpExchange exchange;
|
||||
|
||||
public ConnectExchange(Address serverAddress, SelectConnector.ProxySelectChannelEndPoint proxyEndPoint, HttpExchange exchange)
|
||||
public ConnectExchange(Address serverAddress, SelectConnector.UpgradableEndPoint proxyEndPoint, HttpExchange exchange)
|
||||
{
|
||||
this.proxyEndPoint = proxyEndPoint;
|
||||
this.exchange = exchange;
|
||||
|
@ -712,16 +716,16 @@ public class HttpDestination implements Dumpable
|
|||
protected void onException(Throwable x)
|
||||
{
|
||||
_queue.remove(exchange);
|
||||
exchange.setStatus(STATUS_EXCEPTED);
|
||||
exchange.getEventListener().onException(x);
|
||||
if (exchange.setStatus(STATUS_EXCEPTED))
|
||||
exchange.getEventListener().onException(x);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onExpire()
|
||||
{
|
||||
_queue.remove(exchange);
|
||||
exchange.setStatus(STATUS_EXPIRED);
|
||||
exchange.getEventListener().onExpire();
|
||||
if (exchange.setStatus(STATUS_EXPIRED))
|
||||
exchange.getEventListener().onExpire();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -59,7 +59,7 @@ import org.eclipse.jetty.util.thread.Timeout;
|
|||
*
|
||||
* <p>
|
||||
* Typically the HttpExchange is passed to the {@link HttpClient#send(HttpExchange)} method, which in turn selects a {@link HttpDestination} and calls its
|
||||
* {@link HttpDestination#send(HttpExchange)}, which then creates or selects a {@link HttpConnection} and calls its {@link HttpConnection#send(HttpExchange)}. A
|
||||
* {@link HttpDestination#send(HttpExchange)}, which then creates or selects a {@link AbstractHttpConnection} and calls its {@link AbstractHttpConnection#send(HttpExchange)}. A
|
||||
* developer may wish to directly call send on the destination or connection if they wish to bypass some handling provided (eg Cookie handling in the
|
||||
* HttpDestination).
|
||||
* </p>
|
||||
|
@ -98,12 +98,11 @@ public class HttpExchange
|
|||
private InputStream _requestContentSource;
|
||||
|
||||
private AtomicInteger _status = new AtomicInteger(STATUS_START);
|
||||
private Buffer _requestContentChunk;
|
||||
private boolean _retryStatus = false;
|
||||
// controls if the exchange will have listeners autoconfigured by the destination
|
||||
private boolean _configureListeners = true;
|
||||
private HttpEventListener _listener = new Listener();
|
||||
private volatile HttpConnection _connection;
|
||||
private volatile AbstractHttpConnection _connection;
|
||||
|
||||
private Address _localAddress = null;
|
||||
|
||||
|
@ -123,9 +122,8 @@ public class HttpExchange
|
|||
{
|
||||
if (getStatus() < HttpExchange.STATUS_COMPLETED)
|
||||
setStatus(HttpExchange.STATUS_EXPIRED);
|
||||
|
||||
destination.exchangeExpired(this);
|
||||
HttpConnection connection = _connection;
|
||||
AbstractHttpConnection connection = _connection;
|
||||
if (connection != null)
|
||||
connection.exchangeExpired(this);
|
||||
}
|
||||
|
@ -183,12 +181,18 @@ public class HttpExchange
|
|||
}
|
||||
}
|
||||
|
||||
void setStatus(int newStatus)
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param newStatus
|
||||
* @return True if the status was actually set.
|
||||
*/
|
||||
boolean setStatus(int newStatus)
|
||||
{
|
||||
boolean set = false;
|
||||
try
|
||||
{
|
||||
int oldStatus = _status.get();
|
||||
boolean set = false;
|
||||
boolean ignored = false;
|
||||
if (oldStatus != newStatus)
|
||||
{
|
||||
long now = System.currentTimeMillis();
|
||||
|
@ -198,7 +202,7 @@ public class HttpExchange
|
|||
if (newStatus==STATUS_SENDING_REQUEST)
|
||||
_sent=_lastStateChange;
|
||||
}
|
||||
|
||||
|
||||
// State machine: from which old status you can go into which new status
|
||||
switch (oldStatus)
|
||||
{
|
||||
|
@ -315,7 +319,7 @@ public class HttpExchange
|
|||
case STATUS_CANCELLING:
|
||||
case STATUS_EXPIRED:
|
||||
// Don't change the status, it's too late
|
||||
set = true;
|
||||
ignored = true;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
@ -329,7 +333,7 @@ public class HttpExchange
|
|||
break;
|
||||
default:
|
||||
// Ignore other statuses, we're cancelling
|
||||
set = true;
|
||||
ignored = true;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
@ -341,8 +345,14 @@ public class HttpExchange
|
|||
case STATUS_START:
|
||||
set = _status.compareAndSet(oldStatus,newStatus);
|
||||
break;
|
||||
|
||||
case STATUS_COMPLETED:
|
||||
ignored = true;
|
||||
done();
|
||||
break;
|
||||
|
||||
default:
|
||||
set = true;
|
||||
ignored = true;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
@ -351,13 +361,15 @@ public class HttpExchange
|
|||
throw new AssertionError(oldStatus + " => " + newStatus);
|
||||
}
|
||||
|
||||
if (!set)
|
||||
if (!set && !ignored)
|
||||
throw new IllegalStateException(toState(oldStatus) + " => " + toState(newStatus));
|
||||
LOG.debug("setStatus {} {}",newStatus,this);
|
||||
}
|
||||
catch (IOException x)
|
||||
{
|
||||
LOG.warn(x);
|
||||
}
|
||||
return set;
|
||||
}
|
||||
|
||||
private boolean setStatusExpired(int newStatus, int oldStatus)
|
||||
|
@ -706,25 +718,22 @@ public class HttpExchange
|
|||
return _requestContentSource;
|
||||
}
|
||||
|
||||
public Buffer getRequestContentChunk() throws IOException
|
||||
public Buffer getRequestContentChunk(Buffer buffer) throws IOException
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
if (_requestContentChunk == null)
|
||||
_requestContentChunk = new ByteArrayBuffer(4096); // TODO configure
|
||||
else
|
||||
if (_requestContentSource!=null)
|
||||
{
|
||||
if (_requestContentChunk.hasContent())
|
||||
throw new IllegalStateException();
|
||||
_requestContentChunk.clear();
|
||||
}
|
||||
if (buffer == null)
|
||||
buffer = new ByteArrayBuffer(8192); // TODO configure
|
||||
|
||||
int read = _requestContentChunk.capacity();
|
||||
int length = _requestContentSource.read(_requestContentChunk.array(),0,read);
|
||||
if (length >= 0)
|
||||
{
|
||||
_requestContentChunk.setPutIndex(length);
|
||||
return _requestContentChunk;
|
||||
int space = buffer.space();
|
||||
int length = _requestContentSource.read(buffer.array(),buffer.putIndex(),space);
|
||||
if (length >= 0)
|
||||
{
|
||||
buffer.setPutIndex(buffer.putIndex()+length);
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -779,7 +788,7 @@ public class HttpExchange
|
|||
|
||||
private void abort()
|
||||
{
|
||||
HttpConnection httpConnection = _connection;
|
||||
AbstractHttpConnection httpConnection = _connection;
|
||||
if (httpConnection != null)
|
||||
{
|
||||
try
|
||||
|
@ -799,7 +808,7 @@ public class HttpExchange
|
|||
}
|
||||
}
|
||||
|
||||
void associate(HttpConnection connection)
|
||||
void associate(AbstractHttpConnection connection)
|
||||
{
|
||||
if (connection.getEndPoint().getLocalHost() != null)
|
||||
_localAddress = new Address(connection.getEndPoint().getLocalHost(),connection.getEndPoint().getLocalPort());
|
||||
|
@ -814,9 +823,9 @@ public class HttpExchange
|
|||
return this._connection != null;
|
||||
}
|
||||
|
||||
HttpConnection disassociate()
|
||||
AbstractHttpConnection disassociate()
|
||||
{
|
||||
HttpConnection result = _connection;
|
||||
AbstractHttpConnection result = _connection;
|
||||
this._connection = null;
|
||||
if (getStatus() == STATUS_CANCELLING)
|
||||
setStatus(STATUS_CANCELLED);
|
||||
|
|
|
@ -21,25 +21,21 @@ import java.nio.channels.UnresolvedAddressException;
|
|||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import javax.net.ssl.SSLSession;
|
||||
|
||||
import org.eclipse.jetty.http.HttpGenerator;
|
||||
import org.eclipse.jetty.http.HttpParser;
|
||||
import org.eclipse.jetty.http.ssl.SslContextFactory;
|
||||
import org.eclipse.jetty.io.AsyncEndPoint;
|
||||
import org.eclipse.jetty.io.Buffer;
|
||||
import org.eclipse.jetty.io.Buffers;
|
||||
import org.eclipse.jetty.io.Buffers.Type;
|
||||
import org.eclipse.jetty.io.BuffersFactory;
|
||||
import org.eclipse.jetty.io.ConnectedEndPoint;
|
||||
import org.eclipse.jetty.io.Connection;
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
import org.eclipse.jetty.io.nio.AsyncConnection;
|
||||
import org.eclipse.jetty.io.nio.SelectChannelEndPoint;
|
||||
import org.eclipse.jetty.io.nio.SelectorManager;
|
||||
import org.eclipse.jetty.io.nio.SslSelectChannelEndPoint;
|
||||
import org.eclipse.jetty.io.nio.SslConnection;
|
||||
import org.eclipse.jetty.util.component.AbstractLifeCycle;
|
||||
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
|
||||
{
|
||||
|
@ -48,7 +44,6 @@ class SelectConnector extends AbstractLifeCycle implements HttpClient.Connector
|
|||
private final HttpClient _httpClient;
|
||||
private final Manager _selectorManager=new Manager();
|
||||
private final Map<SocketChannel, Timeout.Task> _connectingChannels = new ConcurrentHashMap<SocketChannel, Timeout.Task>();
|
||||
private Buffers _sslBuffers;
|
||||
|
||||
/**
|
||||
* @param httpClient the HttpClient this connector is associated to
|
||||
|
@ -64,16 +59,6 @@ class SelectConnector extends AbstractLifeCycle implements HttpClient.Connector
|
|||
{
|
||||
super.doStart();
|
||||
|
||||
|
||||
final boolean direct=_httpClient.getUseDirectBuffers();
|
||||
|
||||
SSLEngine sslEngine=_selectorManager.newSslEngine(null);
|
||||
final SSLSession ssl_session=sslEngine.getSession();
|
||||
_sslBuffers = BuffersFactory.newBuffers(
|
||||
direct?Type.DIRECT:Type.INDIRECT,ssl_session.getApplicationBufferSize(),
|
||||
direct?Type.DIRECT:Type.INDIRECT,ssl_session.getApplicationBufferSize(),
|
||||
direct?Type.DIRECT:Type.INDIRECT,1024);
|
||||
|
||||
_selectorManager.start();
|
||||
}
|
||||
|
||||
|
@ -128,6 +113,8 @@ class SelectConnector extends AbstractLifeCycle implements HttpClient.Connector
|
|||
/* ------------------------------------------------------------ */
|
||||
class Manager extends SelectorManager
|
||||
{
|
||||
Logger LOG = SelectConnector.LOG;
|
||||
|
||||
@Override
|
||||
public boolean dispatch(Runnable task)
|
||||
{
|
||||
|
@ -150,12 +137,9 @@ class SelectConnector extends AbstractLifeCycle implements HttpClient.Connector
|
|||
}
|
||||
|
||||
@Override
|
||||
protected Connection newConnection(SocketChannel channel, SelectChannelEndPoint endpoint)
|
||||
public AsyncConnection newConnection(SocketChannel channel, AsyncEndPoint endpoint, Object attachment)
|
||||
{
|
||||
if (endpoint instanceof SslSelectChannelEndPoint)
|
||||
return new HttpConnection(_sslBuffers,_sslBuffers,endpoint);
|
||||
|
||||
return new HttpConnection(_httpClient.getRequestBuffers(),_httpClient.getResponseBuffers(),endpoint);
|
||||
return new AsyncHttpConnection(_httpClient.getRequestBuffers(),_httpClient.getResponseBuffers(),endpoint);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -171,32 +155,29 @@ 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();
|
||||
|
||||
SelectChannelEndPoint ep=null;
|
||||
AsyncEndPoint ep=null;
|
||||
|
||||
SelectChannelEndPoint scep= new SelectChannelEndPoint(channel, selectSet, key, (int)_httpClient.getIdleTimeout());
|
||||
ep = scep;
|
||||
|
||||
if (dest.isSecure())
|
||||
{
|
||||
if (dest.isProxied())
|
||||
{
|
||||
SSLEngine engine=newSslEngine(channel);
|
||||
ep = new ProxySelectChannelEndPoint(channel, selectSet, key, _sslBuffers, engine, (int)_httpClient.getIdleTimeout());
|
||||
}
|
||||
else
|
||||
{
|
||||
SSLEngine engine=newSslEngine(channel);
|
||||
SslSelectChannelEndPoint sslEp = new SslSelectChannelEndPoint(_sslBuffers, channel, selectSet, key, engine, (int)_httpClient.getIdleTimeout());
|
||||
sslEp.setAllowRenegotiate(_httpClient.getSslContextFactory().isAllowRenegotiate());
|
||||
ep = sslEp;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ep = new SelectChannelEndPoint(channel, selectSet, key, (int)_httpClient.getIdleTimeout());
|
||||
LOG.debug("secure to {}, proxied={}",channel,dest.isProxied());
|
||||
ep = new UpgradableEndPoint(ep,newSslEngine(channel));
|
||||
}
|
||||
|
||||
HttpConnection connection=(HttpConnection)ep.getConnection();
|
||||
connection.setDestination(dest);
|
||||
dest.onNewConnection(connection);
|
||||
return ep;
|
||||
AsyncConnection connection = selectSet.getManager().newConnection(channel,ep, key.attachment());
|
||||
ep.setConnection(connection);
|
||||
|
||||
AbstractHttpConnection httpConnection=(AbstractHttpConnection)connection;
|
||||
httpConnection.setDestination(dest);
|
||||
|
||||
if (dest.isSecure() && !dest.isProxied())
|
||||
((UpgradableEndPoint)ep).upgrade();
|
||||
|
||||
dest.onNewConnection(httpConnection);
|
||||
|
||||
return scep;
|
||||
}
|
||||
|
||||
private synchronized SSLEngine newSslEngine(SocketChannel channel) throws IOException
|
||||
|
@ -268,364 +249,194 @@ class SelectConnector extends AbstractLifeCycle implements HttpClient.Connector
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An endpoint that is able to "upgrade" from a normal endpoint to a SSL endpoint.
|
||||
* Since {@link HttpParser} and {@link HttpGenerator} only depend on the {@link EndPoint}
|
||||
* interface, this class overrides all methods of {@link EndPoint} to provide the right
|
||||
* behavior depending on the fact that it has been upgraded or not.
|
||||
*/
|
||||
public static class ProxySelectChannelEndPoint extends SslSelectChannelEndPoint
|
||||
public static class UpgradableEndPoint implements AsyncEndPoint
|
||||
{
|
||||
private final SelectChannelEndPoint plainEndPoint;
|
||||
private final EnforceOverrideEndPointMethods enforcer;
|
||||
private volatile boolean upgraded = false;
|
||||
AsyncEndPoint _endp;
|
||||
SSLEngine _engine;
|
||||
|
||||
public ProxySelectChannelEndPoint(SocketChannel channel, SelectorManager.SelectSet selectSet, SelectionKey key, Buffers sslBuffers, SSLEngine engine, int maxIdleTimeout) throws IOException
|
||||
public UpgradableEndPoint(AsyncEndPoint endp, SSLEngine engine) throws IOException
|
||||
{
|
||||
super(sslBuffers, channel, selectSet, key, engine, maxIdleTimeout);
|
||||
this.plainEndPoint = new SelectChannelEndPoint(channel, selectSet, key, maxIdleTimeout);
|
||||
this.enforcer = new EnforceOverrideEndPointMethods();
|
||||
_engine=engine;
|
||||
_endp=endp;
|
||||
}
|
||||
|
||||
public void upgrade()
|
||||
{
|
||||
upgraded = true;
|
||||
AsyncHttpConnection connection = (AsyncHttpConnection) ((SelectChannelEndPoint)_endp).getConnection();
|
||||
|
||||
SslConnection sslConnection = new SslConnection(_engine,_endp);
|
||||
((SelectChannelEndPoint)_endp).setConnection(sslConnection);
|
||||
|
||||
_endp=sslConnection.getSslEndPoint();
|
||||
sslConnection.getSslEndPoint().setConnection(connection);
|
||||
|
||||
LOG.debug("upgrade {} to {} for {}",this,sslConnection,connection);
|
||||
}
|
||||
|
||||
|
||||
public Connection getConnection()
|
||||
{
|
||||
return _endp.getConnection();
|
||||
}
|
||||
|
||||
public void setConnection(Connection connection)
|
||||
{
|
||||
_endp.setConnection(connection);
|
||||
}
|
||||
|
||||
public void shutdownOutput() throws IOException
|
||||
{
|
||||
enforcer.shutdownOutput();
|
||||
_endp.shutdownOutput();
|
||||
}
|
||||
|
||||
public void asyncDispatch()
|
||||
{
|
||||
_endp.asyncDispatch();
|
||||
}
|
||||
|
||||
public boolean isOutputShutdown()
|
||||
{
|
||||
return enforcer.isOutputShutdown();
|
||||
return _endp.isOutputShutdown();
|
||||
}
|
||||
|
||||
public void shutdownInput() throws IOException
|
||||
{
|
||||
enforcer.shutdownInput();
|
||||
_endp.shutdownInput();
|
||||
}
|
||||
|
||||
public void scheduleWrite()
|
||||
{
|
||||
_endp.scheduleWrite();
|
||||
}
|
||||
|
||||
public boolean isInputShutdown()
|
||||
{
|
||||
return enforcer.isInputShutdown();
|
||||
return _endp.isInputShutdown();
|
||||
}
|
||||
|
||||
public void close() throws IOException
|
||||
{
|
||||
enforcer.close();
|
||||
_endp.close();
|
||||
}
|
||||
|
||||
public void scheduleIdle()
|
||||
{
|
||||
_endp.scheduleIdle();
|
||||
}
|
||||
|
||||
public int fill(Buffer buffer) throws IOException
|
||||
{
|
||||
return enforcer.fill(buffer);
|
||||
return _endp.fill(buffer);
|
||||
}
|
||||
|
||||
public void cancelIdle()
|
||||
{
|
||||
_endp.cancelIdle();
|
||||
}
|
||||
|
||||
public boolean isWritable()
|
||||
{
|
||||
return _endp.isWritable();
|
||||
}
|
||||
|
||||
public boolean hasProgressed()
|
||||
{
|
||||
return _endp.hasProgressed();
|
||||
}
|
||||
|
||||
public int flush(Buffer buffer) throws IOException
|
||||
{
|
||||
return enforcer.flush(buffer);
|
||||
return _endp.flush(buffer);
|
||||
}
|
||||
|
||||
public void scheduleTimeout(Task task, long timeoutMs)
|
||||
{
|
||||
_endp.scheduleTimeout(task,timeoutMs);
|
||||
}
|
||||
|
||||
public void cancelTimeout(Task task)
|
||||
{
|
||||
_endp.cancelTimeout(task);
|
||||
}
|
||||
|
||||
public int flush(Buffer header, Buffer buffer, Buffer trailer) throws IOException
|
||||
{
|
||||
return enforcer.flush(header, buffer, trailer);
|
||||
return _endp.flush(header,buffer,trailer);
|
||||
}
|
||||
|
||||
public String getLocalAddr()
|
||||
{
|
||||
return enforcer.getLocalAddr();
|
||||
return _endp.getLocalAddr();
|
||||
}
|
||||
|
||||
public String getLocalHost()
|
||||
{
|
||||
return enforcer.getLocalHost();
|
||||
return _endp.getLocalHost();
|
||||
}
|
||||
|
||||
public int getLocalPort()
|
||||
{
|
||||
return enforcer.getLocalPort();
|
||||
return _endp.getLocalPort();
|
||||
}
|
||||
|
||||
public String getRemoteAddr()
|
||||
{
|
||||
return enforcer.getRemoteAddr();
|
||||
return _endp.getRemoteAddr();
|
||||
}
|
||||
|
||||
public String getRemoteHost()
|
||||
{
|
||||
return enforcer.getRemoteHost();
|
||||
return _endp.getRemoteHost();
|
||||
}
|
||||
|
||||
public int getRemotePort()
|
||||
{
|
||||
return enforcer.getRemotePort();
|
||||
return _endp.getRemotePort();
|
||||
}
|
||||
|
||||
public boolean isBlocking()
|
||||
{
|
||||
return enforcer.isBlocking();
|
||||
}
|
||||
|
||||
public boolean isBufferred()
|
||||
{
|
||||
return enforcer.isBufferred();
|
||||
return _endp.isBlocking();
|
||||
}
|
||||
|
||||
public boolean blockReadable(long millisecs) throws IOException
|
||||
{
|
||||
return enforcer.blockReadable(millisecs);
|
||||
return _endp.blockReadable(millisecs);
|
||||
}
|
||||
|
||||
public boolean blockWritable(long millisecs) throws IOException
|
||||
{
|
||||
return enforcer.blockWritable(millisecs);
|
||||
return _endp.blockWritable(millisecs);
|
||||
}
|
||||
|
||||
public boolean isOpen()
|
||||
{
|
||||
return enforcer.isOpen();
|
||||
return _endp.isOpen();
|
||||
}
|
||||
|
||||
public Object getTransport()
|
||||
{
|
||||
return enforcer.getTransport();
|
||||
}
|
||||
|
||||
public boolean isBufferingInput()
|
||||
{
|
||||
return enforcer.isBufferingInput();
|
||||
}
|
||||
|
||||
public boolean isBufferingOutput()
|
||||
{
|
||||
return enforcer.isBufferingOutput();
|
||||
return _endp.getTransport();
|
||||
}
|
||||
|
||||
public void flush() throws IOException
|
||||
{
|
||||
enforcer.flush();
|
||||
_endp.flush();
|
||||
}
|
||||
|
||||
public int getMaxIdleTime()
|
||||
{
|
||||
return enforcer.getMaxIdleTime();
|
||||
return _endp.getMaxIdleTime();
|
||||
}
|
||||
|
||||
public void setMaxIdleTime(int timeMs) throws IOException
|
||||
{
|
||||
enforcer.setMaxIdleTime(timeMs);
|
||||
_endp.setMaxIdleTime(timeMs);
|
||||
}
|
||||
|
||||
/**
|
||||
* The only reason this class exist is to enforce that
|
||||
* {@link ProxySelectChannelEndPoint} overrides all methods of {@link EndPoint}.
|
||||
* Therefore, if a method is added to {@link EndPoint}, this class
|
||||
* won't compile anymore, will need an implementation, and one must remember
|
||||
* to override the correspondent method in {@link ProxySelectChannelEndPoint}.
|
||||
*/
|
||||
private class EnforceOverrideEndPointMethods implements EndPoint
|
||||
public String toString()
|
||||
{
|
||||
public void shutdownOutput() throws IOException
|
||||
{
|
||||
if (upgraded)
|
||||
ProxySelectChannelEndPoint.super.shutdownOutput();
|
||||
else
|
||||
plainEndPoint.shutdownOutput();
|
||||
}
|
||||
|
||||
public boolean isOutputShutdown()
|
||||
{
|
||||
if (upgraded)
|
||||
return ProxySelectChannelEndPoint.super.isOutputShutdown();
|
||||
else
|
||||
return plainEndPoint.isOutputShutdown();
|
||||
}
|
||||
|
||||
public void shutdownInput() throws IOException
|
||||
{
|
||||
if (upgraded)
|
||||
ProxySelectChannelEndPoint.super.shutdownInput();
|
||||
else
|
||||
plainEndPoint.shutdownInput();
|
||||
}
|
||||
|
||||
public boolean isInputShutdown()
|
||||
{
|
||||
if (upgraded)
|
||||
return ProxySelectChannelEndPoint.super.isInputShutdown();
|
||||
else
|
||||
return plainEndPoint.isInputShutdown();
|
||||
}
|
||||
|
||||
public void close() throws IOException
|
||||
{
|
||||
if (upgraded)
|
||||
ProxySelectChannelEndPoint.super.close();
|
||||
else
|
||||
plainEndPoint.close();
|
||||
}
|
||||
|
||||
public int fill(Buffer buffer) throws IOException
|
||||
{
|
||||
if (upgraded)
|
||||
return ProxySelectChannelEndPoint.super.fill(buffer);
|
||||
else
|
||||
return plainEndPoint.fill(buffer);
|
||||
}
|
||||
|
||||
public int flush(Buffer buffer) throws IOException
|
||||
{
|
||||
if (upgraded)
|
||||
return ProxySelectChannelEndPoint.super.flush(buffer);
|
||||
else
|
||||
return plainEndPoint.flush(buffer);
|
||||
}
|
||||
|
||||
public int flush(Buffer header, Buffer buffer, Buffer trailer) throws IOException
|
||||
{
|
||||
if (upgraded)
|
||||
return ProxySelectChannelEndPoint.super.flush(header, buffer, trailer);
|
||||
else
|
||||
return plainEndPoint.flush(header, buffer, trailer);
|
||||
}
|
||||
|
||||
public String getLocalAddr()
|
||||
{
|
||||
if (upgraded)
|
||||
return ProxySelectChannelEndPoint.super.getLocalAddr();
|
||||
else
|
||||
return plainEndPoint.getLocalAddr();
|
||||
}
|
||||
|
||||
public String getLocalHost()
|
||||
{
|
||||
if (upgraded)
|
||||
return ProxySelectChannelEndPoint.super.getLocalHost();
|
||||
else
|
||||
return plainEndPoint.getLocalHost();
|
||||
}
|
||||
|
||||
public int getLocalPort()
|
||||
{
|
||||
if (upgraded)
|
||||
return ProxySelectChannelEndPoint.super.getLocalPort();
|
||||
else
|
||||
return plainEndPoint.getLocalPort();
|
||||
}
|
||||
|
||||
public String getRemoteAddr()
|
||||
{
|
||||
if (upgraded)
|
||||
return ProxySelectChannelEndPoint.super.getRemoteAddr();
|
||||
else
|
||||
return plainEndPoint.getRemoteAddr();
|
||||
}
|
||||
|
||||
public String getRemoteHost()
|
||||
{
|
||||
if (upgraded)
|
||||
return ProxySelectChannelEndPoint.super.getRemoteHost();
|
||||
else
|
||||
return plainEndPoint.getRemoteHost();
|
||||
}
|
||||
|
||||
public int getRemotePort()
|
||||
{
|
||||
if (upgraded)
|
||||
return ProxySelectChannelEndPoint.super.getRemotePort();
|
||||
else
|
||||
return plainEndPoint.getRemotePort();
|
||||
}
|
||||
|
||||
public boolean isBlocking()
|
||||
{
|
||||
if (upgraded)
|
||||
return ProxySelectChannelEndPoint.super.isBlocking();
|
||||
else
|
||||
return plainEndPoint.isBlocking();
|
||||
}
|
||||
|
||||
public boolean isBufferred()
|
||||
{
|
||||
if (upgraded)
|
||||
return ProxySelectChannelEndPoint.super.isBufferred();
|
||||
else
|
||||
return plainEndPoint.isBufferred();
|
||||
}
|
||||
|
||||
public boolean blockReadable(long millisecs) throws IOException
|
||||
{
|
||||
if (upgraded)
|
||||
return ProxySelectChannelEndPoint.super.blockReadable(millisecs);
|
||||
else
|
||||
return plainEndPoint.blockReadable(millisecs);
|
||||
}
|
||||
|
||||
public boolean blockWritable(long millisecs) throws IOException
|
||||
{
|
||||
if (upgraded)
|
||||
return ProxySelectChannelEndPoint.super.blockWritable(millisecs);
|
||||
else
|
||||
return plainEndPoint.blockWritable(millisecs);
|
||||
}
|
||||
|
||||
public boolean isOpen()
|
||||
{
|
||||
if (upgraded)
|
||||
return ProxySelectChannelEndPoint.super.isOpen();
|
||||
else
|
||||
return plainEndPoint.isOpen();
|
||||
}
|
||||
|
||||
public Object getTransport()
|
||||
{
|
||||
if (upgraded)
|
||||
return ProxySelectChannelEndPoint.super.getTransport();
|
||||
else
|
||||
return plainEndPoint.getTransport();
|
||||
}
|
||||
|
||||
public boolean isBufferingInput()
|
||||
{
|
||||
if (upgraded)
|
||||
return ProxySelectChannelEndPoint.super.isBufferingInput();
|
||||
else
|
||||
return plainEndPoint.isBufferingInput();
|
||||
}
|
||||
|
||||
public boolean isBufferingOutput()
|
||||
{
|
||||
if (upgraded)
|
||||
return ProxySelectChannelEndPoint.super.isBufferingOutput();
|
||||
else
|
||||
return plainEndPoint.isBufferingOutput();
|
||||
}
|
||||
|
||||
public void flush() throws IOException
|
||||
{
|
||||
if (upgraded)
|
||||
ProxySelectChannelEndPoint.super.flush();
|
||||
else
|
||||
plainEndPoint.flush();
|
||||
|
||||
}
|
||||
|
||||
public int getMaxIdleTime()
|
||||
{
|
||||
if (upgraded)
|
||||
return ProxySelectChannelEndPoint.super.getMaxIdleTime();
|
||||
else
|
||||
return plainEndPoint.getMaxIdleTime();
|
||||
}
|
||||
|
||||
public void setMaxIdleTime(int timeMs) throws IOException
|
||||
{
|
||||
if (upgraded)
|
||||
ProxySelectChannelEndPoint.super.setMaxIdleTime(timeMs);
|
||||
else
|
||||
plainEndPoint.setMaxIdleTime(timeMs);
|
||||
}
|
||||
return "Upgradable:"+_endp.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,6 @@ import java.io.InterruptedIOException;
|
|||
import java.net.Socket;
|
||||
|
||||
import javax.net.SocketFactory;
|
||||
import javax.net.ssl.SSLContext;
|
||||
|
||||
import org.eclipse.jetty.io.Connection;
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
|
@ -55,9 +54,9 @@ class SocketConnector extends AbstractLifeCycle implements HttpClient.Connector
|
|||
Address address = destination.isProxied() ? destination.getProxy() : destination.getAddress();
|
||||
socket.connect(address.toSocketAddress(), _httpClient.getConnectTimeout());
|
||||
|
||||
EndPoint endpoint=new SocketEndPoint(socket);
|
||||
final EndPoint endpoint=new SocketEndPoint(socket);
|
||||
|
||||
final HttpConnection connection=new HttpConnection(_httpClient.getRequestBuffers(),_httpClient.getResponseBuffers(),endpoint);
|
||||
final AbstractHttpConnection connection=new BlockingHttpConnection(_httpClient.getRequestBuffers(),_httpClient.getResponseBuffers(),endpoint);
|
||||
connection.setDestination(destination);
|
||||
destination.onNewConnection(connection);
|
||||
_httpClient.getThreadPool().dispatch(new Runnable()
|
||||
|
|
|
@ -14,7 +14,11 @@
|
|||
|
||||
package org.eclipse.jetty.client;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
|
@ -25,9 +29,6 @@ import java.util.concurrent.TimeUnit;
|
|||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* @version $Revision$ $Date$
|
||||
*/
|
||||
|
@ -41,6 +42,14 @@ public abstract class AbstractConnectionTest
|
|||
return httpClient;
|
||||
}
|
||||
|
||||
|
||||
protected ServerSocket newServerSocket() throws IOException
|
||||
{
|
||||
ServerSocket serverSocket=new ServerSocket();
|
||||
serverSocket.bind(null);
|
||||
return serverSocket;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testServerClosedConnection() throws Exception
|
||||
{
|
||||
|
@ -119,11 +128,15 @@ public abstract class AbstractConnectionTest
|
|||
}
|
||||
}
|
||||
|
||||
protected String getScheme()
|
||||
{
|
||||
return "http";
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testServerClosedIncomplete() throws Exception
|
||||
{
|
||||
ServerSocket serverSocket = new ServerSocket();
|
||||
serverSocket.bind(null);
|
||||
ServerSocket serverSocket = newServerSocket();
|
||||
int port=serverSocket.getLocalPort();
|
||||
|
||||
HttpClient httpClient = newHttpClient();
|
||||
|
@ -133,6 +146,7 @@ public abstract class AbstractConnectionTest
|
|||
{
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
HttpExchange exchange = new ConnectionExchange(latch);
|
||||
exchange.setScheme(getScheme());
|
||||
exchange.setAddress(new Address("localhost", port));
|
||||
exchange.setRequestURI("/");
|
||||
httpClient.send(exchange);
|
||||
|
@ -159,7 +173,9 @@ public abstract class AbstractConnectionTest
|
|||
|
||||
remote.close();
|
||||
|
||||
assertEquals(HttpExchange.STATUS_EXCEPTED, exchange.waitForDone());
|
||||
int status = exchange.waitForDone();
|
||||
|
||||
assertEquals(HttpExchange.STATUS_EXCEPTED, status);
|
||||
|
||||
}
|
||||
finally
|
||||
|
@ -346,27 +362,33 @@ public abstract class AbstractConnectionTest
|
|||
HttpDestination dest = httpClient.getDestination(new Address("localhost", port),false);
|
||||
|
||||
httpClient.send(exchange);
|
||||
Socket s = serverSocket.accept();
|
||||
Socket server = serverSocket.accept();
|
||||
server.setSoTimeout(5000);
|
||||
byte[] buf = new byte[4096];
|
||||
s.getInputStream().read(buf);
|
||||
|
||||
int len=server.getInputStream().read(buf);
|
||||
assertEquals(1,dest.getConnections());
|
||||
assertEquals(0,dest.getIdleConnections());
|
||||
|
||||
s.getOutputStream().write("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n".getBytes());
|
||||
|
||||
Thread.sleep(300);
|
||||
server.getOutputStream().write("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n".getBytes());
|
||||
|
||||
assertEquals(HttpExchange.STATUS_COMPLETED,exchange.waitForDone());
|
||||
Thread.sleep(200); // TODO get rid of this
|
||||
assertEquals(1,dest.getConnections());
|
||||
assertEquals(1,dest.getIdleConnections());
|
||||
|
||||
exchange = new ConnectionExchange();
|
||||
exchange.setAddress(new Address("localhost", port));
|
||||
exchange.setRequestURI("/");
|
||||
|
||||
httpClient.send(exchange);
|
||||
s.getInputStream().read(buf);
|
||||
assertEquals(1,dest.getConnections());
|
||||
assertEquals(0,dest.getIdleConnections());
|
||||
s.getOutputStream().write("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n".getBytes());
|
||||
|
||||
|
||||
len=server.getInputStream().read(buf);
|
||||
assertEquals(1,dest.getConnections());
|
||||
assertEquals(0,dest.getIdleConnections());
|
||||
server.getOutputStream().write("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n".getBytes());
|
||||
|
||||
Thread.sleep(500);
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
package org.eclipse.jetty.client;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -25,23 +26,25 @@ import javax.servlet.http.HttpServletRequest;
|
|||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.io.Buffer;
|
||||
import org.eclipse.jetty.server.AbstractHttpConnection;
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.HttpConnection;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||
import org.eclipse.jetty.server.nio.SelectChannelConnector;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.util.log.StdErrLog;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @version $Revision$ $Date$
|
||||
*/
|
||||
public abstract class AbstractHttpExchangeCancelTest
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(AbstractHttpExchangeCancelTest.TestHttpExchange.class);
|
||||
|
||||
private Server server;
|
||||
private Connector connector;
|
||||
|
||||
|
@ -73,13 +76,13 @@ public abstract class AbstractHttpExchangeCancelTest
|
|||
TestHttpExchange exchange = new TestHttpExchange()
|
||||
{
|
||||
@Override
|
||||
void setStatus(int status)
|
||||
boolean setStatus(int status)
|
||||
{
|
||||
// Cancel before setting the new status
|
||||
if (getStatus() == HttpExchange.STATUS_START &&
|
||||
status == STATUS_WAITING_FOR_CONNECTION)
|
||||
cancel();
|
||||
super.setStatus(status);
|
||||
return super.setStatus(status);
|
||||
}
|
||||
};
|
||||
exchange.setAddress(newAddress());
|
||||
|
@ -110,14 +113,15 @@ public abstract class AbstractHttpExchangeCancelTest
|
|||
TestHttpExchange exchange = new TestHttpExchange()
|
||||
{
|
||||
@Override
|
||||
void setStatus(int status)
|
||||
boolean setStatus(int status)
|
||||
{
|
||||
// Cancel after setting the new status
|
||||
int oldStatus = getStatus();
|
||||
super.setStatus(status);
|
||||
boolean set = super.setStatus(status);
|
||||
if (oldStatus == STATUS_START &&
|
||||
getStatus() == HttpExchange.STATUS_WAITING_FOR_CONNECTION)
|
||||
cancel();
|
||||
return set;
|
||||
}
|
||||
};
|
||||
exchange.setAddress(newAddress());
|
||||
|
@ -181,10 +185,10 @@ public abstract class AbstractHttpExchangeCancelTest
|
|||
getHttpClient().send(exchange);
|
||||
|
||||
int status = exchange.waitForDone();
|
||||
assertEquals(HttpExchange.STATUS_CANCELLED, status);
|
||||
assertFalse(exchange.isResponseCompleted());
|
||||
assertFalse(exchange.isFailed());
|
||||
assertFalse(exchange.isAssociated());
|
||||
assertThat("Exchange Status", status, is(HttpExchange.STATUS_CANCELLED));
|
||||
assertThat("Exchange.isResponseCompleted", exchange.isResponseCompleted(), is(false));
|
||||
assertThat("Exchange.isFailed", exchange.isFailed(), is(false));
|
||||
assertThat("Exchange.isAssociated", exchange.isAssociated(), is(false));
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -318,7 +322,7 @@ public abstract class AbstractHttpExchangeCancelTest
|
|||
{
|
||||
try
|
||||
{
|
||||
((StdErrLog)Log.getLogger(HttpConnection.class)).setHideStacks(true);
|
||||
((StdErrLog)Log.getLogger(AbstractHttpConnection.class)).setHideStacks(true);
|
||||
TestHttpExchange exchange = new TestHttpExchange();
|
||||
exchange.setAddress(newAddress());
|
||||
exchange.setRequestURI("/?action=throw");
|
||||
|
@ -333,7 +337,7 @@ public abstract class AbstractHttpExchangeCancelTest
|
|||
}
|
||||
finally
|
||||
{
|
||||
((StdErrLog)Log.getLogger(HttpConnection.class)).setHideStacks(false);
|
||||
((StdErrLog)Log.getLogger(AbstractHttpConnection.class)).setHideStacks(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -442,6 +446,7 @@ public abstract class AbstractHttpExchangeCancelTest
|
|||
@Override
|
||||
protected synchronized void onException(Throwable ex)
|
||||
{
|
||||
LOG.debug(ex);
|
||||
if (ex instanceof SocketTimeoutException ||
|
||||
ex.getCause() instanceof SocketTimeoutException)
|
||||
expired=true;
|
||||
|
|
|
@ -13,6 +13,13 @@
|
|||
|
||||
package org.eclipse.jetty.client;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.ServerSocket;
|
||||
|
||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
import org.junit.BeforeClass;
|
||||
|
||||
public class AsyncSelectConnectionTest extends AbstractConnectionTest
|
||||
{
|
||||
protected HttpClient newHttpClient()
|
||||
|
@ -23,10 +30,38 @@ public class AsyncSelectConnectionTest extends AbstractConnectionTest
|
|||
return httpClient;
|
||||
}
|
||||
|
||||
static SslContextFactory ctx = new SslContextFactory(MavenTestingUtils.getTestResourceFile("keystore").getAbsolutePath());
|
||||
|
||||
@BeforeClass
|
||||
public static void initKS() throws Exception
|
||||
{
|
||||
ctx.setKeyStorePassword("storepwd");
|
||||
ctx.setKeyManagerPassword("keypwd");
|
||||
ctx.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getScheme()
|
||||
{
|
||||
return "https";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ServerSocket newServerSocket() throws IOException
|
||||
{
|
||||
return ctx.newSslServerSocket(null,0,100);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void testServerHalfClosedIncomplete() throws Exception
|
||||
{
|
||||
super.testServerHalfClosedIncomplete();
|
||||
// SSL doesn't do half closes
|
||||
}
|
||||
|
||||
@Override
|
||||
public void testServerClosedIncomplete() throws Exception
|
||||
{
|
||||
super.testServerClosedIncomplete();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -16,7 +16,6 @@ package org.eclipse.jetty.client;
|
|||
import org.eclipse.jetty.client.helperClasses.AsyncSslServerAndClientCreator;
|
||||
import org.eclipse.jetty.client.helperClasses.ServerAndClientCreator;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
public class AsyncSslHttpExchangeTest extends SslHttpExchangeTest
|
||||
|
@ -32,4 +31,18 @@ public class AsyncSslHttpExchangeTest extends SslHttpExchangeTest
|
|||
_port = _server.getConnectors()[0].getLocalPort();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testPerf1() throws Exception
|
||||
{
|
||||
sender(1,true);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void testGetWithContentExchange() throws Exception
|
||||
{
|
||||
super.testGetWithContentExchange();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
public class ExternalKeyStoreAsyncSslHttpExchangeTest extends SslHttpExchangeTest
|
||||
|
|
|
@ -13,8 +13,12 @@
|
|||
|
||||
package org.eclipse.jetty.client;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.junit.matchers.JUnitMatchers.*;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.matchers.JUnitMatchers.containsString;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
@ -34,15 +38,14 @@ 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;
|
||||
import org.eclipse.jetty.toolchain.test.Stress;
|
||||
import org.eclipse.jetty.util.component.AbstractLifeCycle;
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -51,7 +54,7 @@ import org.junit.Test;
|
|||
*/
|
||||
public class HttpExchangeTest
|
||||
{
|
||||
final static boolean verbose=false;
|
||||
final static boolean verbose=true;
|
||||
protected static int _maxConnectionsPerAddress = 2;
|
||||
protected static String _scheme = "http";
|
||||
protected static Server _server;
|
||||
|
@ -125,6 +128,7 @@ public class HttpExchangeTest
|
|||
*/
|
||||
public void sender(final int nb, final boolean close) throws Exception
|
||||
{
|
||||
// System.err.printf("%nSENDER %d %s%n",nb,close);
|
||||
_count.set(0);
|
||||
final CountDownLatch complete = new CountDownLatch(nb);
|
||||
final AtomicInteger allcontent = new AtomicInteger(nb);
|
||||
|
@ -144,7 +148,7 @@ public class HttpExchangeTest
|
|||
protected void onRequestCommitted()
|
||||
{
|
||||
if (verbose)
|
||||
System.err.println("[ ");
|
||||
System.err.println(n+" [ "+this);
|
||||
result = "committed";
|
||||
}
|
||||
|
||||
|
@ -153,7 +157,7 @@ public class HttpExchangeTest
|
|||
protected void onRequestComplete() throws IOException
|
||||
{
|
||||
if (verbose)
|
||||
System.err.println("[ ==");
|
||||
System.err.println(n+" [ ==");
|
||||
result = "sent";
|
||||
}
|
||||
|
||||
|
@ -162,7 +166,7 @@ public class HttpExchangeTest
|
|||
protected void onResponseStatus(Buffer version, int status, Buffer reason)
|
||||
{
|
||||
if (verbose)
|
||||
System.err.println("] "+version+" "+status+" "+reason);
|
||||
System.err.println(n+" ] "+version+" "+status+" "+reason);
|
||||
result = "status";
|
||||
}
|
||||
|
||||
|
@ -171,7 +175,7 @@ public class HttpExchangeTest
|
|||
protected void onResponseHeader(Buffer name, Buffer value)
|
||||
{
|
||||
if (verbose)
|
||||
System.err.println("] "+name+": "+value);
|
||||
System.err.println(n+" ] "+name+": "+value);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -179,7 +183,7 @@ public class HttpExchangeTest
|
|||
protected void onResponseHeaderComplete() throws IOException
|
||||
{
|
||||
if (verbose)
|
||||
System.err.println("] -");
|
||||
System.err.println(n+" ] -");
|
||||
result = "content";
|
||||
super.onResponseHeaderComplete();
|
||||
}
|
||||
|
@ -190,7 +194,7 @@ public class HttpExchangeTest
|
|||
{
|
||||
len += content.length();
|
||||
if (verbose)
|
||||
System.err.println("] "+content.length()+" -> "+len);
|
||||
System.err.println(n+" ] "+content.length()+" -> "+len);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -198,12 +202,12 @@ public class HttpExchangeTest
|
|||
protected void onResponseComplete()
|
||||
{
|
||||
if (verbose)
|
||||
System.err.println("] == "+len+" "+complete.getCount()+"/"+nb);
|
||||
System.err.println(n+" ] == "+len+" "+complete.getCount()+"/"+nb);
|
||||
result = "complete";
|
||||
if (len == 2009)
|
||||
allcontent.decrementAndGet();
|
||||
else
|
||||
System.err.println(n + " ONLY " + len+ "/2009");
|
||||
System.err.println(n+ " ONLY " + len+ "/2009");
|
||||
complete.countDown();
|
||||
}
|
||||
|
||||
|
@ -212,10 +216,10 @@ public class HttpExchangeTest
|
|||
protected void onConnectionFailed(Throwable ex)
|
||||
{
|
||||
if (verbose)
|
||||
System.err.println("] "+ex);
|
||||
System.err.println(n+" ] "+ex);
|
||||
complete.countDown();
|
||||
result = "failed";
|
||||
System.err.println(n + " FAILED " + ex);
|
||||
System.err.println(n+ " FAILED " + ex);
|
||||
super.onConnectionFailed(ex);
|
||||
}
|
||||
|
||||
|
@ -224,10 +228,10 @@ public class HttpExchangeTest
|
|||
protected void onException(Throwable ex)
|
||||
{
|
||||
if (verbose)
|
||||
System.err.println("] "+ex);
|
||||
System.err.println(n+" ] "+ex);
|
||||
complete.countDown();
|
||||
result = "excepted";
|
||||
System.err.println(n + " EXCEPTED " + ex);
|
||||
System.err.println(n+ " EXCEPTED " + ex);
|
||||
super.onException(ex);
|
||||
}
|
||||
|
||||
|
@ -236,7 +240,7 @@ public class HttpExchangeTest
|
|||
protected void onExpire()
|
||||
{
|
||||
if (verbose)
|
||||
System.err.println("] expired");
|
||||
System.err.println(n+" ] expired");
|
||||
complete.countDown();
|
||||
result = "expired";
|
||||
System.err.println(n + " EXPIRED " + len);
|
||||
|
@ -297,7 +301,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);
|
||||
|
@ -475,10 +479,7 @@ public class HttpExchangeTest
|
|||
@Test
|
||||
public void testSlowPost() throws Exception
|
||||
{
|
||||
ContentExchange httpExchange=new ContentExchange()
|
||||
{
|
||||
|
||||
};
|
||||
ContentExchange httpExchange=new ContentExchange();
|
||||
httpExchange.setURI(getBaseURI());
|
||||
httpExchange.setMethod(HttpMethods.POST);
|
||||
|
||||
|
@ -491,15 +492,27 @@ public class HttpExchangeTest
|
|||
@Override
|
||||
public int read() throws IOException
|
||||
{
|
||||
// System.err.printf("reading 1 of %d/%d%n",_index,data.length());
|
||||
if (_index>=data.length())
|
||||
return -1;
|
||||
|
||||
try
|
||||
{
|
||||
Thread.sleep(5);
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
// System.err.printf("read 1%n");
|
||||
return data.charAt(_index++);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte[] b, int off, int len) throws IOException
|
||||
{
|
||||
// System.err.printf("reading %d of %d/%d%n",len,_index,data.length());
|
||||
if (_index >= data.length())
|
||||
return -1;
|
||||
|
||||
|
@ -516,18 +529,17 @@ public class HttpExchangeTest
|
|||
|
||||
while (l < 5 && _index < data.length() && l < len)
|
||||
b[off + l++] = (byte)data.charAt(_index++);
|
||||
// System.err.printf("read %d%n",l);
|
||||
return l;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
httpExchange.setRequestContentSource(content);
|
||||
// httpExchange.setRequestContent(new ByteArrayBuffer(data));
|
||||
|
||||
_httpClient.send(httpExchange);
|
||||
|
||||
int status = httpExchange.waitForDone();
|
||||
// httpExchange.waitForStatus(HttpExchange.STATUS_COMPLETED);
|
||||
String result = httpExchange.getResponseContent();
|
||||
assertEquals(HttpExchange.STATUS_COMPLETED,status);
|
||||
assertEquals(data,result);
|
||||
|
@ -571,7 +583,7 @@ public class HttpExchangeTest
|
|||
{
|
||||
_httpClient = serverAndClientCreator.createClient(3000L,3500L,2000);
|
||||
final HttpDestination destination = _httpClient.getDestination(new Address("localhost",_port),_scheme.equalsIgnoreCase("https"));
|
||||
final org.eclipse.jetty.client.HttpConnection[] connections = new org.eclipse.jetty.client.HttpConnection[_maxConnectionsPerAddress];
|
||||
final org.eclipse.jetty.client.AbstractHttpConnection[] connections = new org.eclipse.jetty.client.AbstractHttpConnection[_maxConnectionsPerAddress];
|
||||
for (int i = 0; i < _maxConnectionsPerAddress; i++)
|
||||
{
|
||||
connections[i] = destination.reserveConnection(200);
|
||||
|
@ -595,7 +607,7 @@ public class HttpExchangeTest
|
|||
assertNotNull(c);
|
||||
|
||||
// release connections
|
||||
for (HttpConnection httpConnection : connections){
|
||||
for (AbstractHttpConnection httpConnection : connections){
|
||||
destination.returnConnection(httpConnection,false);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ import javax.servlet.http.HttpServletRequest;
|
|||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.eclipse.jetty.server.HttpConnection;
|
||||
import org.eclipse.jetty.server.AbstractHttpConnection;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.ConnectHandler;
|
||||
|
@ -68,7 +68,16 @@ public class HttpsViaBrokenHttpProxyTest
|
|||
@Test
|
||||
public void httpsViaProxyThatClosesConnectionOnConnectRequestTest() throws Exception
|
||||
{
|
||||
sendRequestThroughProxy(new ContentExchange(), "close", 9);
|
||||
sendRequestThroughProxy(new ContentExchange()
|
||||
{
|
||||
|
||||
@Override
|
||||
protected void onException(Throwable x)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}, "close", 9);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -110,7 +119,7 @@ public class HttpsViaBrokenHttpProxyTest
|
|||
{
|
||||
if (serverAddress.contains("close"))
|
||||
{
|
||||
HttpConnection.getCurrentConnection().getEndPoint().close();
|
||||
AbstractHttpConnection.getCurrentConnection().getEndPoint().close();
|
||||
}
|
||||
else if (serverAddress.contains("error500"))
|
||||
{
|
||||
|
|
|
@ -51,4 +51,10 @@ public class NonBlockingHttpExchangeCancelTest extends AbstractHttpExchangeCance
|
|||
{
|
||||
return httpClient;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void testHttpExchangeCancelOnRequestComplete() throws Exception
|
||||
{
|
||||
super.testHttpExchangeCancelOnRequestComplete();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,6 @@ import javax.servlet.http.HttpServletResponse;
|
|||
import org.eclipse.jetty.http.HttpHeaders;
|
||||
import org.eclipse.jetty.http.HttpMethods;
|
||||
import org.eclipse.jetty.http.MimeTypes;
|
||||
import org.eclipse.jetty.http.ssl.SslContextFactory;
|
||||
import org.eclipse.jetty.io.ByteArrayBuffer;
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.Handler;
|
||||
|
@ -27,6 +26,7 @@ import org.eclipse.jetty.server.handler.ConnectHandler;
|
|||
import org.eclipse.jetty.server.nio.SelectChannelConnector;
|
||||
import org.eclipse.jetty.server.ssl.SslSelectChannelConnector;
|
||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
|
||||
|
|
|
@ -19,7 +19,6 @@ import java.util.HashSet;
|
|||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jetty.client.security.Realm;
|
||||
import org.eclipse.jetty.http.security.Constraint;
|
||||
import org.eclipse.jetty.security.ConstraintMapping;
|
||||
import org.eclipse.jetty.security.ConstraintSecurityHandler;
|
||||
import org.eclipse.jetty.security.HashLoginService;
|
||||
|
@ -33,6 +32,7 @@ import org.eclipse.jetty.servlet.DefaultServlet;
|
|||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||
import org.eclipse.jetty.util.security.Constraint;
|
||||
|
||||
public class SecuredContentExchangeTest
|
||||
extends ContentExchangeTest
|
||||
|
|
|
@ -20,7 +20,6 @@ import java.util.Set;
|
|||
|
||||
import org.eclipse.jetty.client.security.Realm;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.eclipse.jetty.http.security.Constraint;
|
||||
import org.eclipse.jetty.security.ConstraintMapping;
|
||||
import org.eclipse.jetty.security.ConstraintSecurityHandler;
|
||||
import org.eclipse.jetty.security.HashLoginService;
|
||||
|
@ -34,6 +33,7 @@ import org.eclipse.jetty.servlet.DefaultServlet;
|
|||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||
import org.eclipse.jetty.util.security.Constraint;
|
||||
import org.junit.Test;
|
||||
|
||||
public class SecuredErrorStatusTest
|
||||
|
|
|
@ -31,7 +31,6 @@ import javax.servlet.http.HttpServletResponse;
|
|||
import org.eclipse.jetty.client.security.Realm;
|
||||
import org.eclipse.jetty.client.security.SimpleRealmResolver;
|
||||
import org.eclipse.jetty.http.HttpMethods;
|
||||
import org.eclipse.jetty.http.security.Constraint;
|
||||
import org.eclipse.jetty.io.Buffer;
|
||||
import org.eclipse.jetty.io.EofException;
|
||||
import org.eclipse.jetty.security.ConstraintMapping;
|
||||
|
@ -46,6 +45,7 @@ import org.eclipse.jetty.server.Server;
|
|||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||
import org.eclipse.jetty.server.nio.SelectChannelConnector;
|
||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||
import org.eclipse.jetty.util.security.Constraint;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
|
|
@ -0,0 +1,250 @@
|
|||
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;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
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;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.bio.SocketConnector;
|
||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* A class that attempts to simulate a client communicating with a slow server. It imposes a delay between each handle() call made to the server's handler.
|
||||
*
|
||||
* The client sends a binary blob of data to the server, and this blob is then inspected to verify correct transfer.
|
||||
*/
|
||||
public class SluggishServerTest
|
||||
{
|
||||
|
||||
/** msec to wait between reads in the handler -- may need to adjust based on OS/HW/etc. to reproduce bug */
|
||||
private final static int READ_DELAY = 5;
|
||||
|
||||
private final static String URL = "http://localhost:";
|
||||
|
||||
/** Stream providing a binary message to send */
|
||||
private static class SluggishStream extends InputStream
|
||||
{
|
||||
private final byte[] request;
|
||||
private int pos;
|
||||
|
||||
public SluggishStream(byte[] request)
|
||||
{
|
||||
this.request = request;
|
||||
this.pos = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException
|
||||
{
|
||||
if (pos < request.length)
|
||||
{
|
||||
int byteVal = request[pos++] & 0xFF;
|
||||
return byteVal;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** Sends a message containing random binary content to a SluggishHandler */
|
||||
private static class SluggishExchange extends HttpExchange
|
||||
{
|
||||
private byte[] request;
|
||||
|
||||
public SluggishExchange(int port, int count)
|
||||
{
|
||||
request = new byte[count];
|
||||
for (int i=0;i<count;i++)
|
||||
request[i]=(byte)('A'+(i%26));
|
||||
setURL(URL+port);
|
||||
setRequestContentSource(new SluggishStream(request));
|
||||
setRequestContentType("application/octet-stream");
|
||||
setRequestHeader(HttpHeaders.TRANSFER_ENCODING,HttpHeaderValues.CHUNKED);
|
||||
}
|
||||
|
||||
public byte[] getRequestBody()
|
||||
{
|
||||
return request;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRequestComplete()
|
||||
{
|
||||
//System.err.println("REQUEST COMPLETE " + this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResponseComplete()
|
||||
{
|
||||
//System.err.println("RESPONSE COMPLETE " + this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResponseStatus(Buffer version, int status, Buffer reason) throws IOException
|
||||
{
|
||||
//System.err.printf("<<< %s %d %s%n",version,status,reason);
|
||||
super.onResponseStatus(version,status,reason);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResponseHeader(Buffer name, Buffer value) throws IOException
|
||||
{
|
||||
//System.err.printf("<<< %s: %s%n",name,value);
|
||||
super.onResponseHeader(name,value);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResponseHeaderComplete() throws IOException
|
||||
{
|
||||
//System.err.printf("<<< --%n");
|
||||
super.onResponseHeaderComplete();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** Receives binary message from a SluggishExchange & stores it for validation */
|
||||
private static class SluggishHandler extends AbstractHandler
|
||||
{
|
||||
|
||||
private final ArrayList<Byte> accumulatedRequest;
|
||||
|
||||
public SluggishHandler(int requestSize)
|
||||
{
|
||||
accumulatedRequest = new ArrayList<Byte>(requestSize);
|
||||
}
|
||||
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
{
|
||||
accumulatedRequest.clear();
|
||||
ServletInputStream input = request.getInputStream();
|
||||
byte[] buffer = new byte[16384];
|
||||
int bytesAvailable;
|
||||
while ((bytesAvailable = input.read(buffer,0,buffer.length)) > 0)
|
||||
{
|
||||
//System.err.println("AVAILABLE FOR READ = " + bytesAvailable);
|
||||
for (int n = 0; n < bytesAvailable; ++n)
|
||||
{
|
||||
accumulatedRequest.add(buffer[n]);
|
||||
}
|
||||
try
|
||||
{
|
||||
Thread.sleep(READ_DELAY);
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
response.setStatus(HttpServletResponse.SC_OK);
|
||||
baseRequest.setHandled(true);
|
||||
//System.err.println("HANDLED");
|
||||
}
|
||||
|
||||
public byte[] getAccumulatedRequest()
|
||||
{
|
||||
byte[] buffer = new byte[accumulatedRequest.size()];
|
||||
int pos = 0;
|
||||
for (Byte b : accumulatedRequest)
|
||||
{
|
||||
buffer[pos++] = b;
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean compareBuffers(byte[] sent, byte[] received)
|
||||
{
|
||||
if (sent.length != received.length)
|
||||
{
|
||||
System.err.format("Mismatch in sent/received lengths: sent=%d received=%d\n",sent.length,received.length);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int n = 0; n < sent.length; ++n)
|
||||
{
|
||||
if (sent[n] != received[n])
|
||||
{
|
||||
System.err.format("Mismatch at offset %d: request=%d response=%d\n",n,sent[n],received[n]);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test0() throws Exception
|
||||
{
|
||||
goSlow(20000,10);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test1() throws Exception
|
||||
{
|
||||
goSlow(200000,5);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test2() throws Exception
|
||||
{
|
||||
goSlow(2000000,2);
|
||||
}
|
||||
|
||||
void goSlow(int requestSize,int iterations) throws Exception
|
||||
{
|
||||
Server server = new Server();
|
||||
SocketConnector connector = new SocketConnector();
|
||||
server.addConnector(connector);
|
||||
SluggishHandler handler = new SluggishHandler(requestSize);
|
||||
server.setHandler(handler);
|
||||
server.start();
|
||||
int port = connector.getLocalPort();
|
||||
|
||||
HttpClient client = new HttpClient();
|
||||
client.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL);
|
||||
client.setConnectTimeout(5000);
|
||||
client.setIdleTimeout(60000);
|
||||
client.start();
|
||||
|
||||
try
|
||||
{
|
||||
for (int i = 0; i < iterations; ++i)
|
||||
{
|
||||
//System.err.format("-------------- ITERATION %d ------------------\n",i);
|
||||
SluggishExchange exchange = new SluggishExchange(port,requestSize);
|
||||
long startTime = System.currentTimeMillis();
|
||||
client.send(exchange);
|
||||
exchange.waitForDone();
|
||||
long endTime = System.currentTimeMillis();
|
||||
//System.err.println("EXCHANGE STATUS = " + exchange);
|
||||
//System.err.println("ELAPSED MSEC = " + (endTime - startTime));
|
||||
Assert.assertTrue(compareBuffers(exchange.getRequestBody(),handler.getAccumulatedRequest()));
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
server.stop();
|
||||
server.join();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -13,6 +13,8 @@
|
|||
|
||||
package org.eclipse.jetty.client;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
|
@ -21,8 +23,6 @@ import java.net.ServerSocket;
|
|||
import java.net.Socket;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class SocketConnectionTest extends AbstractConnectionTest
|
||||
{
|
||||
protected HttpClient newHttpClient()
|
||||
|
@ -88,4 +88,9 @@ public class SocketConnectionTest extends AbstractConnectionTest
|
|||
httpClient.stop();
|
||||
}
|
||||
}
|
||||
|
||||
public void testIdleConnection() throws Exception
|
||||
{
|
||||
super.testIdleConnection();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,9 +20,6 @@ import java.util.Set;
|
|||
|
||||
import javax.security.auth.Subject;
|
||||
|
||||
import org.eclipse.jetty.http.security.Constraint;
|
||||
import org.eclipse.jetty.http.security.Credential;
|
||||
import org.eclipse.jetty.http.ssl.SslContextFactory;
|
||||
import org.eclipse.jetty.security.ConstraintMapping;
|
||||
import org.eclipse.jetty.security.ConstraintSecurityHandler;
|
||||
import org.eclipse.jetty.security.IdentityService;
|
||||
|
@ -38,6 +35,9 @@ import org.eclipse.jetty.servlet.DefaultServlet;
|
|||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||
import org.eclipse.jetty.util.security.Constraint;
|
||||
import org.eclipse.jetty.util.security.Credential;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
|
||||
public class SslCertSecuredExchangeTest extends ContentExchangeTest
|
||||
{
|
||||
|
|
|
@ -15,7 +15,6 @@ package org.eclipse.jetty.client;
|
|||
|
||||
import java.io.File;
|
||||
|
||||
import org.eclipse.jetty.http.ssl.SslContextFactory;
|
||||
import org.eclipse.jetty.server.Handler;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.HandlerCollection;
|
||||
|
@ -24,6 +23,7 @@ import org.eclipse.jetty.servlet.DefaultServlet;
|
|||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
|
||||
public class SslContentExchangeTest
|
||||
extends ContentExchangeTest
|
||||
|
|
|
@ -13,7 +13,8 @@
|
|||
|
||||
package org.eclipse.jetty.client;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
|
||||
import org.eclipse.jetty.client.helperClasses.ServerAndClientCreator;
|
||||
import org.eclipse.jetty.client.helperClasses.SslServerAndClientCreator;
|
||||
|
@ -22,7 +23,6 @@ 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.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
|
@ -72,9 +72,6 @@ public class SslHttpExchangeTest extends HttpExchangeTest
|
|||
@Override
|
||||
public void testPerf() throws Exception
|
||||
{
|
||||
// TODO needs to be further investigated
|
||||
Assume.assumeTrue(!OS.IS_OSX || Stress.isEnabled());
|
||||
|
||||
// TODO Resolve problems on IBM JVM https://bugs.eclipse.org/bugs/show_bug.cgi?id=304532
|
||||
IgnoreTestOnBuggyIBM();
|
||||
super.testPerf();
|
||||
|
|
|
@ -19,8 +19,6 @@ import java.util.HashSet;
|
|||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jetty.client.security.Realm;
|
||||
import org.eclipse.jetty.http.security.Constraint;
|
||||
import org.eclipse.jetty.http.ssl.SslContextFactory;
|
||||
import org.eclipse.jetty.security.ConstraintMapping;
|
||||
import org.eclipse.jetty.security.ConstraintSecurityHandler;
|
||||
import org.eclipse.jetty.security.HashLoginService;
|
||||
|
@ -34,6 +32,8 @@ import org.eclipse.jetty.servlet.DefaultServlet;
|
|||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||
import org.eclipse.jetty.util.security.Constraint;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
|
||||
public class SslSecuredContentExchangeTest
|
||||
extends ContentExchangeTest
|
||||
|
|
|
@ -20,7 +20,6 @@ import java.util.Set;
|
|||
|
||||
import org.eclipse.jetty.client.security.Realm;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.eclipse.jetty.http.security.Constraint;
|
||||
import org.eclipse.jetty.security.ConstraintMapping;
|
||||
import org.eclipse.jetty.security.ConstraintSecurityHandler;
|
||||
import org.eclipse.jetty.security.HashLoginService;
|
||||
|
@ -34,6 +33,7 @@ import org.eclipse.jetty.servlet.DefaultServlet;
|
|||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||
import org.eclipse.jetty.util.security.Constraint;
|
||||
import org.junit.Test;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
|
|
@ -34,8 +34,6 @@ import javax.servlet.http.HttpServletResponse;
|
|||
import org.eclipse.jetty.client.security.HashRealmResolver;
|
||||
import org.eclipse.jetty.client.security.Realm;
|
||||
import org.eclipse.jetty.http.HttpMethods;
|
||||
import org.eclipse.jetty.http.security.Constraint;
|
||||
import org.eclipse.jetty.http.ssl.SslContextFactory;
|
||||
import org.eclipse.jetty.io.EofException;
|
||||
import org.eclipse.jetty.security.ConstraintMapping;
|
||||
import org.eclipse.jetty.security.ConstraintSecurityHandler;
|
||||
|
@ -51,6 +49,8 @@ import org.eclipse.jetty.server.ssl.SslSocketConnector;
|
|||
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.security.Constraint;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
|
|
@ -6,7 +6,6 @@ import java.security.KeyStore;
|
|||
import java.security.cert.CRL;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.eclipse.jetty.http.ssl.SslContextFactory;
|
||||
import org.eclipse.jetty.server.Handler;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.HandlerCollection;
|
||||
|
@ -16,6 +15,7 @@ import org.eclipse.jetty.servlet.ServletContextHandler;
|
|||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||
import org.eclipse.jetty.util.security.CertificateUtils;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
|
||||
public abstract class SslValidationTestBase extends ContentExchangeTest
|
||||
{
|
||||
|
|
|
@ -16,27 +16,25 @@ package org.eclipse.jetty.client;
|
|||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
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;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.http.HttpMethods;
|
||||
import org.eclipse.jetty.io.EofException;
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||
import org.eclipse.jetty.server.nio.SelectChannelConnector;
|
||||
import org.eclipse.jetty.util.IO;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Functional testing for HttpExchange.
|
||||
|
@ -44,91 +42,71 @@ import org.eclipse.jetty.util.IO;
|
|||
* @author Matthew Purland
|
||||
* @author Greg Wilkins
|
||||
*/
|
||||
public class UnexpectedDataTest extends TestCase
|
||||
public class UnexpectedDataTest
|
||||
{
|
||||
protected int _maxConnectionsPerAddress = 1;
|
||||
protected String _scheme = "http://";
|
||||
protected Server _server;
|
||||
protected int _port;
|
||||
protected HttpClient _httpClient;
|
||||
protected Connector _connector;
|
||||
protected AtomicInteger _count = new AtomicInteger();
|
||||
private Server _server;
|
||||
private int _port;
|
||||
private HttpClient _httpClient;
|
||||
private Connector _connector;
|
||||
private AtomicInteger _count = new AtomicInteger();
|
||||
|
||||
protected void setUp() throws Exception
|
||||
@Before
|
||||
public void setUp() throws Exception
|
||||
{
|
||||
startServer();
|
||||
_httpClient=new HttpClient();
|
||||
_httpClient = new HttpClient();
|
||||
_httpClient.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL);
|
||||
_httpClient.setMaxConnectionsPerAddress(_maxConnectionsPerAddress);
|
||||
_httpClient.setMaxConnectionsPerAddress(1);
|
||||
_httpClient.start();
|
||||
}
|
||||
|
||||
protected void tearDown() throws Exception
|
||||
@After
|
||||
public void tearDown() throws Exception
|
||||
{
|
||||
_httpClient.stop();
|
||||
Thread.sleep(500);
|
||||
stopServer();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnexpectedData() throws Exception
|
||||
{
|
||||
for (int i=0; i<4; i++)
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
final CountDownLatch done=new CountDownLatch(1);
|
||||
ContentExchange httpExchange=new ContentExchange()
|
||||
final CountDownLatch done = new CountDownLatch(1);
|
||||
ContentExchange httpExchange = new ContentExchange()
|
||||
{
|
||||
protected void onResponseComplete() throws IOException
|
||||
{
|
||||
super.onResponseComplete();
|
||||
|
||||
done.countDown();
|
||||
}
|
||||
};
|
||||
httpExchange.setURL(_scheme+"localhost:"+_port+"/?i="+i);
|
||||
httpExchange.setURL("http://localhost:" + _port + "/?i=" + i);
|
||||
httpExchange.setMethod(HttpMethods.GET);
|
||||
_httpClient.send(httpExchange);
|
||||
|
||||
done.await(1,TimeUnit.SECONDS);
|
||||
|
||||
int status = httpExchange.getStatus();
|
||||
String result=httpExchange.getResponseContent();
|
||||
assertEquals("i="+i,0,result.indexOf("<hello>"));
|
||||
assertEquals("i="+i,result.length()-10,result.indexOf("</hello>"));
|
||||
assertEquals(HttpExchange.STATUS_COMPLETED, status);
|
||||
|
||||
Thread.sleep(5);
|
||||
}
|
||||
}
|
||||
|
||||
public static void copyStream(InputStream in, OutputStream out)
|
||||
{
|
||||
try
|
||||
{
|
||||
byte[] buffer=new byte[1024];
|
||||
int len;
|
||||
while ((len=in.read(buffer))>=0)
|
||||
{
|
||||
out.write(buffer,0,len);
|
||||
}
|
||||
}
|
||||
catch (EofException e)
|
||||
{
|
||||
System.err.println(e);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
Assert.assertTrue(done.await(1000, TimeUnit.SECONDS));
|
||||
|
||||
int status = httpExchange.getStatus();
|
||||
String result = httpExchange.getResponseContent();
|
||||
Assert.assertEquals("i=" + i, 0, result.indexOf("<hello>"));
|
||||
Assert.assertEquals("i=" + i, result.length() - 10, result.indexOf("</hello>"));
|
||||
Assert.assertEquals(HttpExchange.STATUS_COMPLETED, status);
|
||||
|
||||
// Give the client the time to read -1 from server before issuing the next request
|
||||
// There is currently no simple way to be notified of connection closed.
|
||||
Thread.sleep(500);
|
||||
}
|
||||
}
|
||||
|
||||
protected void newServer() throws Exception
|
||||
{
|
||||
_server=new Server();
|
||||
_server = new Server();
|
||||
_server.setGracefulShutdown(500);
|
||||
_connector=new SelectChannelConnector();
|
||||
|
||||
_connector = new SelectChannelConnector();
|
||||
_connector.setPort(0);
|
||||
_server.setConnectors(new Connector[] { _connector });
|
||||
_server.setConnectors(new Connector[]{_connector});
|
||||
}
|
||||
|
||||
protected void startServer() throws Exception
|
||||
|
@ -137,28 +115,28 @@ public class UnexpectedDataTest extends TestCase
|
|||
_server.setHandler(new AbstractHandler()
|
||||
{
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)
|
||||
throws IOException, ServletException
|
||||
throws IOException, ServletException
|
||||
{
|
||||
int i=0;
|
||||
int i = 0;
|
||||
try
|
||||
{
|
||||
baseRequest.setHandled(true);
|
||||
response.setStatus(200);
|
||||
_count.incrementAndGet();
|
||||
|
||||
|
||||
if (request.getMethod().equalsIgnoreCase("GET"))
|
||||
{
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
buffer.append("<hello>\r\n");
|
||||
for (; i<100; i++)
|
||||
for (; i < 100; i++)
|
||||
{
|
||||
buffer.append(" <world>"+i+"</world>\r\n");
|
||||
buffer.append(" <world>").append(i).append("</world>\r\n");
|
||||
}
|
||||
buffer.append("</hello>\r\n");
|
||||
|
||||
|
||||
byte[] buff = buffer.toString().getBytes();
|
||||
response.setContentLength(buff.length);
|
||||
|
||||
|
||||
buffer.append("extra data");
|
||||
buff = buffer.toString().getBytes();
|
||||
|
||||
|
@ -169,35 +147,30 @@ public class UnexpectedDataTest extends TestCase
|
|||
else
|
||||
{
|
||||
response.setContentType(request.getContentType());
|
||||
int size=request.getContentLength();
|
||||
ByteArrayOutputStream bout = new ByteArrayOutputStream(size>0?size:32768);
|
||||
IO.copy(request.getInputStream(),bout);
|
||||
int size = request.getContentLength();
|
||||
ByteArrayOutputStream bout = new ByteArrayOutputStream(size > 0 ? size : 32768);
|
||||
IO.copy(request.getInputStream(), bout);
|
||||
response.getOutputStream().write(bout.toByteArray());
|
||||
}
|
||||
}
|
||||
catch(IOException e)
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
throw e;
|
||||
}
|
||||
catch(Throwable e)
|
||||
catch (Throwable e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
throw new ServletException(e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
// System.err.println("HANDLED "+i);
|
||||
}
|
||||
}
|
||||
});
|
||||
_server.start();
|
||||
_port=_connector.getLocalPort();
|
||||
_port = _connector.getLocalPort();
|
||||
}
|
||||
|
||||
private void stopServer() throws Exception
|
||||
{
|
||||
_server.stop();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -162,8 +162,6 @@ public class WebSocketUpgradeTest
|
|||
int status = httpExchange.waitForDone();
|
||||
assertEquals(HttpExchange.STATUS_COMPLETED, status);
|
||||
|
||||
// System.err.println("results="+_results);
|
||||
|
||||
assertEquals("serverWS.onConnect", _results.poll(1,TimeUnit.SECONDS));
|
||||
TestWebSocket serverWS = (TestWebSocket)_results.poll(1,TimeUnit.SECONDS);
|
||||
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
|
||||
package org.eclipse.jetty.client.helperClasses;
|
||||
|
||||
import org.eclipse.jetty.http.ssl.SslContextFactory;
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.ssl.SslSelectChannelConnector;
|
||||
|
@ -22,6 +21,7 @@ import org.eclipse.jetty.server.ssl.SslSocketConnector;
|
|||
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;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -35,7 +35,7 @@ public abstract class AbstractSslServerAndClientCreator implements ServerAndClie
|
|||
public Server createServer() throws Exception
|
||||
{
|
||||
Server server = new Server();
|
||||
//SslSelectChannelConnector connector = new SslSelectChannelConnector();
|
||||
// SslSelectChannelConnector connector = new SslSelectChannelConnector();
|
||||
SslSocketConnector connector = new SslSocketConnector();
|
||||
|
||||
String keystore = MavenTestingUtils.getTestResourceFile("keystore").getAbsolutePath();
|
||||
|
@ -45,7 +45,6 @@ public abstract class AbstractSslServerAndClientCreator implements ServerAndClie
|
|||
cf.setKeyStorePath(keystore);
|
||||
cf.setKeyStorePassword("storepwd");
|
||||
cf.setKeyManagerPassword("keypwd");
|
||||
connector.setAllowRenegotiate(true);
|
||||
|
||||
server.setConnectors(new Connector[]{ connector });
|
||||
server.setHandler(new GenericServerHandler());
|
||||
|
|
|
@ -16,9 +16,9 @@ public class AsyncSslServerAndClientCreator extends AbstractSslServerAndClientCr
|
|||
httpClient.setMaxConnectionsPerAddress(2);
|
||||
|
||||
String keystore = MavenTestingUtils.getTestResourceFile("keystore").getAbsolutePath();
|
||||
httpClient.setKeyStoreInputStream(new FileInputStream(keystore));
|
||||
httpClient.setKeyStorePassword("storepwd");
|
||||
httpClient.setKeyManagerPassword("keypwd");
|
||||
httpClient.getSslContextFactory().setKeyStorePath(keystore);
|
||||
httpClient.getSslContextFactory().setKeyStorePassword("storepwd");
|
||||
httpClient.getSslContextFactory().setKeyManagerPassword("keypwd");
|
||||
httpClient.start();
|
||||
return httpClient;
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import javax.servlet.http.HttpServletRequest;
|
|||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.http.HttpHeaders;
|
||||
import org.eclipse.jetty.io.EofException;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||
import org.eclipse.jetty.util.IO;
|
||||
|
@ -70,6 +71,12 @@ public class GenericServerHandler extends AbstractHandler
|
|||
{
|
||||
LOG.debug(e);
|
||||
}
|
||||
catch (EofException e)
|
||||
{
|
||||
LOG.info(e.toString());
|
||||
LOG.debug(e);
|
||||
throw e;
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
LOG.warn(e);
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>8.0.5-SNAPSHOT</version>
|
||||
<version>8.1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-continuation</artifactId>
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package org.eclipse.jetty.continuation;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.FilterConfig;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>8.0.5-SNAPSHOT</version>
|
||||
<version>8.1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-deploy</artifactId>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>8.0.5-SNAPSHOT</version>
|
||||
<version>8.1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>jetty-distribution</artifactId>
|
||||
<name>Jetty :: Distribution Assemblies</name>
|
||||
|
@ -206,24 +206,11 @@
|
|||
</goals>
|
||||
<configuration>
|
||||
<includeGroupIds>org.eclipse.jetty</includeGroupIds>
|
||||
<excludeArtifactIds>jetty-start,jetty-monitor,jetty-jsp-2.1</excludeArtifactIds>
|
||||
<excludeArtifactIds>jetty-start,jetty-monitor</excludeArtifactIds>
|
||||
<includeTypes>jar</includeTypes>
|
||||
<outputDirectory>${assembly-directory}/lib</outputDirectory>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>copy-lib-jsp-deps</id>
|
||||
<phase>generate-resources</phase>
|
||||
<goals>
|
||||
<goal>copy-dependencies</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<includeGroupIds>org.eclipse.jetty,org.glassfish.web</includeGroupIds>
|
||||
<includeArtifactIds>jetty-jsp-2.1,jsp-impl</includeArtifactIds>
|
||||
<includeTypes>jar</includeTypes>
|
||||
<outputDirectory>${assembly-directory}/lib/jsp</outputDirectory>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>copy-lib-monitor-deps</id>
|
||||
<phase>generate-resources</phase>
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
# Below are some recommended options for Sun's JRE
|
||||
#-----------------------------------------------------------
|
||||
# --exec
|
||||
# -Dorg.apache.jasper.compiler.disablejsr199=true
|
||||
# -Dcom.sun.management.jmxremote
|
||||
# -Dorg.eclipse.jetty.util.log.IGNORED=true
|
||||
# -Dorg.eclipse.jetty.util.log.stderr.DEBUG=true
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>8.0.5-SNAPSHOT</version>
|
||||
<version>8.1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-http-spi</artifactId>
|
||||
|
|
|
@ -17,7 +17,6 @@ import com.sun.net.httpserver.Authenticator.Result;
|
|||
import com.sun.net.httpserver.HttpContext;
|
||||
import com.sun.net.httpserver.HttpHandler;
|
||||
import com.sun.net.httpserver.HttpPrincipal;
|
||||
import org.eclipse.jetty.server.HttpConnection;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
|
||||
|
@ -80,8 +79,7 @@ public class HttpSpiContextHandler extends ContextHandler
|
|||
}
|
||||
finally
|
||||
{
|
||||
Request base_request = (req instanceof Request) ? (Request)req:HttpConnection.getCurrentConnection().getRequest();
|
||||
base_request.setHandled(true);
|
||||
baseRequest.setHandled(true);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<version>8.0.5-SNAPSHOT</version>
|
||||
<version>8.1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
|
|
|
@ -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.http;
|
||||
|
@ -27,11 +27,11 @@ import org.eclipse.jetty.util.log.Logger;
|
|||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Abstract Generator. Builds HTTP Messages.
|
||||
*
|
||||
*
|
||||
* Currently this class uses a system parameter "jetty.direct.writers" to control
|
||||
* two optional writer to byte conversions. buffer.writers=true will probably be
|
||||
* two optional writer to byte conversions. buffer.writers=true will probably be
|
||||
* faster, but will consume more memory. This option is just for testing and tuning.
|
||||
*
|
||||
*
|
||||
*/
|
||||
public abstract class AbstractGenerator implements Generator
|
||||
{
|
||||
|
@ -42,16 +42,16 @@ public abstract class AbstractGenerator implements Generator
|
|||
public final static int STATE_CONTENT = 2;
|
||||
public final static int STATE_FLUSHING = 3;
|
||||
public final static int STATE_END = 4;
|
||||
|
||||
|
||||
public static final byte[] NO_BYTES = {};
|
||||
|
||||
// data
|
||||
|
||||
protected final Buffers _buffers; // source of buffers
|
||||
protected final EndPoint _endp;
|
||||
|
||||
|
||||
protected int _state = STATE_HEADER;
|
||||
|
||||
|
||||
protected int _status = 0;
|
||||
protected int _version = HttpVersions.HTTP_1_1_ORDINAL;
|
||||
protected Buffer _reason;
|
||||
|
@ -64,20 +64,20 @@ public abstract class AbstractGenerator implements Generator
|
|||
protected boolean _head = false;
|
||||
protected boolean _noContent = false;
|
||||
protected Boolean _persistent = null;
|
||||
|
||||
|
||||
protected Buffer _header; // Buffer for HTTP header (and maybe small _content)
|
||||
protected Buffer _buffer; // Buffer for copy of passed _content
|
||||
protected Buffer _content; // Buffer passed to addContent
|
||||
|
||||
|
||||
protected Buffer _date;
|
||||
|
||||
|
||||
private boolean _sendServerVersion;
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------- */
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
*
|
||||
* @param buffers buffer pool
|
||||
* @param io the end point
|
||||
*/
|
||||
|
@ -89,18 +89,18 @@ public abstract class AbstractGenerator implements Generator
|
|||
|
||||
/* ------------------------------------------------------------------------------- */
|
||||
public abstract boolean isRequest();
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------- */
|
||||
public abstract boolean isResponse();
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------- */
|
||||
public boolean isOpen()
|
||||
{
|
||||
return _endp.isOpen();
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------- */
|
||||
public void reset(boolean returnBuffers)
|
||||
public void reset()
|
||||
{
|
||||
_state = STATE_HEADER;
|
||||
_status = 0;
|
||||
|
@ -114,27 +114,13 @@ public abstract class AbstractGenerator implements Generator
|
|||
_contentLength = HttpTokens.UNKNOWN_CONTENT;
|
||||
_date = null;
|
||||
|
||||
// always return the body buffer
|
||||
if (_buffer!=null)
|
||||
_buffers.returnBuffer(_buffer);
|
||||
_buffer=null;
|
||||
|
||||
if (returnBuffers)
|
||||
{
|
||||
if (_header!=null)
|
||||
_buffers.returnBuffer(_header);
|
||||
_header=null;
|
||||
}
|
||||
else if (_header != null)
|
||||
_header.clear();
|
||||
|
||||
_content = null;
|
||||
_method=null;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------------- */
|
||||
public void returnBuffers()
|
||||
{
|
||||
{
|
||||
if (_buffer!=null && _buffer.length()==0)
|
||||
{
|
||||
_buffers.returnBuffer(_buffer);
|
||||
|
@ -145,22 +131,22 @@ public abstract class AbstractGenerator implements Generator
|
|||
{
|
||||
_buffers.returnBuffer(_header);
|
||||
_header=null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------- */
|
||||
public void resetBuffer()
|
||||
{
|
||||
{
|
||||
if(_state>=STATE_FLUSHING)
|
||||
throw new IllegalStateException("Flushed");
|
||||
|
||||
|
||||
_last = false;
|
||||
_persistent=null;
|
||||
_contentWritten = 0;
|
||||
_contentLength = HttpTokens.UNKNOWN_CONTENT;
|
||||
_content=null;
|
||||
if (_buffer!=null)
|
||||
_buffer.clear();
|
||||
_buffer.clear();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -190,25 +176,25 @@ public abstract class AbstractGenerator implements Generator
|
|||
_buffer = nb;
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public Buffer getUncheckedBuffer()
|
||||
{
|
||||
return _buffer;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public boolean getSendServerVersion ()
|
||||
{
|
||||
return _sendServerVersion;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void setSendServerVersion (boolean sendServerVersion)
|
||||
{
|
||||
_sendServerVersion = sendServerVersion;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public int getState()
|
||||
{
|
||||
|
@ -256,7 +242,7 @@ public abstract class AbstractGenerator implements Generator
|
|||
else
|
||||
_contentLength=value;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param head The head to set.
|
||||
|
@ -277,7 +263,7 @@ public abstract class AbstractGenerator implements Generator
|
|||
?_persistent.booleanValue()
|
||||
:(isRequest()?true:_version>HttpVersions.HTTP_1_0_ORDINAL);
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void setPersistent(boolean persistent)
|
||||
{
|
||||
|
@ -291,7 +277,7 @@ public abstract class AbstractGenerator implements Generator
|
|||
*/
|
||||
public void setVersion(int version)
|
||||
{
|
||||
if (_state != STATE_HEADER)
|
||||
if (_state != STATE_HEADER)
|
||||
throw new IllegalStateException("STATE!=START "+_state);
|
||||
_version = version;
|
||||
if (_version==HttpVersions.HTTP_0_9_ORDINAL && _method!=null)
|
||||
|
@ -303,7 +289,7 @@ public abstract class AbstractGenerator implements Generator
|
|||
{
|
||||
return _version;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.http.Generator#setDate(org.eclipse.jetty.io.Buffer)
|
||||
|
@ -340,7 +326,7 @@ public abstract class AbstractGenerator implements Generator
|
|||
if (reason!=null)
|
||||
{
|
||||
int len=reason.length();
|
||||
|
||||
|
||||
// TODO don't hard code
|
||||
if (len>1024)
|
||||
len=1024;
|
||||
|
@ -378,14 +364,14 @@ public abstract class AbstractGenerator implements Generator
|
|||
if(_buffer!=null)
|
||||
_buffer.clear();
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
_contentWritten+=_buffer.length();
|
||||
if (_head)
|
||||
_buffer.clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public boolean isBufferFull()
|
||||
{
|
||||
|
@ -404,20 +390,20 @@ public abstract class AbstractGenerator implements Generator
|
|||
{
|
||||
return _contentWritten>0;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public boolean isAllContentWritten()
|
||||
{
|
||||
return _contentLength>=0 && _contentWritten>=_contentLength;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public abstract void completeHeader(HttpFields fields, boolean allContentAdded) throws IOException;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Complete the message.
|
||||
*
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
public void complete() throws IOException
|
||||
|
@ -436,9 +422,9 @@ public abstract class AbstractGenerator implements Generator
|
|||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public abstract long flushBuffer() throws IOException;
|
||||
public abstract int flushBuffer() throws IOException;
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void flush(long maxIdleTime) throws IOException
|
||||
{
|
||||
|
@ -450,29 +436,20 @@ public abstract class AbstractGenerator implements Generator
|
|||
if (content!=null && content.length()>0 || buffer!=null && buffer.length()>0 || isBufferFull())
|
||||
{
|
||||
flushBuffer();
|
||||
|
||||
|
||||
while (now<end && (content!=null && content.length()>0 ||buffer!=null && buffer.length()>0) && _endp.isOpen()&& !_endp.isOutputShutdown())
|
||||
{
|
||||
blockForOutput(end-now);
|
||||
now=System.currentTimeMillis();
|
||||
}
|
||||
}
|
||||
|
||||
// make sure buffered data is also flushed
|
||||
while (now<end && _endp.isBufferingOutput() && _endp.isOpen() && !_endp.isOutputShutdown())
|
||||
{
|
||||
if (!_endp.isBlocking())
|
||||
_endp.blockWritable(end-now);
|
||||
_endp.flush();
|
||||
now=System.currentTimeMillis();
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Utility method to send an error response. If the builder is not committed, this call is
|
||||
* equivalent to a setResponse, addContent and complete call.
|
||||
*
|
||||
*
|
||||
* @param code The error code
|
||||
* @param reason The error reason
|
||||
* @param content Contents of the error page
|
||||
|
@ -491,7 +468,7 @@ public abstract class AbstractGenerator implements Generator
|
|||
{
|
||||
LOG.debug("sendError: {} {}",code,reason);
|
||||
setResponse(code, reason);
|
||||
if (content != null)
|
||||
if (content != null)
|
||||
{
|
||||
completeHeader(null, false);
|
||||
addContent(new View(new ByteArrayBuffer(content)), Generator.LAST);
|
||||
|
@ -512,7 +489,7 @@ public abstract class AbstractGenerator implements Generator
|
|||
{
|
||||
return _contentWritten;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -537,9 +514,9 @@ public abstract class AbstractGenerator implements Generator
|
|||
_endp.close();
|
||||
throw new EofException("timeout");
|
||||
}
|
||||
|
||||
|
||||
flushBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -50,7 +50,7 @@ public interface Generator
|
|||
|
||||
void completeHeader(HttpFields responseFields, boolean last) throws IOException;
|
||||
|
||||
long flushBuffer() throws IOException;
|
||||
int flushBuffer() throws IOException;
|
||||
|
||||
int getContentBufferSize();
|
||||
|
||||
|
@ -70,7 +70,7 @@ public interface Generator
|
|||
|
||||
boolean isPersistent();
|
||||
|
||||
void reset(boolean returnBuffers);
|
||||
void reset();
|
||||
|
||||
void resetBuffer();
|
||||
|
||||
|
|
|
@ -40,7 +40,6 @@ import org.eclipse.jetty.io.BufferCache.CachedBuffer;
|
|||
import org.eclipse.jetty.io.BufferDateCache;
|
||||
import org.eclipse.jetty.io.BufferUtil;
|
||||
import org.eclipse.jetty.io.ByteArrayBuffer;
|
||||
import org.eclipse.jetty.io.View;
|
||||
import org.eclipse.jetty.util.LazyList;
|
||||
import org.eclipse.jetty.util.QuotedStringTokenizer;
|
||||
import org.eclipse.jetty.util.StringMap;
|
||||
|
|
|
@ -125,9 +125,26 @@ public class HttpGenerator extends AbstractGenerator
|
|||
|
||||
/* ------------------------------------------------------------------------------- */
|
||||
@Override
|
||||
public void reset(boolean returnBuffers)
|
||||
public void reset()
|
||||
{
|
||||
super.reset(returnBuffers);
|
||||
if (_persistent!=null && !_persistent && _endp!=null && !_endp.isOutputShutdown())
|
||||
{
|
||||
try
|
||||
{
|
||||
_endp.shutdownOutput();
|
||||
}
|
||||
catch(IOException e)
|
||||
{
|
||||
LOG.ignore(e);
|
||||
}
|
||||
}
|
||||
super.reset();
|
||||
if (_buffer!=null)
|
||||
_buffer.clear();
|
||||
if (_header!=null)
|
||||
_header.clear();
|
||||
if (_content!=null)
|
||||
_content=null;
|
||||
_bypass = false;
|
||||
_needCRLF = false;
|
||||
_needEOC = false;
|
||||
|
@ -137,8 +154,6 @@ public class HttpGenerator extends AbstractGenerator
|
|||
_noContent=false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Add content.
|
||||
|
@ -157,17 +172,16 @@ public class HttpGenerator extends AbstractGenerator
|
|||
|
||||
if (_last || _state==STATE_END)
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Ignoring extra content {}",content.toDetailString());
|
||||
LOG.warn("Ignoring extra content {}",content);
|
||||
content.clear();
|
||||
return;
|
||||
}
|
||||
_last = last;
|
||||
|
||||
|
||||
// Handle any unfinished business?
|
||||
if (_content!=null && _content.length()>0 || _bufferChunked)
|
||||
{
|
||||
if (!_endp.isOpen())
|
||||
if (_endp.isOutputShutdown())
|
||||
throw new EofException();
|
||||
flushBuffer();
|
||||
if (_content != null && _content.length()>0)
|
||||
|
@ -243,8 +257,7 @@ public class HttpGenerator extends AbstractGenerator
|
|||
|
||||
if (_last || _state==STATE_END)
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Ignoring extra content {}",Byte.valueOf(b));
|
||||
LOG.warn("Ignoring extra content {}",Byte.valueOf(b));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -401,7 +414,7 @@ public class HttpGenerator extends AbstractGenerator
|
|||
_contentLength = HttpTokens.NO_CONTENT;
|
||||
_header.put(_method);
|
||||
_header.put((byte)' ');
|
||||
_header.put(_uri.getBytes("utf-8")); // TODO WRONG!
|
||||
_header.put(_uri.getBytes("UTF-8")); // TODO check
|
||||
_header.put(HttpTokens.CRLF);
|
||||
_state = STATE_FLUSHING;
|
||||
_noContent=true;
|
||||
|
@ -411,7 +424,7 @@ public class HttpGenerator extends AbstractGenerator
|
|||
{
|
||||
_header.put(_method);
|
||||
_header.put((byte)' ');
|
||||
_header.put(_uri.getBytes("utf-8")); // TODO WRONG!
|
||||
_header.put(_uri.getBytes("UTF-8")); // TODO check
|
||||
_header.put((byte)' ');
|
||||
_header.put(_version==HttpVersions.HTTP_1_0_ORDINAL?HttpVersions.HTTP_1_0_BUFFER:HttpVersions.HTTP_1_1_BUFFER);
|
||||
_header.put(HttpTokens.CRLF);
|
||||
|
@ -420,7 +433,6 @@ public class HttpGenerator extends AbstractGenerator
|
|||
else
|
||||
{
|
||||
// Responses
|
||||
|
||||
if (_version == HttpVersions.HTTP_0_9_ORDINAL)
|
||||
{
|
||||
_persistent = false;
|
||||
|
@ -679,7 +691,7 @@ public class HttpGenerator extends AbstractGenerator
|
|||
{
|
||||
// we have seen all the _content there is
|
||||
_contentLength = _contentWritten;
|
||||
if (content_length == null && (isResponse() || _contentLength>0 || content_type ))
|
||||
if (content_length == null && (isResponse() || _contentLength>0 || content_type ) && !_noContent)
|
||||
{
|
||||
// known length but not actually set.
|
||||
_header.put(HttpHeaders.CONTENT_LENGTH_BUFFER);
|
||||
|
@ -778,7 +790,6 @@ public class HttpGenerator extends AbstractGenerator
|
|||
|
||||
// end the header.
|
||||
_header.put(HttpTokens.CRLF);
|
||||
|
||||
_state = STATE_CONTENT;
|
||||
|
||||
}
|
||||
|
@ -788,8 +799,6 @@ public class HttpGenerator extends AbstractGenerator
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Complete the message.
|
||||
|
@ -816,10 +825,11 @@ public class HttpGenerator extends AbstractGenerator
|
|||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public long flushBuffer() throws IOException
|
||||
public int flushBuffer() throws IOException
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
if (_state == STATE_HEADER)
|
||||
throw new IllegalStateException("State==HEADER");
|
||||
|
||||
|
@ -839,79 +849,87 @@ public class HttpGenerator extends AbstractGenerator
|
|||
int total= 0;
|
||||
|
||||
int len = -1;
|
||||
int to_flush = ((_header != null && _header.length() > 0)?4:0) | ((_buffer != null && _buffer.length() > 0)?2:0) | ((_bypass && _content != null && _content.length() > 0)?1:0);
|
||||
switch (to_flush)
|
||||
int to_flush = flushMask();
|
||||
int last_flush;
|
||||
|
||||
do
|
||||
{
|
||||
case 7:
|
||||
throw new IllegalStateException(); // should never happen!
|
||||
case 6:
|
||||
len = _endp.flush(_header, _buffer, null);
|
||||
break;
|
||||
case 5:
|
||||
len = _endp.flush(_header, _content, null);
|
||||
break;
|
||||
case 4:
|
||||
len = _endp.flush(_header);
|
||||
break;
|
||||
case 3:
|
||||
len = _endp.flush(_buffer, _content, null);
|
||||
break;
|
||||
case 2:
|
||||
len = _endp.flush(_buffer);
|
||||
break;
|
||||
case 1:
|
||||
len = _endp.flush(_content);
|
||||
break;
|
||||
case 0:
|
||||
last_flush=to_flush;
|
||||
switch (to_flush)
|
||||
{
|
||||
// Nothing more we can write now.
|
||||
if (_header != null)
|
||||
_header.clear();
|
||||
|
||||
_bypass = false;
|
||||
_bufferChunked = false;
|
||||
|
||||
if (_buffer != null)
|
||||
case 7:
|
||||
throw new IllegalStateException(); // should never happen!
|
||||
case 6:
|
||||
len = _endp.flush(_header, _buffer, null);
|
||||
break;
|
||||
case 5:
|
||||
len = _endp.flush(_header, _content, null);
|
||||
break;
|
||||
case 4:
|
||||
len = _endp.flush(_header);
|
||||
break;
|
||||
case 3:
|
||||
len = _endp.flush(_buffer, _content, null);
|
||||
break;
|
||||
case 2:
|
||||
len = _endp.flush(_buffer);
|
||||
break;
|
||||
case 1:
|
||||
len = _endp.flush(_content);
|
||||
break;
|
||||
case 0:
|
||||
{
|
||||
_buffer.clear();
|
||||
if (_contentLength == HttpTokens.CHUNKED_CONTENT)
|
||||
{
|
||||
// reserve some space for the chunk header
|
||||
_buffer.setPutIndex(CHUNK_SPACE);
|
||||
_buffer.setGetIndex(CHUNK_SPACE);
|
||||
len=0;
|
||||
// Nothing more we can write now.
|
||||
if (_header != null)
|
||||
_header.clear();
|
||||
|
||||
// Special case handling for small left over buffer from
|
||||
// an addContent that caused a buffer flush.
|
||||
if (_content != null && _content.length() < _buffer.space() && _state != STATE_FLUSHING)
|
||||
_bypass = false;
|
||||
_bufferChunked = false;
|
||||
|
||||
if (_buffer != null)
|
||||
{
|
||||
_buffer.clear();
|
||||
if (_contentLength == HttpTokens.CHUNKED_CONTENT)
|
||||
{
|
||||
_buffer.put(_content);
|
||||
_content.clear();
|
||||
_content=null;
|
||||
// reserve some space for the chunk header
|
||||
_buffer.setPutIndex(CHUNK_SPACE);
|
||||
_buffer.setGetIndex(CHUNK_SPACE);
|
||||
|
||||
// Special case handling for small left over buffer from
|
||||
// an addContent that caused a buffer flush.
|
||||
if (_content != null && _content.length() < _buffer.space() && _state != STATE_FLUSHING)
|
||||
{
|
||||
_buffer.put(_content);
|
||||
_content.clear();
|
||||
_content=null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Are we completely finished for now?
|
||||
if (!_needCRLF && !_needEOC && (_content==null || _content.length()==0))
|
||||
{
|
||||
if (_state == STATE_FLUSHING)
|
||||
// Are we completely finished for now?
|
||||
if (!_needCRLF && !_needEOC && (_content==null || _content.length()==0))
|
||||
{
|
||||
_state = STATE_END;
|
||||
}
|
||||
|
||||
if (_state==STATE_END && _persistent != null && !_persistent && _status!=100 && _method==null)
|
||||
{
|
||||
_endp.shutdownOutput();
|
||||
}
|
||||
}
|
||||
else
|
||||
// Try to prepare more to write.
|
||||
prepareBuffers();
|
||||
}
|
||||
}
|
||||
if (_state == STATE_FLUSHING)
|
||||
_state = STATE_END;
|
||||
|
||||
if (len > 0)
|
||||
total+=len;
|
||||
if (_state==STATE_END && _persistent != null && !_persistent && _status!=100 && _method==null)
|
||||
_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)
|
||||
while (len>0 || (to_flush!=0 && last_flush==0));
|
||||
|
||||
return total;
|
||||
}
|
||||
|
@ -921,7 +939,15 @@ public class HttpGenerator extends AbstractGenerator
|
|||
throw (e instanceof EofException) ? e:new EofException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
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()
|
||||
{
|
||||
|
@ -940,12 +966,15 @@ public class HttpGenerator extends AbstractGenerator
|
|||
// Chunk buffer if need be
|
||||
if (_contentLength == HttpTokens.CHUNKED_CONTENT)
|
||||
{
|
||||
if ((_buffer==null||_buffer.length()==0) && _content!=null)
|
||||
if (_bypass && (_buffer==null||_buffer.length()==0) && _content!=null)
|
||||
{
|
||||
// this is a bypass write
|
||||
int size = _content.length();
|
||||
_bufferChunked = true;
|
||||
|
||||
if (_header == null)
|
||||
_header = _buffers.getHeader();
|
||||
|
||||
// if we need CRLF add this to header
|
||||
if (_needCRLF)
|
||||
{
|
||||
|
@ -1072,9 +1101,10 @@ public class HttpGenerator extends AbstractGenerator
|
|||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "HttpGenerator s="+_state+
|
||||
" h="+(_header==null?"null":_header.length())+
|
||||
" b="+(_buffer==null?"null":_buffer.length())+
|
||||
" c="+(_content==null?"null":_content.length());
|
||||
return "HttpGenerator{s="+_state+
|
||||
",h="+(_header==null?"":_header.length())+
|
||||
",b="+(_buffer==null?"":_buffer.length())+
|
||||
",c="+(_content==null?"":_content.length())+
|
||||
"}";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,14 +13,9 @@
|
|||
|
||||
package org.eclipse.jetty.http;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.LineNumberReader;
|
||||
|
||||
import org.eclipse.jetty.io.Buffer;
|
||||
import org.eclipse.jetty.io.BufferCache;
|
||||
import org.eclipse.jetty.io.ByteArrayBuffer;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
|
||||
/**
|
||||
* Cached HTTP Header values.
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -26,13 +26,17 @@ public interface Parser
|
|||
boolean isComplete();
|
||||
|
||||
/**
|
||||
* @return An indication of progress, typically the number of bytes filled plus the events parsed: -1 means EOF read, 0 no progress, >0 progress
|
||||
* @return True if progress made
|
||||
* @throws IOException
|
||||
*/
|
||||
int parseAvailable() throws IOException;
|
||||
boolean parseAvailable() throws IOException;
|
||||
|
||||
boolean isMoreInBuffer() throws IOException;
|
||||
|
||||
boolean isIdle();
|
||||
|
||||
boolean isPersistent();
|
||||
|
||||
void setPersistent(boolean persistent);
|
||||
|
||||
}
|
||||
|
|
|
@ -22,7 +22,6 @@ import java.io.UnsupportedEncodingException;
|
|||
import java.util.Set;
|
||||
|
||||
import javax.servlet.ServletOutputStream;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpServletResponseWrapper;
|
||||
|
@ -121,7 +120,7 @@ public class GzipResponseWrapper extends HttpServletResponseWrapper
|
|||
public void setStatus(int sc, String sm)
|
||||
{
|
||||
super.setStatus(sc,sm);
|
||||
if (sc<200||sc>=300)
|
||||
if (sc<200 || sc==204 || sc==205 || sc>=300)
|
||||
noGzip();
|
||||
}
|
||||
|
||||
|
@ -132,7 +131,7 @@ public class GzipResponseWrapper extends HttpServletResponseWrapper
|
|||
public void setStatus(int sc)
|
||||
{
|
||||
super.setStatus(sc);
|
||||
if (sc<200||sc>=300)
|
||||
if (sc<200 || sc==204 || sc==205 ||sc>=300)
|
||||
noGzip();
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -14,10 +14,9 @@
|
|||
package org.eclipse.jetty.http;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashSet;
|
||||
|
|
|
@ -138,7 +138,7 @@ public class HttpGeneratorClientTest
|
|||
String t="v="+v+",r="+r+",chunks="+chunks+",c="+c+",tr="+tr[r];
|
||||
// System.err.println(t);
|
||||
|
||||
hb.reset(true);
|
||||
hb.reset();
|
||||
endp.reset();
|
||||
fields.clear();
|
||||
|
||||
|
@ -193,7 +193,7 @@ public class HttpGeneratorClientTest
|
|||
}
|
||||
|
||||
private static final String[] headers= { "Content-Type","Content-Length","Connection","Transfer-Encoding","Other"};
|
||||
private class TR
|
||||
private static class TR
|
||||
{
|
||||
private String[] values=new String[headers.length];
|
||||
private String body;
|
||||
|
|
|
@ -86,7 +86,7 @@ public class HttpGeneratorTest
|
|||
String t="v="+v+",r="+r+",chunks="+chunks+",connect="+c+",tr="+tr[r];
|
||||
// System.err.println(t);
|
||||
|
||||
hb.reset(true);
|
||||
hb.reset();
|
||||
endp.reset();
|
||||
fields.clear();
|
||||
|
||||
|
@ -138,7 +138,7 @@ public class HttpGeneratorTest
|
|||
}
|
||||
|
||||
private static final String[] headers= { "Content-Type","Content-Length","Connection","Transfer-Encoding","Other"};
|
||||
private class TR
|
||||
private static class TR
|
||||
{
|
||||
private int _code;
|
||||
private String _body;
|
||||
|
|
|
@ -210,6 +210,7 @@ public class HttpParserTest
|
|||
StringEndPoint io=new StringEndPoint();
|
||||
io.setInput(
|
||||
"GET /mp HTTP/1.0\015\012"
|
||||
+ "Connection: Keep-Alive\015\012"
|
||||
+ "Header1: value1\015\012"
|
||||
+ "Transfer-Encoding: chunked\015\012"
|
||||
+ "\015\012"
|
||||
|
@ -219,10 +220,12 @@ public class HttpParserTest
|
|||
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ\015\012"
|
||||
+ "0\015\012"
|
||||
+ "POST /foo HTTP/1.0\015\012"
|
||||
+ "Connection: Keep-Alive\015\012"
|
||||
+ "Header2: value2\015\012"
|
||||
+ "Content-Length: 0\015\012"
|
||||
+ "\015\012"
|
||||
+ "PUT /doodle HTTP/1.0\015\012"
|
||||
+ "Connection: close\015\012"
|
||||
+ "Header3: value3\015\012"
|
||||
+ "Content-Length: 10\015\012"
|
||||
+ "\015\012"
|
||||
|
@ -238,27 +241,27 @@ public class HttpParserTest
|
|||
assertEquals("GET", f0);
|
||||
assertEquals("/mp", f1);
|
||||
assertEquals("HTTP/1.0", f2);
|
||||
assertEquals(1, h);
|
||||
assertEquals("Header1", hdr[0]);
|
||||
assertEquals("value1", val[0]);
|
||||
assertEquals(2, h);
|
||||
assertEquals("Header1", hdr[1]);
|
||||
assertEquals("value1", val[1]);
|
||||
assertEquals("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ", _content);
|
||||
|
||||
parser.parse();
|
||||
assertEquals("POST", f0);
|
||||
assertEquals("/foo", f1);
|
||||
assertEquals("HTTP/1.0", f2);
|
||||
assertEquals(1, h);
|
||||
assertEquals("Header2", hdr[0]);
|
||||
assertEquals("value2", val[0]);
|
||||
assertEquals(2, h);
|
||||
assertEquals("Header2", hdr[1]);
|
||||
assertEquals("value2", val[1]);
|
||||
assertEquals(null, _content);
|
||||
|
||||
parser.parse();
|
||||
assertEquals("PUT", f0);
|
||||
assertEquals("/doodle", f1);
|
||||
assertEquals("HTTP/1.0", f2);
|
||||
assertEquals(1, h);
|
||||
assertEquals("Header3", hdr[0]);
|
||||
assertEquals("value3", val[0]);
|
||||
assertEquals(2, h);
|
||||
assertEquals("Header3", hdr[1]);
|
||||
assertEquals("value3", val[1]);
|
||||
assertEquals("0123456789", _content);
|
||||
}
|
||||
|
||||
|
@ -266,7 +269,8 @@ public class HttpParserTest
|
|||
public void testStreamParse() throws Exception
|
||||
{
|
||||
StringEndPoint io=new StringEndPoint();
|
||||
String http="GET / HTTP/1.0\015\012"
|
||||
String http="GET / HTTP/1.1\015\012"
|
||||
+ "Host: test\015\012"
|
||||
+ "Header1: value1\015\012"
|
||||
+ "Transfer-Encoding: chunked\015\012"
|
||||
+ "\015\012"
|
||||
|
@ -275,11 +279,14 @@ public class HttpParserTest
|
|||
+ "1a\015\012"
|
||||
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ\015\012"
|
||||
+ "0\015\012"
|
||||
+ "POST /foo HTTP/1.0\015\012"
|
||||
+ "POST /foo HTTP/1.1\015\012"
|
||||
+ "Host: test\015\012"
|
||||
+ "Header2: value2\015\012"
|
||||
+ "Content-Length: 0\015\012"
|
||||
+ "\015\012"
|
||||
+ "PUT /doodle HTTP/1.0\015\012"
|
||||
+ "PUT /doodle HTTP/1.1\015\012"
|
||||
+ "Host: test\015\012"
|
||||
+ "Connection: close\015\012"
|
||||
+ "Header3: value3\015\012"
|
||||
+ "Content-Length: 10\015\012"
|
||||
+ "\015\012"
|
||||
|
@ -296,15 +303,17 @@ public class HttpParserTest
|
|||
http.length() - 2,
|
||||
http.length() / 2,
|
||||
http.length() / 3,
|
||||
64,
|
||||
128,
|
||||
32
|
||||
};
|
||||
|
||||
for (int t= 0; t < tests.length; t++)
|
||||
{
|
||||
String tst="t"+tests[t];
|
||||
String tst="t"+t+"="+tests[t];
|
||||
try
|
||||
{
|
||||
{
|
||||
f0=f1=f2=null;
|
||||
h=0;
|
||||
ByteArrayBuffer buffer= new ByteArrayBuffer(tests[t]);
|
||||
ByteArrayBuffer content=new ByteArrayBuffer(8192);
|
||||
SimpleBuffers buffers=new SimpleBuffers(buffer,content);
|
||||
|
@ -314,31 +323,32 @@ public class HttpParserTest
|
|||
|
||||
io.setInput(http);
|
||||
|
||||
// System.err.println(tst);
|
||||
parser.parse();
|
||||
assertEquals(tst,"GET", f0);
|
||||
assertEquals(tst,"/", f1);
|
||||
assertEquals(tst,"HTTP/1.0", f2);
|
||||
assertEquals(tst,1, h);
|
||||
assertEquals(tst,"Header1", hdr[0]);
|
||||
assertEquals(tst,"value1", val[0]);
|
||||
assertEquals(tst,"HTTP/1.1", f2);
|
||||
assertEquals(tst,2, h);
|
||||
assertEquals(tst,"Header1", hdr[1]);
|
||||
assertEquals(tst,"value1", val[1]);
|
||||
assertEquals(tst,"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ", _content);
|
||||
|
||||
parser.parse();
|
||||
assertEquals(tst,"POST", f0);
|
||||
assertEquals(tst,"/foo", f1);
|
||||
assertEquals(tst,"HTTP/1.0", f2);
|
||||
assertEquals(tst,1, h);
|
||||
assertEquals(tst,"Header2", hdr[0]);
|
||||
assertEquals(tst,"value2", val[0]);
|
||||
assertEquals(tst,"HTTP/1.1", f2);
|
||||
assertEquals(tst,2, h);
|
||||
assertEquals(tst,"Header2", hdr[1]);
|
||||
assertEquals(tst,"value2", val[1]);
|
||||
assertEquals(tst,null, _content);
|
||||
|
||||
parser.parse();
|
||||
assertEquals(tst,"PUT", f0);
|
||||
assertEquals(tst,"/doodle", f1);
|
||||
assertEquals(tst,"HTTP/1.0", f2);
|
||||
assertEquals(tst,1, h);
|
||||
assertEquals(tst,"Header3", hdr[0]);
|
||||
assertEquals(tst,"value3", val[0]);
|
||||
assertEquals(tst,"HTTP/1.1", f2);
|
||||
assertEquals(tst,3, h);
|
||||
assertEquals(tst,"Header3", hdr[2]);
|
||||
assertEquals(tst,"value3", val[2]);
|
||||
assertEquals(tst,"0123456789", _content);
|
||||
}
|
||||
catch(Exception e)
|
||||
|
@ -401,7 +411,7 @@ public class HttpParserTest
|
|||
StringEndPoint io=new StringEndPoint();
|
||||
io.setInput(
|
||||
"HTTP/1.1 204 No-Content\015\012"
|
||||
+ "Connection: close\015\012"
|
||||
+ "Header: value\015\012"
|
||||
+ "\015\012"
|
||||
+ "HTTP/1.1 200 Correct\015\012"
|
||||
+ "Content-Length: 10\015\012"
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<version>8.0.5-SNAPSHOT</version>
|
||||
<version>8.1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
|
|
|
@ -11,17 +11,17 @@ 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=endp;
|
||||
_endp=(EndPoint)endp;
|
||||
_timeStamp = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public AbstractConnection(EndPoint endp,long timestamp)
|
||||
{
|
||||
_endp=endp;
|
||||
_endp=(EndPoint)endp;
|
||||
_timeStamp = timestamp;
|
||||
}
|
||||
|
||||
|
@ -35,7 +35,7 @@ public abstract class AbstractConnection implements Connection
|
|||
return _endp;
|
||||
}
|
||||
|
||||
public void idleExpired()
|
||||
public void onIdleExpired()
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -59,6 +59,6 @@ public abstract class AbstractConnection implements Connection
|
|||
|
||||
public String toString()
|
||||
{
|
||||
return super.toString()+"@"+_endp.getLocalAddr()+":"+_endp.getLocalPort()+"<->"+_endp.getRemoteAddr()+":"+_endp.getRemotePort();
|
||||
return this.getClass().getSimpleName()+"@"+_endp.getLocalAddr()+":"+_endp.getLocalPort()+"<->"+_endp.getRemoteAddr()+":"+_endp.getRemotePort();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,20 +13,16 @@
|
|||
|
||||
package org.eclipse.jetty.io;
|
||||
|
||||
public interface AsyncEndPoint extends EndPoint
|
||||
import org.eclipse.jetty.util.thread.Timeout;
|
||||
|
||||
public interface AsyncEndPoint extends ConnectedEndPoint
|
||||
{
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Dispatch the endpoint to a thread to attend to it.
|
||||
*
|
||||
*/
|
||||
public void dispatch();
|
||||
|
||||
/**
|
||||
* @return true if this endpoint can accept a dispatch. False if the
|
||||
* endpoint cannot accept a dispatched (eg is suspended or already dispatched)
|
||||
*/
|
||||
public boolean isReadyForDispatch();
|
||||
public void asyncDispatch();
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Schedule a write dispatch.
|
||||
|
@ -45,4 +41,22 @@ public interface AsyncEndPoint extends EndPoint
|
|||
*/
|
||||
public void cancelIdle();
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public boolean isWritable();
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @return True if IO has been successfully performed since the last call to {@link #hasProgressed()}
|
||||
*/
|
||||
public boolean hasProgressed();
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
*/
|
||||
public void scheduleTimeout(Timeout.Task task, long timeoutMs);
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
*/
|
||||
public void cancelTimeout(Timeout.Task task);
|
||||
}
|
||||
|
|
|
@ -103,6 +103,12 @@ public class BufferCache
|
|||
return lookup(buffer).toString();
|
||||
}
|
||||
|
||||
public int getOrdinal(String value)
|
||||
{
|
||||
CachedBuffer buffer = (CachedBuffer)_stringMap.get(value);
|
||||
return buffer==null?-1:buffer.getOrdinal();
|
||||
}
|
||||
|
||||
public int getOrdinal(Buffer buffer)
|
||||
{
|
||||
if (buffer instanceof CachedBuffer)
|
||||
|
|
|
@ -46,7 +46,6 @@ public class BufferDateCache extends DateCache
|
|||
public synchronized Buffer formatBuffer(long date)
|
||||
{
|
||||
String d = super.format(date);
|
||||
//noinspection StringEquality
|
||||
if (d==_last)
|
||||
return _buffer;
|
||||
_last=d;
|
||||
|
|
|
@ -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.io;
|
||||
|
@ -19,7 +19,7 @@ import java.io.IOException;
|
|||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** ByteArrayEndPoint.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class ByteArrayEndPoint implements ConnectedEndPoint
|
||||
|
@ -36,12 +36,12 @@ public class ByteArrayEndPoint implements ConnectedEndPoint
|
|||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
public ByteArrayEndPoint()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.io.ConnectedEndPoint#getConnection()
|
||||
|
@ -80,7 +80,7 @@ public class ByteArrayEndPoint implements ConnectedEndPoint
|
|||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
public ByteArrayEndPoint(byte[] input, int outputSize)
|
||||
{
|
||||
|
@ -121,9 +121,9 @@ public class ByteArrayEndPoint implements ConnectedEndPoint
|
|||
{
|
||||
_out = out;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/*
|
||||
/*
|
||||
* @see org.eclipse.io.EndPoint#isOpen()
|
||||
*/
|
||||
public boolean isOpen()
|
||||
|
@ -150,7 +150,7 @@ public class ByteArrayEndPoint implements ConnectedEndPoint
|
|||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/*
|
||||
/*
|
||||
* @see org.eclipse.io.EndPoint#isBlocking()
|
||||
*/
|
||||
public boolean isBlocking()
|
||||
|
@ -171,7 +171,7 @@ public class ByteArrayEndPoint implements ConnectedEndPoint
|
|||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/*
|
||||
/*
|
||||
* @see org.eclipse.io.EndPoint#shutdownOutput()
|
||||
*/
|
||||
public void shutdownOutput() throws IOException
|
||||
|
@ -180,16 +180,16 @@ public class ByteArrayEndPoint implements ConnectedEndPoint
|
|||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/*
|
||||
/*
|
||||
* @see org.eclipse.io.EndPoint#shutdownInput()
|
||||
*/
|
||||
public void shutdownInput() throws IOException
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/*
|
||||
/*
|
||||
* @see org.eclipse.io.EndPoint#close()
|
||||
*/
|
||||
public void close() throws IOException
|
||||
|
@ -198,30 +198,30 @@ public class ByteArrayEndPoint implements ConnectedEndPoint
|
|||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/*
|
||||
/*
|
||||
* @see org.eclipse.io.EndPoint#fill(org.eclipse.io.Buffer)
|
||||
*/
|
||||
public int fill(Buffer buffer) throws IOException
|
||||
{
|
||||
if (_closed)
|
||||
throw new IOException("CLOSED");
|
||||
|
||||
|
||||
if (_in!=null && _in.length()>0)
|
||||
{
|
||||
int len = buffer.put(_in);
|
||||
_in.skip(len);
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
if (_in!=null && _in.length()==0 && _nonBlocking)
|
||||
return 0;
|
||||
|
||||
|
||||
close();
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/*
|
||||
/*
|
||||
* @see org.eclipse.io.EndPoint#flush(org.eclipse.io.Buffer)
|
||||
*/
|
||||
public int flush(Buffer buffer) throws IOException
|
||||
|
@ -251,24 +251,24 @@ public class ByteArrayEndPoint implements ConnectedEndPoint
|
|||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/*
|
||||
/*
|
||||
* @see org.eclipse.io.EndPoint#flush(org.eclipse.io.Buffer, org.eclipse.io.Buffer, org.eclipse.io.Buffer)
|
||||
*/
|
||||
public int flush(Buffer header, Buffer buffer, Buffer trailer) throws IOException
|
||||
{
|
||||
if (_closed)
|
||||
throw new IOException("CLOSED");
|
||||
|
||||
|
||||
int flushed=0;
|
||||
|
||||
|
||||
if (header!=null && header.length()>0)
|
||||
flushed=flush(header);
|
||||
|
||||
|
||||
if (header==null || header.length()==0)
|
||||
{
|
||||
if (buffer!=null && buffer.length()>0)
|
||||
flushed+=flush(buffer);
|
||||
|
||||
|
||||
if (buffer==null || buffer.length()==0)
|
||||
{
|
||||
if (trailer!=null && trailer.length()>0)
|
||||
|
@ -277,13 +277,13 @@ public class ByteArrayEndPoint implements ConnectedEndPoint
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return flushed;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
public void reset()
|
||||
{
|
||||
|
@ -295,7 +295,7 @@ public class ByteArrayEndPoint implements ConnectedEndPoint
|
|||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/*
|
||||
/*
|
||||
* @see org.eclipse.io.EndPoint#getLocalAddr()
|
||||
*/
|
||||
public String getLocalAddr()
|
||||
|
@ -304,7 +304,7 @@ public class ByteArrayEndPoint implements ConnectedEndPoint
|
|||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/*
|
||||
/*
|
||||
* @see org.eclipse.io.EndPoint#getLocalHost()
|
||||
*/
|
||||
public String getLocalHost()
|
||||
|
@ -313,7 +313,7 @@ public class ByteArrayEndPoint implements ConnectedEndPoint
|
|||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/*
|
||||
/*
|
||||
* @see org.eclipse.io.EndPoint#getLocalPort()
|
||||
*/
|
||||
public int getLocalPort()
|
||||
|
@ -322,7 +322,7 @@ public class ByteArrayEndPoint implements ConnectedEndPoint
|
|||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/*
|
||||
/*
|
||||
* @see org.eclipse.io.EndPoint#getRemoteAddr()
|
||||
*/
|
||||
public String getRemoteAddr()
|
||||
|
@ -331,7 +331,7 @@ public class ByteArrayEndPoint implements ConnectedEndPoint
|
|||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/*
|
||||
/*
|
||||
* @see org.eclipse.io.EndPoint#getRemoteHost()
|
||||
*/
|
||||
public String getRemoteHost()
|
||||
|
@ -340,7 +340,7 @@ public class ByteArrayEndPoint implements ConnectedEndPoint
|
|||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/*
|
||||
/*
|
||||
* @see org.eclipse.io.EndPoint#getRemotePort()
|
||||
*/
|
||||
public int getRemotePort()
|
||||
|
@ -349,7 +349,7 @@ public class ByteArrayEndPoint implements ConnectedEndPoint
|
|||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/*
|
||||
/*
|
||||
* @see org.eclipse.io.EndPoint#getConnection()
|
||||
*/
|
||||
public Object getTransport()
|
||||
|
@ -359,27 +359,9 @@ public class ByteArrayEndPoint implements ConnectedEndPoint
|
|||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void flush() throws IOException
|
||||
{
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public boolean isBufferingInput()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public boolean isBufferingOutput()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public boolean isBufferred()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @return the growOutput
|
||||
|
|
|
@ -50,10 +50,10 @@ public interface Connection
|
|||
/**
|
||||
* Called when the connection is closed
|
||||
*/
|
||||
void closed();
|
||||
void onClose();
|
||||
|
||||
/**
|
||||
* Called when the connection idle timeout expires
|
||||
*/
|
||||
void idleExpired();
|
||||
void onIdleExpired();
|
||||
}
|
||||
|
|
|
@ -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.io;
|
||||
|
@ -17,7 +17,7 @@ import java.io.IOException;
|
|||
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* A transport EndPoint
|
||||
*/
|
||||
public interface EndPoint
|
||||
|
@ -28,36 +28,36 @@ public interface EndPoint
|
|||
void shutdownOutput() throws IOException;
|
||||
|
||||
boolean isOutputShutdown();
|
||||
|
||||
|
||||
/**
|
||||
* Shutdown any backing input stream associated with the endpoint
|
||||
*/
|
||||
void shutdownInput() throws IOException;
|
||||
|
||||
|
||||
boolean isInputShutdown();
|
||||
|
||||
|
||||
/**
|
||||
* Close any backing stream associated with the endpoint
|
||||
*/
|
||||
void close() throws IOException;
|
||||
|
||||
/**
|
||||
* Fill the buffer from the current putIndex to it's capacity from whatever
|
||||
* Fill the buffer from the current putIndex to it's capacity from whatever
|
||||
* byte source is backing the buffer. The putIndex is increased if bytes filled.
|
||||
* The buffer may chose to do a compact before filling.
|
||||
* @return an <code>int</code> value indicating the number of bytes
|
||||
* @return an <code>int</code> value indicating the number of bytes
|
||||
* filled or -1 if EOF is reached.
|
||||
* @throws EofException If input is shutdown or the endpoint is closed.
|
||||
*/
|
||||
int fill(Buffer buffer) throws IOException;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Flush the buffer from the current getIndex to it's putIndex using whatever byte
|
||||
* sink is backing the buffer. The getIndex is updated with the number of bytes flushed.
|
||||
* Any mark set is cleared.
|
||||
* If the entire contents of the buffer are flushed, then an implicit empty() is done.
|
||||
*
|
||||
*
|
||||
* @param buffer The buffer to flush. This buffers getIndex is updated.
|
||||
* @return the number of bytes written
|
||||
* @throws EofException If the endpoint is closed or output is shutdown.
|
||||
|
@ -69,7 +69,7 @@ public interface EndPoint
|
|||
* sink is backing the buffer. The getIndex is updated with the number of bytes flushed.
|
||||
* Any mark set is cleared.
|
||||
* If the entire contents of the buffer are flushed, then an implicit empty() is done.
|
||||
* The passed header/trailer buffers are written before/after the contents of this buffer. This may be done
|
||||
* The passed header/trailer buffers are written before/after the contents of this buffer. This may be done
|
||||
* either as gather writes, as a poke into this buffer or as several writes. The implementation is free to
|
||||
* select the optimal mechanism.
|
||||
* @param header A buffer to write before flushing this buffer. This buffers getIndex is updated.
|
||||
|
@ -79,14 +79,14 @@ public interface EndPoint
|
|||
*/
|
||||
int flush(Buffer header, Buffer buffer, Buffer trailer) throws IOException;
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @return The local IP address to which this <code>EndPoint</code> is bound, or <code>null</code>
|
||||
* if this <code>EndPoint</code> does not represent a network connection.
|
||||
*/
|
||||
public String getLocalAddr();
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @return The local host name to which this <code>EndPoint</code> is bound, or <code>null</code>
|
||||
|
@ -122,13 +122,9 @@ public interface EndPoint
|
|||
*/
|
||||
public int getRemotePort();
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public boolean isBlocking();
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public boolean isBufferred();
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public boolean blockReadable(long millisecs) throws IOException;
|
||||
|
||||
|
@ -143,27 +139,14 @@ public interface EndPoint
|
|||
* @return The underlying transport object (socket, channel, etc.)
|
||||
*/
|
||||
public Object getTransport();
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @return True if the endpoint has some buffered input data
|
||||
*/
|
||||
public boolean isBufferingInput();
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @return True if the endpoint has some buffered output data
|
||||
*/
|
||||
public boolean isBufferingOutput();
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Flush any buffered output.
|
||||
* May fail to write all data if endpoint is non-blocking
|
||||
* @throws EofException If the endpoint is closed or output is shutdown.
|
||||
*/
|
||||
public void flush() throws IOException;
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Get the max idle time in ms.
|
||||
* <p>The max idle time is the time the endpoint can be idle before
|
||||
|
@ -174,14 +157,14 @@ public interface EndPoint
|
|||
* @return the max idle time in ms or if ms <= 0 implies an infinite timeout
|
||||
*/
|
||||
public int getMaxIdleTime();
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Set the max idle time.
|
||||
* @param timeMs the max idle time in MS. Timeout <= 0 implies an infinite timeout
|
||||
* @throws IOException if the timeout cannot be set.
|
||||
*/
|
||||
public void setMaxIdleTime(int timeMs) throws IOException;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -15,6 +15,13 @@ package org.eclipse.jetty.io;
|
|||
|
||||
import java.io.EOFException;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** A Jetty specialization of EOFException.
|
||||
* <p> This is thrown by Jetty to distinguish between EOF received from
|
||||
* the connection, vs and EOF thrown by some application talking to some other file/socket etc.
|
||||
* The only difference in handling is that Jetty EOFs are logged less verbosely.
|
||||
*/
|
||||
public class EofException extends EOFException
|
||||
{
|
||||
public EofException()
|
||||
|
|
|
@ -107,7 +107,7 @@ public class UncheckedPrintWriter extends PrintWriter
|
|||
{
|
||||
setError();
|
||||
if (_throwUnchecked)
|
||||
throw new UncheckedIOException(th);
|
||||
throw new RuntimeIOException(th);
|
||||
LOG.debug(th);
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ import java.io.IOException;
|
|||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Socket;
|
||||
|
||||
import javax.net.ssl.SSLSocket;
|
||||
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
|
@ -79,14 +80,34 @@ public class SocketEndPoint extends StreamEndPoint
|
|||
@Override
|
||||
public boolean isInputShutdown()
|
||||
{
|
||||
return !isOpen() || super.isInputShutdown();
|
||||
if (_socket instanceof SSLSocket)
|
||||
return super.isInputShutdown();
|
||||
return _socket.isClosed() || _socket.isInputShutdown();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public boolean isOutputShutdown()
|
||||
{
|
||||
if (_socket instanceof SSLSocket)
|
||||
return super.isOutputShutdown();
|
||||
|
||||
return _socket.isClosed() || _socket.isOutputShutdown();
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/*
|
||||
*/
|
||||
protected final void shutdownSocketOutput() throws IOException
|
||||
{
|
||||
return !isOpen() || super.isOutputShutdown();
|
||||
if (!_socket.isClosed())
|
||||
{
|
||||
if (!_socket.isOutputShutdown())
|
||||
_socket.shutdownOutput();
|
||||
if (_socket.isInputShutdown())
|
||||
_socket.close();
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -96,15 +117,27 @@ public class SocketEndPoint extends StreamEndPoint
|
|||
@Override
|
||||
public void shutdownOutput() throws IOException
|
||||
{
|
||||
if (!isOutputShutdown())
|
||||
{
|
||||
if (_socket instanceof SSLSocket)
|
||||
super.shutdownOutput();
|
||||
if (!(_socket instanceof SSLSocket))
|
||||
_socket.shutdownOutput();
|
||||
}
|
||||
else
|
||||
shutdownSocketOutput();
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/*
|
||||
*/
|
||||
public void shutdownSocketInput() throws IOException
|
||||
{
|
||||
if (!_socket.isClosed())
|
||||
{
|
||||
if (!_socket.isInputShutdown())
|
||||
_socket.shutdownInput();
|
||||
if (_socket.isOutputShutdown())
|
||||
_socket.close();
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/*
|
||||
* @see org.eclipse.jetty.io.bio.StreamEndPoint#shutdownOutput()
|
||||
|
@ -112,12 +145,10 @@ public class SocketEndPoint extends StreamEndPoint
|
|||
@Override
|
||||
public void shutdownInput() throws IOException
|
||||
{
|
||||
if (!isInputShutdown())
|
||||
{
|
||||
if (_socket instanceof SSLSocket)
|
||||
super.shutdownInput();
|
||||
if (!(_socket instanceof SSLSocket))
|
||||
_socket.shutdownInput();
|
||||
}
|
||||
else
|
||||
shutdownSocketInput();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
|
|
@ -72,10 +72,8 @@ public class StreamEndPoint implements EndPoint
|
|||
|
||||
public void shutdownOutput() throws IOException
|
||||
{
|
||||
if (_oshut)
|
||||
return;
|
||||
_oshut = true;
|
||||
if (_out!=null)
|
||||
if (_ishut && _out!=null)
|
||||
_out.close();
|
||||
}
|
||||
|
||||
|
@ -86,10 +84,8 @@ public class StreamEndPoint implements EndPoint
|
|||
|
||||
public void shutdownInput() throws IOException
|
||||
{
|
||||
if (_ishut)
|
||||
return;
|
||||
_ishut = true;
|
||||
if (_in!=null)
|
||||
if (_oshut&&_in!=null)
|
||||
_in.close();
|
||||
}
|
||||
|
||||
|
@ -122,6 +118,8 @@ public class StreamEndPoint implements EndPoint
|
|||
*/
|
||||
public int fill(Buffer buffer) throws IOException
|
||||
{
|
||||
if (_ishut)
|
||||
return -1;
|
||||
if (_in==null)
|
||||
return 0;
|
||||
|
||||
|
@ -135,15 +133,10 @@ public class StreamEndPoint implements EndPoint
|
|||
|
||||
try
|
||||
{
|
||||
int read=buffer.readFrom(_in, space);
|
||||
if (read<0 && isOpen())
|
||||
{
|
||||
if (!isInputShutdown())
|
||||
shutdownInput();
|
||||
else if (isOutputShutdown())
|
||||
close();
|
||||
}
|
||||
return read;
|
||||
int filled=buffer.readFrom(_in, space);
|
||||
if (filled<0)
|
||||
shutdownInput();
|
||||
return filled;
|
||||
}
|
||||
catch(SocketTimeoutException e)
|
||||
{
|
||||
|
@ -157,8 +150,10 @@ public class StreamEndPoint implements EndPoint
|
|||
*/
|
||||
public int flush(Buffer buffer) throws IOException
|
||||
{
|
||||
if (_out==null)
|
||||
if (_oshut)
|
||||
return -1;
|
||||
if (_out==null)
|
||||
return 0;
|
||||
int length=buffer.length();
|
||||
if (length>0)
|
||||
buffer.writeTo(_out);
|
||||
|
@ -309,24 +304,6 @@ public class StreamEndPoint implements EndPoint
|
|||
_out.flush();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public boolean isBufferingInput()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public boolean isBufferingOutput()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public boolean isBufferred()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public int getMaxIdleTime()
|
||||
{
|
||||
|
|
|
@ -53,6 +53,8 @@ public class StringEndPoint extends StreamEndPoint
|
|||
_in=_bin;
|
||||
_bout = new ByteArrayOutputStream();
|
||||
_out=_bout;
|
||||
_ishut=false;
|
||||
_oshut=false;
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
// ========================================================================
|
||||
// Copyright (c) 2010 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 java.io.IOException;
|
||||
|
||||
import org.eclipse.jetty.io.Connection;
|
||||
|
||||
public interface AsyncConnection extends Connection
|
||||
{
|
||||
void onInputShutdown() throws IOException;
|
||||
}
|
|
@ -102,29 +102,77 @@ public class ChannelEndPoint implements EndPoint
|
|||
return _channel.isOpen();
|
||||
}
|
||||
|
||||
/** Shutdown the channel Input.
|
||||
* Cannot be overridden. To override, see {@link #shutdownInput()}
|
||||
* @throws IOException
|
||||
*/
|
||||
protected final void shutdownChannelInput() throws IOException
|
||||
{
|
||||
LOG.debug("ishut {}",this);
|
||||
if (_channel.isOpen())
|
||||
{
|
||||
if (_channel instanceof SocketChannel)
|
||||
{
|
||||
Socket socket= ((SocketChannel)_channel).socket();
|
||||
try
|
||||
{
|
||||
if (!socket.isInputShutdown())
|
||||
socket.shutdownInput();
|
||||
}
|
||||
catch(SocketException e)
|
||||
{
|
||||
LOG.debug(e.toString());
|
||||
LOG.ignore(e);
|
||||
if (!socket.isClosed())
|
||||
close();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if(socket.isOutputShutdown() && !socket.isClosed())
|
||||
close();
|
||||
}
|
||||
}
|
||||
else
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.io.EndPoint#close()
|
||||
*/
|
||||
public void shutdownInput() throws IOException
|
||||
{
|
||||
if (_channel.isOpen() && _channel instanceof SocketChannel)
|
||||
{
|
||||
Socket socket= ((SocketChannel)_channel).socket();
|
||||
if (!socket.isClosed())
|
||||
{
|
||||
shutdownChannelInput();
|
||||
}
|
||||
|
||||
protected final void shutdownChannelOutput() throws IOException
|
||||
{
|
||||
LOG.debug("oshut {}",this);
|
||||
if (_channel.isOpen())
|
||||
{
|
||||
if (_channel instanceof SocketChannel)
|
||||
{
|
||||
Socket socket= ((SocketChannel)_channel).socket();
|
||||
try
|
||||
{
|
||||
if (!socket.isInputShutdown())
|
||||
socket.shutdownInput();
|
||||
if (socket.isOutputShutdown())
|
||||
socket.close();
|
||||
if (!socket.isOutputShutdown())
|
||||
socket.shutdownOutput();
|
||||
}
|
||||
catch (SocketException e)
|
||||
catch(SocketException e)
|
||||
{
|
||||
LOG.ignore(e);
|
||||
LOG.warn(e.toString());
|
||||
LOG.debug(e);
|
||||
if (!socket.isClosed())
|
||||
close();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (socket.isInputShutdown() && !socket.isClosed())
|
||||
close();
|
||||
}
|
||||
}
|
||||
else
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -133,34 +181,17 @@ public class ChannelEndPoint implements EndPoint
|
|||
*/
|
||||
public void shutdownOutput() throws IOException
|
||||
{
|
||||
if (_channel.isOpen() && _channel instanceof SocketChannel)
|
||||
{
|
||||
Socket socket= ((SocketChannel)_channel).socket();
|
||||
if (!socket.isClosed())
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!socket.isOutputShutdown())
|
||||
socket.shutdownOutput();
|
||||
if (socket.isInputShutdown())
|
||||
socket.close();
|
||||
}
|
||||
catch (SocketException e)
|
||||
{
|
||||
LOG.ignore(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
shutdownChannelOutput();
|
||||
}
|
||||
|
||||
public boolean isOutputShutdown()
|
||||
{
|
||||
return _channel.isOpen() && _socket!=null && _socket.isOutputShutdown();
|
||||
return !_channel.isOpen() || _socket!=null && _socket.isOutputShutdown();
|
||||
}
|
||||
|
||||
public boolean isInputShutdown()
|
||||
{
|
||||
return _channel.isOpen() && _socket!=null && _socket.isInputShutdown();
|
||||
return !_channel.isOpen() || _socket!=null && _socket.isInputShutdown();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
|
@ -168,6 +199,7 @@ public class ChannelEndPoint implements EndPoint
|
|||
*/
|
||||
public void close() throws IOException
|
||||
{
|
||||
LOG.debug("close {}",this);
|
||||
_channel.close();
|
||||
}
|
||||
|
||||
|
@ -204,18 +236,20 @@ public class ChannelEndPoint implements EndPoint
|
|||
{
|
||||
if (!isInputShutdown())
|
||||
shutdownInput();
|
||||
else if (isOutputShutdown())
|
||||
if (isOutputShutdown())
|
||||
_channel.close();
|
||||
}
|
||||
}
|
||||
catch (IOException x)
|
||||
{
|
||||
LOG.debug(x);
|
||||
LOG.debug(x.toString());
|
||||
LOG.ignore(x);
|
||||
try
|
||||
{
|
||||
close();
|
||||
if (_channel.isOpen())
|
||||
_channel.close();
|
||||
}
|
||||
catch (IOException xx)
|
||||
catch (Exception xx)
|
||||
{
|
||||
LOG.ignore(xx);
|
||||
}
|
||||
|
@ -301,20 +335,6 @@ public class ChannelEndPoint implements EndPoint
|
|||
}
|
||||
else
|
||||
{
|
||||
if (header!=null)
|
||||
{
|
||||
if (buffer!=null && buffer.length()>0 && header.space()>buffer.length())
|
||||
{
|
||||
header.put(buffer);
|
||||
buffer.clear();
|
||||
}
|
||||
if (trailer!=null && trailer.length()>0 && header.space()>trailer.length())
|
||||
{
|
||||
header.put(trailer);
|
||||
trailer.clear();
|
||||
}
|
||||
}
|
||||
|
||||
// flush header
|
||||
if (header!=null && header.length()>0)
|
||||
length=flush(header);
|
||||
|
@ -330,7 +350,7 @@ public class ChannelEndPoint implements EndPoint
|
|||
trailer!=null && trailer.length()>0)
|
||||
length+=flush(trailer);
|
||||
}
|
||||
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
|
@ -492,24 +512,6 @@ public class ChannelEndPoint implements EndPoint
|
|||
{
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public boolean isBufferingInput()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public boolean isBufferingOutput()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public boolean isBufferred()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public int getMaxIdleTime()
|
||||
{
|
||||
|
|
|
@ -27,6 +27,7 @@ import org.eclipse.jetty.io.EofException;
|
|||
import org.eclipse.jetty.io.nio.SelectorManager.SelectSet;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.util.thread.Timeout.Task;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
|
@ -53,13 +54,13 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
|||
* ProxyConnect. The connection may change for an SCEP as it is upgraded
|
||||
* from HTTP to proxy connect or websocket.
|
||||
*/
|
||||
private volatile Connection _connection;
|
||||
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 _redispatched = false;
|
||||
private boolean _asyncDispatch = false;
|
||||
|
||||
/** true if the last write operation succeed and wrote all offered bytes */
|
||||
private volatile boolean _writable = true;
|
||||
|
@ -76,6 +77,8 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
|||
|
||||
private volatile long _idleTimestamp;
|
||||
|
||||
private boolean _ishut;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public SelectChannelEndPoint(SocketChannel channel, SelectSet selectSet, SelectionKey key, int maxIdleTime)
|
||||
throws IOException
|
||||
|
@ -85,30 +88,10 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
|||
_manager = selectSet.getManager();
|
||||
_selectSet = selectSet;
|
||||
_dispatched = false;
|
||||
_redispatched = false;
|
||||
_asyncDispatch = false;
|
||||
_open=true;
|
||||
_key = key;
|
||||
|
||||
_connection = _manager.newConnection(channel,this);
|
||||
|
||||
scheduleIdle();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public SelectChannelEndPoint(SocketChannel channel, SelectSet selectSet, SelectionKey key)
|
||||
throws IOException
|
||||
{
|
||||
super(channel);
|
||||
|
||||
_manager = selectSet.getManager();
|
||||
_selectSet = selectSet;
|
||||
_dispatched = false;
|
||||
_redispatched = false;
|
||||
_open=true;
|
||||
_key = key;
|
||||
|
||||
_connection = _manager.newConnection(channel,this);
|
||||
|
||||
scheduleIdle();
|
||||
}
|
||||
|
||||
|
@ -137,8 +120,9 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
|||
public void setConnection(Connection connection)
|
||||
{
|
||||
Connection old=_connection;
|
||||
_connection=connection;
|
||||
_manager.endPointUpgraded(this,old);
|
||||
_connection=(AsyncConnection)connection;
|
||||
if (old!=null && old!=_connection)
|
||||
_manager.endPointUpgraded(this,old);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -164,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;
|
||||
|
@ -176,15 +160,6 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
|||
// wake them up is as good as a dispatched.
|
||||
this.notifyAll();
|
||||
|
||||
// we are not interested in further selecting
|
||||
if (_dispatched)
|
||||
_key.interestOps(0);
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise if we are still dispatched
|
||||
if (!isReadyForDispatch())
|
||||
{
|
||||
// we are not interested in further selecting
|
||||
_key.interestOps(0);
|
||||
return;
|
||||
|
@ -211,6 +186,18 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
|||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void asyncDispatch()
|
||||
{
|
||||
synchronized(this)
|
||||
{
|
||||
if (_dispatched)
|
||||
_asyncDispatch=true;
|
||||
else
|
||||
dispatch();
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void dispatch()
|
||||
{
|
||||
|
@ -218,7 +205,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
|||
{
|
||||
if (_dispatched)
|
||||
{
|
||||
_redispatched=true;
|
||||
throw new IllegalStateException("dispatched");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -245,9 +232,9 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
|||
{
|
||||
synchronized (this)
|
||||
{
|
||||
if (_redispatched)
|
||||
if (_asyncDispatch)
|
||||
{
|
||||
_redispatched=false;
|
||||
_asyncDispatch=false;
|
||||
return false;
|
||||
}
|
||||
_dispatched = false;
|
||||
|
@ -256,6 +243,18 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
|||
return true;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void cancelTimeout(Task task)
|
||||
{
|
||||
getSelectSet().cancelTimeout(task);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void scheduleTimeout(Task task, long timeoutMs)
|
||||
{
|
||||
getSelectSet().scheduleTimeout(task,timeoutMs);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void scheduleIdle()
|
||||
{
|
||||
|
@ -279,21 +278,10 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
|||
/* ------------------------------------------------------------ */
|
||||
protected void idleExpired()
|
||||
{
|
||||
_connection.idleExpired();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @return True if the endpoint has produced/consumed bytes itself (non application data).
|
||||
*/
|
||||
public boolean isProgressing()
|
||||
{
|
||||
return false;
|
||||
_connection.onIdleExpired();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/*
|
||||
*/
|
||||
@Override
|
||||
public int flush(Buffer header, Buffer buffer, Buffer trailer) throws IOException
|
||||
{
|
||||
|
@ -309,8 +297,10 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
|||
updateKey();
|
||||
}
|
||||
}
|
||||
else
|
||||
else if (l>0)
|
||||
{
|
||||
_writable=true;
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
|
@ -332,22 +322,14 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
|||
updateKey();
|
||||
}
|
||||
}
|
||||
else
|
||||
else if (l>0)
|
||||
{
|
||||
_writable=true;
|
||||
}
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public boolean isReadyForDispatch()
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
// Ready if not dispatched and not suspended
|
||||
return !(_dispatched || getConnection().isSuspended());
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/*
|
||||
* Allows thread to block waiting for further events.
|
||||
|
@ -357,12 +339,15 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
|||
{
|
||||
synchronized (this)
|
||||
{
|
||||
if (isInputShutdown())
|
||||
throw new EofException();
|
||||
|
||||
long now=_selectSet.getNow();
|
||||
long end=now+timeoutMs;
|
||||
try
|
||||
{
|
||||
_readBlocked=true;
|
||||
while (isOpen() && _readBlocked)
|
||||
while (!isInputShutdown() && _readBlocked)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -399,7 +384,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
|||
{
|
||||
synchronized (this)
|
||||
{
|
||||
if (!isOpen() || isOutputShutdown())
|
||||
if (isOutputShutdown())
|
||||
throw new EofException();
|
||||
|
||||
long now=_selectSet.getNow();
|
||||
|
@ -407,7 +392,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
|||
try
|
||||
{
|
||||
_writeBlocked=true;
|
||||
while (isOpen() && _writeBlocked && !isOutputShutdown())
|
||||
while (_writeBlocked && !isOutputShutdown())
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -426,16 +411,6 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
|||
return false;
|
||||
}
|
||||
}
|
||||
catch(Throwable e)
|
||||
{
|
||||
// TODO remove this if it finds nothing
|
||||
LOG.warn(e);
|
||||
if (e instanceof RuntimeException)
|
||||
throw (RuntimeException)e;
|
||||
if (e instanceof Error)
|
||||
throw (Error)e;
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_writeBlocked=false;
|
||||
|
@ -454,6 +429,9 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
|||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.io.AsyncEndPoint#scheduleWrite()
|
||||
*/
|
||||
public void scheduleWrite()
|
||||
{
|
||||
if (_writable==true)
|
||||
|
@ -462,6 +440,18 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
|||
_writable=false;
|
||||
updateKey();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public boolean isWritable()
|
||||
{
|
||||
return _writable;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public boolean hasProgressed()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
|
@ -471,17 +461,21 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
|||
*/
|
||||
private void updateKey()
|
||||
{
|
||||
final boolean changed;
|
||||
synchronized (this)
|
||||
{
|
||||
int ops=-1;
|
||||
int current_ops=-1;
|
||||
if (getChannel().isOpen())
|
||||
{
|
||||
boolean read_interest = _readBlocked || (!_dispatched && !_connection.isSuspended());
|
||||
boolean write_interest= _writeBlocked || (!_dispatched && !_writable);
|
||||
|
||||
_interestOps =
|
||||
((!_socket.isInputShutdown() && (!_dispatched || _readBlocked)) ? SelectionKey.OP_READ : 0)
|
||||
| ((!_socket.isOutputShutdown()&& (!_writable || _writeBlocked)) ? SelectionKey.OP_WRITE : 0);
|
||||
((!_socket.isInputShutdown() && read_interest ) ? SelectionKey.OP_READ : 0)
|
||||
| ((!_socket.isOutputShutdown()&& write_interest) ? SelectionKey.OP_WRITE : 0);
|
||||
try
|
||||
{
|
||||
ops = ((_key!=null && _key.isValid())?_key.interestOps():-1);
|
||||
current_ops = ((_key!=null && _key.isValid())?_key.interestOps():-1);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
|
@ -489,13 +483,16 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
|||
LOG.ignore(e);
|
||||
}
|
||||
}
|
||||
|
||||
if(_interestOps == ops && getChannel().isOpen())
|
||||
return;
|
||||
changed=_interestOps!=current_ops;
|
||||
}
|
||||
|
||||
if(changed)
|
||||
{
|
||||
_selectSet.addChange(this);
|
||||
_selectSet.wakeup();
|
||||
}
|
||||
_selectSet.addChange(this);
|
||||
_selectSet.wakeup();
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
|
@ -583,11 +580,13 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
|||
{
|
||||
while(true)
|
||||
{
|
||||
final Connection next = _connection.handle();
|
||||
final AsyncConnection next = (AsyncConnection)_connection.handle();
|
||||
if (next!=_connection)
|
||||
{
|
||||
LOG.debug("{} replaced {}",next,_connection);
|
||||
Connection old=_connection;
|
||||
_connection=next;
|
||||
_manager.endPointUpgraded(this,old);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
|
@ -600,23 +599,48 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
|||
catch (EofException e)
|
||||
{
|
||||
LOG.debug("EOF", e);
|
||||
try{getChannel().close();}
|
||||
try{close();}
|
||||
catch(IOException e2){LOG.ignore(e2);}
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
LOG.warn(e.toString());
|
||||
LOG.debug(e);
|
||||
try{getChannel().close();}
|
||||
try{close();}
|
||||
catch(IOException e2){LOG.ignore(e2);}
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
LOG.warn("handle failed", e);
|
||||
try{getChannel().close();}
|
||||
try{close();}
|
||||
catch(IOException e2){LOG.ignore(e2);}
|
||||
}
|
||||
dispatched=!undispatch();
|
||||
finally
|
||||
{
|
||||
if (!_ishut && isInputShutdown() && isOpen())
|
||||
{
|
||||
_ishut=true;
|
||||
try
|
||||
{
|
||||
_connection.onInputShutdown();
|
||||
}
|
||||
catch (ThreadDeath e)
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
catch(Throwable x)
|
||||
{
|
||||
LOG.warn("onInputShutdown failed", x);
|
||||
try{close();}
|
||||
catch(IOException e2){LOG.ignore(e2);}
|
||||
}
|
||||
finally
|
||||
{
|
||||
updateKey();
|
||||
}
|
||||
}
|
||||
dispatched=!undispatch();
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
|
@ -660,9 +684,20 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
|||
{
|
||||
synchronized(this)
|
||||
{
|
||||
return "SCEP@" + hashCode() + "/" + _channel+
|
||||
"[o="+isOpen()+" d=" + _dispatched + ",io=" + _interestOps+
|
||||
",w=" + _writable + ",rb=" + _readBlocked + ",wb=" + _writeBlocked + "]";
|
||||
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":"")))+
|
||||
"}";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@ import java.util.concurrent.ConcurrentMap;
|
|||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jetty.io.AsyncEndPoint;
|
||||
import org.eclipse.jetty.io.ConnectedEndPoint;
|
||||
import org.eclipse.jetty.io.Connection;
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
|
@ -54,7 +55,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
|||
public static final Logger LOG=Log.getLogger("org.eclipse.jetty.io.nio");
|
||||
|
||||
private static final int __MONITOR_PERIOD=Integer.getInteger("org.eclipse.jetty.io.nio.MONITOR_PERIOD",1000).intValue();
|
||||
private static final int __MAX_SELECTS=Integer.getInteger("org.eclipse.jetty.io.nio.MAX_SELECTS",25000).intValue();
|
||||
private static final int __MAX_SELECTS=Integer.getInteger("org.eclipse.jetty.io.nio.MAX_SELECTS",100000).intValue();
|
||||
private static final int __BUSY_PAUSE=Integer.getInteger("org.eclipse.jetty.io.nio.BUSY_PAUSE",50).intValue();
|
||||
private static final int __IDLE_TICK=Integer.getInteger("org.eclipse.jetty.io.nio.IDLE_TICK",400).intValue();
|
||||
|
||||
|
@ -343,7 +344,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
|||
protected abstract void endPointUpgraded(ConnectedEndPoint endpoint,Connection oldConnection);
|
||||
|
||||
/* ------------------------------------------------------------------------------- */
|
||||
protected abstract Connection newConnection(SocketChannel channel, SelectChannelEndPoint endpoint);
|
||||
public abstract AsyncConnection newConnection(SocketChannel channel, AsyncEndPoint endpoint, Object attachment);
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
|
@ -506,11 +507,12 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
|||
{
|
||||
LOG.ignore(e);
|
||||
}
|
||||
catch (ThreadDeath e)
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
if (e instanceof ThreadDeath)
|
||||
throw (ThreadDeath)e;
|
||||
|
||||
if (isRunning())
|
||||
LOG.warn(e);
|
||||
else
|
||||
|
@ -590,6 +592,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
|||
{
|
||||
System.err.println(set+":\n"+set.dump());
|
||||
}
|
||||
public String toString() {return "Dump-"+super.toString();}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -719,6 +722,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
|||
endp.checkIdleTimestamp(idle_now);
|
||||
}
|
||||
}
|
||||
public String toString() {return "Idle-"+super.toString();}
|
||||
});
|
||||
|
||||
}
|
||||
|
@ -843,6 +847,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
|
|||
private SelectChannelEndPoint createEndPoint(SocketChannel channel, SelectionKey sKey) throws IOException
|
||||
{
|
||||
SelectChannelEndPoint endp = newEndPoint(channel,this,sKey);
|
||||
LOG.debug("created {}",endp);
|
||||
endPointOpened(endp);
|
||||
_endPoints.put(endp,this);
|
||||
return endp;
|
||||
|
|
|
@ -0,0 +1,808 @@
|
|||
// ========================================================================
|
||||
// Copyright (c) 2004-2011 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 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;
|
||||
import javax.net.ssl.SSLException;
|
||||
import javax.net.ssl.SSLSession;
|
||||
|
||||
import org.eclipse.jetty.io.AbstractConnection;
|
||||
import org.eclipse.jetty.io.AsyncEndPoint;
|
||||
import org.eclipse.jetty.io.Buffer;
|
||||
import org.eclipse.jetty.io.Connection;
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.util.thread.Timeout.Task;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** SSL Connection.
|
||||
* An AysyncConnection that acts as an interceptor between and EndPoint and another
|
||||
* Connection, that implements TLS encryption using an {@link SSLEngine}.
|
||||
* <p>
|
||||
* The connector uses an {@link AsyncEndPoint} (like {@link SelectChannelEndPoint}) as
|
||||
* it's source/sink of encrypted data. It then provides {@link #getSslEndPoint()} to
|
||||
* expose a source/sink of unencrypted data to another connection (eg HttpConnection).
|
||||
*/
|
||||
public class SslConnection extends AbstractConnection implements AsyncConnection
|
||||
{
|
||||
static final Logger LOG=Log.getLogger("org.eclipse.jetty.io.nio.ssl");
|
||||
|
||||
private static final NIOBuffer __ZERO_BUFFER=new IndirectNIOBuffer(0);
|
||||
|
||||
private static final ThreadLocal<SslBuffers> __buffers = new ThreadLocal<SslBuffers>();
|
||||
private final SSLEngine _engine;
|
||||
private final SSLSession _session;
|
||||
private AsyncConnection _connection;
|
||||
private final SslEndPoint _sslEndPoint = new SslEndPoint();
|
||||
private int _allocations;
|
||||
private SslBuffers _buffers;
|
||||
private NIOBuffer _inbound;
|
||||
private NIOBuffer _unwrapBuf;
|
||||
private NIOBuffer _outbound;
|
||||
private AsyncEndPoint _aEndp;
|
||||
private boolean _allowRenegotiate=true;
|
||||
private boolean _handshook;
|
||||
private boolean _ishut;
|
||||
private boolean _oshut;
|
||||
private final AtomicBoolean _progressed = new AtomicBoolean();
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/* this is a half baked buffer pool
|
||||
*/
|
||||
private static class SslBuffers
|
||||
{
|
||||
final NIOBuffer _in;
|
||||
final NIOBuffer _out;
|
||||
final NIOBuffer _unwrap;
|
||||
|
||||
SslBuffers(int packetSize, int appSize)
|
||||
{
|
||||
_in=new IndirectNIOBuffer(packetSize);
|
||||
_out=new IndirectNIOBuffer(packetSize);
|
||||
_unwrap=new IndirectNIOBuffer(appSize);
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public SslConnection(SSLEngine engine,EndPoint endp)
|
||||
{
|
||||
this(engine,endp,System.currentTimeMillis());
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public SslConnection(SSLEngine engine,EndPoint endp, long timeStamp)
|
||||
{
|
||||
super(endp,timeStamp);
|
||||
_engine=engine;
|
||||
_session=_engine.getSession();
|
||||
_aEndp=(AsyncEndPoint)endp;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @return True if SSL re-negotiation is allowed (default false)
|
||||
*/
|
||||
public boolean isAllowRenegotiate()
|
||||
{
|
||||
return _allowRenegotiate;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Set if SSL re-negotiation is allowed. CVE-2009-3555 discovered
|
||||
* a vulnerability in SSL/TLS with re-negotiation. If your JVM
|
||||
* does not have CVE-2009-3555 fixed, then re-negotiation should
|
||||
* not be allowed. CVE-2009-3555 was fixed in Sun java 1.6 with a ban
|
||||
* of renegotiates in u19 and with RFC5746 in u22.
|
||||
*
|
||||
* @param allowRenegotiate
|
||||
* true if re-negotiation is allowed (default false)
|
||||
*/
|
||||
public void setAllowRenegotiate(boolean allowRenegotiate)
|
||||
{
|
||||
_allowRenegotiate = allowRenegotiate;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private void allocateBuffers()
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
if (_allocations++==0)
|
||||
{
|
||||
if (_buffers==null)
|
||||
{
|
||||
_buffers=__buffers.get();
|
||||
if (_buffers==null)
|
||||
_buffers=new SslBuffers(_session.getPacketBufferSize()*2,_session.getApplicationBufferSize()*2);
|
||||
_inbound=_buffers._in;
|
||||
_outbound=_buffers._out;
|
||||
_unwrapBuf=_buffers._unwrap;
|
||||
__buffers.set(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private void releaseBuffers()
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
if (--_allocations==0)
|
||||
{
|
||||
if (_buffers!=null &&
|
||||
_inbound.length()==0 &&
|
||||
_outbound.length()==0 &&
|
||||
_unwrapBuf.length()==0)
|
||||
{
|
||||
_inbound=null;
|
||||
_outbound=null;
|
||||
_unwrapBuf=null;
|
||||
__buffers.set(_buffers);
|
||||
_buffers=null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public Connection handle() throws IOException
|
||||
{
|
||||
try
|
||||
{
|
||||
allocateBuffers();
|
||||
|
||||
boolean progress=true;
|
||||
|
||||
while (progress)
|
||||
{
|
||||
progress=false;
|
||||
|
||||
// If we are handshook let the delegate connection
|
||||
if (_engine.getHandshakeStatus()!=HandshakeStatus.NOT_HANDSHAKING)
|
||||
progress|=process(null,null);
|
||||
else
|
||||
{
|
||||
// handle the delegate connection
|
||||
AsyncConnection next = (AsyncConnection)_connection.handle();
|
||||
if (next!=_connection && next!=null)
|
||||
{
|
||||
_connection=next;
|
||||
progress=true;
|
||||
}
|
||||
}
|
||||
|
||||
LOG.debug("{} handle {} progress=",_session,this, progress);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
releaseBuffers();
|
||||
|
||||
if (!_ishut && _sslEndPoint.isInputShutdown() && _sslEndPoint.isOpen())
|
||||
{
|
||||
_ishut=true;
|
||||
try
|
||||
{
|
||||
_connection.onInputShutdown();
|
||||
}
|
||||
catch (ThreadDeath e)
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
catch(Throwable x)
|
||||
{
|
||||
LOG.warn("onInputShutdown failed", x);
|
||||
try{_sslEndPoint.close();}
|
||||
catch(IOException e2){LOG.ignore(e2);}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public boolean isIdle()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public boolean isSuspended()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void onClose()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void onInputShutdown() throws IOException
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private synchronized boolean process(Buffer toFill, Buffer toFlush) throws IOException
|
||||
{
|
||||
boolean some_progress=false;
|
||||
try
|
||||
{
|
||||
allocateBuffers();
|
||||
if (toFill==null)
|
||||
{
|
||||
_unwrapBuf.compact();
|
||||
toFill=_unwrapBuf;
|
||||
}
|
||||
else if (toFill.capacity()<_session.getApplicationBufferSize())
|
||||
{
|
||||
boolean progress=process(null,toFlush);
|
||||
if (_unwrapBuf!=null && _unwrapBuf.hasContent())
|
||||
{
|
||||
_unwrapBuf.skip(toFill.put(_unwrapBuf));
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return progress;
|
||||
}
|
||||
else if (_unwrapBuf!=null && _unwrapBuf.hasContent())
|
||||
{
|
||||
_unwrapBuf.skip(toFill.put(_unwrapBuf));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
if (toFlush==null)
|
||||
toFlush=__ZERO_BUFFER;
|
||||
|
||||
boolean progress=true;
|
||||
|
||||
while (progress)
|
||||
{
|
||||
progress=false;
|
||||
int filled=0,flushed=0;
|
||||
|
||||
try
|
||||
{
|
||||
// Read any available data
|
||||
if (_inbound.space()>0 && (filled=_endp.fill(_inbound))>0)
|
||||
progress = true;
|
||||
|
||||
// flush any output data
|
||||
if (_outbound.hasContent() && (flushed=_endp.flush(_outbound))>0)
|
||||
progress = true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.debug(e.toString());
|
||||
LOG.ignore(e);
|
||||
}
|
||||
LOG.debug("{} {} {} filled={}/{} flushed={}/{}",_session,this,_engine.getHandshakeStatus(),filled,_inbound.length(),flushed,_outbound.length());
|
||||
|
||||
// handle the current hand share status
|
||||
switch(_engine.getHandshakeStatus())
|
||||
{
|
||||
case FINISHED:
|
||||
throw new IllegalStateException();
|
||||
|
||||
case NOT_HANDSHAKING:
|
||||
{
|
||||
// Try wrapping some application data
|
||||
if (toFlush.hasContent() && _outbound.space()>0 && wrap(toFlush))
|
||||
progress=true;
|
||||
|
||||
// Try unwrapping some application data
|
||||
if (toFill.space()>0 && _inbound.hasContent() && unwrap(toFill))
|
||||
progress=true;
|
||||
}
|
||||
break;
|
||||
|
||||
case NEED_TASK:
|
||||
{
|
||||
// A task needs to be run, so run it!
|
||||
Runnable task;
|
||||
while ((task=_engine.getDelegatedTask())!=null)
|
||||
{
|
||||
progress=true;
|
||||
task.run();
|
||||
}
|
||||
|
||||
// Detect SUN JVM Bug!!!
|
||||
/* TODO
|
||||
if(initialStatus==HandshakeStatus.NOT_HANDSHAKING &&
|
||||
_engine.getHandshakeStatus()==HandshakeStatus.NEED_UNWRAP && sent==0 )
|
||||
{
|
||||
// This should be NEED_WRAP
|
||||
// The fix simply detects the signature of the bug and then close the connection (fail-fast) so that ff3 will delegate to using SSL instead of TLS.
|
||||
// This is a jvm bug on java1.6 where the SSLEngine expects more data from the initial handshake when the client(ff3-tls) already had given it.
|
||||
// See http://jira.codehaus.org/browse/JETTY-567 for more details
|
||||
LOG.warn("{} JETTY-567",_session);
|
||||
_endp.close();
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
}
|
||||
break;
|
||||
|
||||
case NEED_WRAP:
|
||||
{
|
||||
// The SSL needs to send some handshake data to the other side
|
||||
if (_handshook && !_allowRenegotiate)
|
||||
_endp.close();
|
||||
else if (wrap(toFlush))
|
||||
progress=true;
|
||||
}
|
||||
break;
|
||||
|
||||
case NEED_UNWRAP:
|
||||
{
|
||||
// The SSL needs to receive some handshake data from the other side
|
||||
if (_handshook && !_allowRenegotiate)
|
||||
_endp.close();
|
||||
else if (unwrap(toFill))
|
||||
progress=true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// pass on ishut/oshut state
|
||||
if (!_inbound.hasContent() && _endp.isInputShutdown())
|
||||
_engine.closeInbound();
|
||||
if (!_outbound.hasContent() && _engine.isOutboundDone())
|
||||
_endp.shutdownOutput();
|
||||
|
||||
some_progress|=progress;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
releaseBuffers();
|
||||
_progressed.set(some_progress);
|
||||
}
|
||||
return some_progress;
|
||||
}
|
||||
|
||||
private synchronized boolean wrap(final Buffer buffer) throws IOException
|
||||
{
|
||||
ByteBuffer bbuf=extractByteBuffer(buffer);
|
||||
final SSLEngineResult result;
|
||||
|
||||
synchronized(bbuf)
|
||||
{
|
||||
_outbound.compact();
|
||||
ByteBuffer out_buffer=_outbound.getByteBuffer();
|
||||
synchronized(out_buffer)
|
||||
{
|
||||
try
|
||||
{
|
||||
bbuf.position(buffer.getIndex());
|
||||
bbuf.limit(buffer.putIndex());
|
||||
out_buffer.position(_outbound.putIndex());
|
||||
out_buffer.limit(out_buffer.capacity());
|
||||
result=_engine.wrap(bbuf,out_buffer);
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("{} wrap {} {} consumed={} produced={}",
|
||||
_session,
|
||||
result.getStatus(),
|
||||
result.getHandshakeStatus(),
|
||||
result.bytesConsumed(),
|
||||
result.bytesProduced());
|
||||
|
||||
|
||||
buffer.skip(result.bytesConsumed());
|
||||
_outbound.setPutIndex(_outbound.putIndex()+result.bytesProduced());
|
||||
}
|
||||
catch(SSLException e)
|
||||
{
|
||||
LOG.warn(_endp+":",e);
|
||||
_endp.close();
|
||||
throw e;
|
||||
}
|
||||
finally
|
||||
{
|
||||
out_buffer.position(0);
|
||||
out_buffer.limit(out_buffer.capacity());
|
||||
bbuf.position(0);
|
||||
bbuf.limit(bbuf.capacity());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch(result.getStatus())
|
||||
{
|
||||
case BUFFER_UNDERFLOW:
|
||||
throw new IllegalStateException();
|
||||
|
||||
case BUFFER_OVERFLOW:
|
||||
break;
|
||||
|
||||
case OK:
|
||||
if (result.getHandshakeStatus()==HandshakeStatus.FINISHED)
|
||||
_handshook=true;
|
||||
break;
|
||||
|
||||
case CLOSED:
|
||||
LOG.debug("wrap CLOSE {} {}",this,result);
|
||||
if (result.getHandshakeStatus()==HandshakeStatus.FINISHED)
|
||||
_endp.close();
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG.warn("{} wrap default {}",_session,result);
|
||||
throw new IOException(result.toString());
|
||||
}
|
||||
|
||||
return result.bytesConsumed()>0 || result.bytesProduced()>0;
|
||||
}
|
||||
|
||||
private synchronized boolean unwrap(final Buffer buffer) throws IOException
|
||||
{
|
||||
if (!_inbound.hasContent())
|
||||
return false;
|
||||
|
||||
ByteBuffer bbuf=extractByteBuffer(buffer);
|
||||
final SSLEngineResult result;
|
||||
|
||||
synchronized(bbuf)
|
||||
{
|
||||
ByteBuffer in_buffer=_inbound.getByteBuffer();
|
||||
synchronized(in_buffer)
|
||||
{
|
||||
try
|
||||
{
|
||||
bbuf.position(buffer.putIndex());
|
||||
bbuf.limit(buffer.capacity());
|
||||
in_buffer.position(_inbound.getIndex());
|
||||
in_buffer.limit(_inbound.putIndex());
|
||||
|
||||
result=_engine.unwrap(in_buffer,bbuf);
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("{} unwrap {} {} consumed={} produced={}",
|
||||
_session,
|
||||
result.getStatus(),
|
||||
result.getHandshakeStatus(),
|
||||
result.bytesConsumed(),
|
||||
result.bytesProduced());
|
||||
|
||||
_inbound.skip(result.bytesConsumed());
|
||||
_inbound.compact();
|
||||
buffer.setPutIndex(buffer.putIndex()+result.bytesProduced());
|
||||
}
|
||||
catch(SSLException e)
|
||||
{
|
||||
LOG.warn(_endp+":"+e);
|
||||
LOG.debug(e);
|
||||
if (_endp.isOpen())
|
||||
_endp.close();
|
||||
throw e;
|
||||
}
|
||||
finally
|
||||
{
|
||||
in_buffer.position(0);
|
||||
in_buffer.limit(in_buffer.capacity());
|
||||
bbuf.position(0);
|
||||
bbuf.limit(bbuf.capacity());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch(result.getStatus())
|
||||
{
|
||||
case BUFFER_UNDERFLOW:
|
||||
break;
|
||||
|
||||
case BUFFER_OVERFLOW:
|
||||
LOG.debug("{} unwrap {} {}->{}",_session,result.getStatus(),_inbound.toDetailString(),buffer.toDetailString());
|
||||
break;
|
||||
|
||||
case OK:
|
||||
if (result.getHandshakeStatus()==HandshakeStatus.FINISHED)
|
||||
_handshook=true;
|
||||
break;
|
||||
|
||||
case CLOSED:
|
||||
LOG.debug("unwrap CLOSE {} {}",this,result);
|
||||
if (result.getHandshakeStatus()==HandshakeStatus.FINISHED)
|
||||
_endp.close();
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG.warn("{} wrap default {}",_session,result);
|
||||
throw new IOException(result.toString());
|
||||
}
|
||||
|
||||
//if (LOG.isDebugEnabled() && result.bytesProduced()>0)
|
||||
// LOG.debug("{} unwrapped '{}'",_session,buffer);
|
||||
|
||||
return result.bytesConsumed()>0 || result.bytesProduced()>0;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private ByteBuffer extractByteBuffer(Buffer buffer)
|
||||
{
|
||||
if (buffer.buffer() instanceof NIOBuffer)
|
||||
return ((NIOBuffer)buffer.buffer()).getByteBuffer();
|
||||
return ByteBuffer.wrap(buffer.array());
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public AsyncEndPoint getSslEndPoint()
|
||||
{
|
||||
return _sslEndPoint;
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
Buffer i=_inbound;
|
||||
Buffer o=_outbound;
|
||||
Buffer u=_unwrapBuf;
|
||||
|
||||
return super.toString()+"|"+_engine.getHandshakeStatus()+" i/u/o="+(i==null?0:i.length())+"/"+(u==null?0:u.length())+"/"+(o==null?0:o.length());
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------ */
|
||||
public class SslEndPoint implements AsyncEndPoint
|
||||
{
|
||||
public SSLEngine getSslEngine()
|
||||
{
|
||||
return _engine;
|
||||
}
|
||||
|
||||
public SslConnection getSslConnection()
|
||||
{
|
||||
return SslConnection.this;
|
||||
}
|
||||
|
||||
public void shutdownOutput() throws IOException
|
||||
{
|
||||
synchronized (SslConnection.this)
|
||||
{
|
||||
LOG.debug("{} ssl endp.oshut {}",_session,this);
|
||||
_engine.closeOutbound();
|
||||
_oshut=true;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isOutputShutdown()
|
||||
{
|
||||
synchronized (SslConnection.this)
|
||||
{
|
||||
return _oshut||!isOpen()||_engine.isOutboundDone();
|
||||
}
|
||||
}
|
||||
|
||||
public void shutdownInput() throws IOException
|
||||
{
|
||||
LOG.debug("{} ssl endp.ishut!",_session);
|
||||
// We do not do a closeInput here, as SSL does not support half close.
|
||||
// isInputShutdown works it out itself from buffer state and underlying endpoint state.
|
||||
}
|
||||
|
||||
public boolean isInputShutdown()
|
||||
{
|
||||
synchronized (SslConnection.this)
|
||||
{
|
||||
return _endp.isInputShutdown() &&
|
||||
!(_unwrapBuf!=null&&_unwrapBuf.hasContent()) &&
|
||||
!(_inbound!=null&&_inbound.hasContent());
|
||||
}
|
||||
}
|
||||
|
||||
public void close() throws IOException
|
||||
{
|
||||
LOG.debug("{} ssl endp.close",_session);
|
||||
_endp.close();
|
||||
}
|
||||
|
||||
public int fill(Buffer buffer) throws IOException
|
||||
{
|
||||
int size=buffer.length();
|
||||
process(buffer,null);
|
||||
|
||||
int filled=buffer.length()-size;
|
||||
|
||||
if (filled==0 && isInputShutdown())
|
||||
return -1;
|
||||
return filled;
|
||||
}
|
||||
|
||||
public int flush(Buffer buffer) throws IOException
|
||||
{
|
||||
int size=buffer.length();
|
||||
process(null,buffer);
|
||||
int flushed=size-buffer.length();
|
||||
return flushed;
|
||||
}
|
||||
|
||||
public int flush(Buffer header, Buffer buffer, Buffer trailer) throws IOException
|
||||
{
|
||||
if (header!=null && header.hasContent())
|
||||
return flush(header);
|
||||
if (buffer!=null && buffer.hasContent())
|
||||
return flush(buffer);
|
||||
if (trailer!=null && trailer.hasContent())
|
||||
return flush(trailer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
public boolean blockReadable(long millisecs) throws IOException
|
||||
{
|
||||
long now = System.currentTimeMillis();
|
||||
long end=millisecs>0?(now+millisecs):Long.MAX_VALUE;
|
||||
|
||||
while (now<end)
|
||||
{
|
||||
process(null,null);
|
||||
synchronized (SslConnection.this)
|
||||
{
|
||||
if (_unwrapBuf!=null && _unwrapBuf.hasContent())
|
||||
break;
|
||||
if (_inbound!=null && _inbound.hasContent())
|
||||
break;
|
||||
}
|
||||
_endp.blockReadable(end-now);
|
||||
now = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
return now<end;
|
||||
}
|
||||
|
||||
public boolean blockWritable(long millisecs) throws IOException
|
||||
{
|
||||
return _endp.blockWritable(millisecs);
|
||||
}
|
||||
|
||||
public boolean isOpen()
|
||||
{
|
||||
return _endp.isOpen();
|
||||
}
|
||||
|
||||
public Object getTransport()
|
||||
{
|
||||
return _endp;
|
||||
}
|
||||
|
||||
public void flush() throws IOException
|
||||
{
|
||||
process(null,null);
|
||||
}
|
||||
|
||||
public void asyncDispatch()
|
||||
{
|
||||
_aEndp.asyncDispatch();
|
||||
}
|
||||
|
||||
public void scheduleWrite()
|
||||
{
|
||||
_aEndp.scheduleWrite();
|
||||
}
|
||||
|
||||
public void scheduleIdle()
|
||||
{
|
||||
_aEndp.scheduleIdle();
|
||||
}
|
||||
|
||||
public void cancelIdle()
|
||||
{
|
||||
_aEndp.cancelIdle();
|
||||
}
|
||||
|
||||
public void scheduleTimeout(Task task, long timeoutMs)
|
||||
{
|
||||
_aEndp.scheduleTimeout(task,timeoutMs);
|
||||
}
|
||||
|
||||
public void cancelTimeout(Task task)
|
||||
{
|
||||
_aEndp.cancelTimeout(task);
|
||||
}
|
||||
|
||||
public boolean isWritable()
|
||||
{
|
||||
return _aEndp.isWritable();
|
||||
}
|
||||
|
||||
public boolean hasProgressed()
|
||||
{
|
||||
return _progressed.getAndSet(false);
|
||||
}
|
||||
|
||||
public String getLocalAddr()
|
||||
{
|
||||
return _aEndp.getLocalAddr();
|
||||
}
|
||||
|
||||
public String getLocalHost()
|
||||
{
|
||||
return _aEndp.getLocalHost();
|
||||
}
|
||||
|
||||
public int getLocalPort()
|
||||
{
|
||||
return _aEndp.getLocalPort();
|
||||
}
|
||||
|
||||
public String getRemoteAddr()
|
||||
{
|
||||
return _aEndp.getRemoteAddr();
|
||||
}
|
||||
|
||||
public String getRemoteHost()
|
||||
{
|
||||
return _aEndp.getRemoteHost();
|
||||
}
|
||||
|
||||
public int getRemotePort()
|
||||
{
|
||||
return _aEndp.getRemotePort();
|
||||
}
|
||||
|
||||
public boolean isBlocking()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public int getMaxIdleTime()
|
||||
{
|
||||
return _aEndp.getMaxIdleTime();
|
||||
}
|
||||
|
||||
public void setMaxIdleTime(int timeMs) throws IOException
|
||||
{
|
||||
_aEndp.setMaxIdleTime(timeMs);
|
||||
}
|
||||
|
||||
public Connection getConnection()
|
||||
{
|
||||
return _connection;
|
||||
}
|
||||
|
||||
public void setConnection(Connection connection)
|
||||
{
|
||||
_connection=(AsyncConnection)connection;
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
Buffer i;
|
||||
Buffer o;
|
||||
Buffer u;
|
||||
|
||||
synchronized(SslConnection.this)
|
||||
{
|
||||
i=_inbound;
|
||||
o=_outbound;
|
||||
u=_unwrapBuf;
|
||||
}
|
||||
return "SSL:"+_endp+" "+_engine.getHandshakeStatus()+" i/u/o="+(i==null?0:i.length())+"/"+(u==null?0:u.length())+"/"+(o==null?0:o.length()+(_oshut?" oshut":""));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,734 +0,0 @@
|
|||
// ========================================================================
|
||||
// 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 java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.SelectionKey;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import javax.net.ssl.SSLEngineResult;
|
||||
import javax.net.ssl.SSLEngineResult.HandshakeStatus;
|
||||
import javax.net.ssl.SSLException;
|
||||
import javax.net.ssl.SSLSession;
|
||||
|
||||
import org.eclipse.jetty.io.Buffer;
|
||||
import org.eclipse.jetty.io.Buffers;
|
||||
import org.eclipse.jetty.io.EofException;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* SslSelectChannelEndPoint
|
||||
* <p>
|
||||
* A SelectChannelEndPoint that uses an {@link SSLEngine} to handle an
|
||||
* SSL connection.
|
||||
* <p>
|
||||
* There is a named logger "org.eclipse.jetty.http.ssl"
|
||||
* </p>
|
||||
*/
|
||||
public class SslSelectChannelEndPoint extends SelectChannelEndPoint
|
||||
{
|
||||
public static final Logger LOG=Log.getLogger("org.eclipse.jetty.io.nio").getLogger("ssl");
|
||||
|
||||
private static final Buffer __EMPTY_BUFFER=new DirectNIOBuffer(0);
|
||||
private static final ByteBuffer __ZERO_BUFFER=ByteBuffer.allocate(0);
|
||||
|
||||
private final Buffers _buffers;
|
||||
|
||||
private final SSLEngine _engine;
|
||||
private final SSLSession _session;
|
||||
private volatile NIOBuffer _inNIOBuffer;
|
||||
private volatile NIOBuffer _outNIOBuffer;
|
||||
|
||||
private boolean _closing=false;
|
||||
private SSLEngineResult _result;
|
||||
|
||||
private volatile boolean _handshook=false;
|
||||
private boolean _allowRenegotiate=true;
|
||||
|
||||
private volatile boolean _debug = LOG.isDebugEnabled(); // snapshot debug status for optimizer
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public SslSelectChannelEndPoint(Buffers buffers,SocketChannel channel, SelectorManager.SelectSet selectSet, SelectionKey key, SSLEngine engine, int maxIdleTime)
|
||||
throws IOException
|
||||
{
|
||||
super(channel,selectSet,key, maxIdleTime);
|
||||
_buffers=buffers;
|
||||
|
||||
// ssl
|
||||
_engine=engine;
|
||||
_session=engine.getSession();
|
||||
|
||||
if (_debug)
|
||||
LOG.debug(_session+" channel="+channel);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public SslSelectChannelEndPoint(Buffers buffers,SocketChannel channel, SelectorManager.SelectSet selectSet, SelectionKey key, SSLEngine engine)
|
||||
throws IOException
|
||||
{
|
||||
super(channel,selectSet,key);
|
||||
_buffers=buffers;
|
||||
|
||||
// ssl
|
||||
_engine=engine;
|
||||
_session=engine.getSession();
|
||||
|
||||
if (_debug)
|
||||
LOG.debug(_session+" channel="+channel);
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private void needOutBuffer()
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
if (_outNIOBuffer==null)
|
||||
_outNIOBuffer=(NIOBuffer)_buffers.getBuffer(_session.getPacketBufferSize());
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private void freeOutBuffer()
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
if (_outNIOBuffer!=null && _outNIOBuffer.length()==0)
|
||||
{
|
||||
_buffers.returnBuffer(_outNIOBuffer);
|
||||
_outNIOBuffer=null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private void needInBuffer()
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
if(_inNIOBuffer==null)
|
||||
_inNIOBuffer=(NIOBuffer)_buffers.getBuffer(_session.getPacketBufferSize());
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private void freeInBuffer()
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
if (_inNIOBuffer!=null && _inNIOBuffer.length()==0)
|
||||
{
|
||||
_buffers.returnBuffer(_inNIOBuffer);
|
||||
_inNIOBuffer=null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @return True if the endpoint has produced/consumed bytes itself (non application data).
|
||||
*/
|
||||
public boolean isProgressing()
|
||||
{
|
||||
SSLEngineResult result = _result;
|
||||
_result=null;
|
||||
return result!=null && (result.bytesConsumed()>0 || result.bytesProduced()>0);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @return True if SSL re-negotiation is allowed (default false)
|
||||
*/
|
||||
public boolean isAllowRenegotiate()
|
||||
{
|
||||
return _allowRenegotiate;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Set if SSL re-negotiation is allowed. CVE-2009-3555 discovered
|
||||
* a vulnerability in SSL/TLS with re-negotiation. If your JVM
|
||||
* does not have CVE-2009-3555 fixed, then re-negotiation should
|
||||
* not be allowed.
|
||||
* @param allowRenegotiate true if re-negotiation is allowed (default false)
|
||||
*/
|
||||
public void setAllowRenegotiate(boolean allowRenegotiate)
|
||||
{
|
||||
_allowRenegotiate = allowRenegotiate;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public boolean isOutputShutdown()
|
||||
{
|
||||
return _engine!=null && _engine.isOutboundDone();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public boolean isInputShutdown()
|
||||
{
|
||||
return _engine!=null && _engine.isInboundDone();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public void shutdownOutput() throws IOException
|
||||
{
|
||||
LOG.debug("{} shutdownOutput",_session);
|
||||
// All SSL closes should be graceful, as it is more secure.
|
||||
// So normal SSL close can be used here.
|
||||
close();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private int process(ByteBuffer inBBuf, Buffer outBuf) throws IOException
|
||||
{
|
||||
if (_debug)
|
||||
LOG.debug("{} process closing={} in={} out={}",_session,_closing,inBBuf,outBuf);
|
||||
|
||||
// If there is no place to put incoming application data,
|
||||
if (inBBuf==null)
|
||||
{
|
||||
// use ZERO buffer
|
||||
inBBuf=__ZERO_BUFFER;
|
||||
}
|
||||
|
||||
int received=0;
|
||||
int sent=0;
|
||||
|
||||
|
||||
HandshakeStatus initialStatus = _engine.getHandshakeStatus();
|
||||
boolean progress=true;
|
||||
|
||||
while (progress)
|
||||
{
|
||||
progress=false;
|
||||
|
||||
// flush output data
|
||||
int len=_outNIOBuffer==null?0:_outNIOBuffer.length();
|
||||
|
||||
// we must flush it, as the other end might be
|
||||
// waiting for that outgoing data before sending
|
||||
// more incoming data
|
||||
flush();
|
||||
|
||||
// If we have written some bytes, then progress has been made.
|
||||
progress|=(_outNIOBuffer==null?0:_outNIOBuffer.length())<len;
|
||||
|
||||
// handle the current hand share status
|
||||
if (_debug) LOG.debug("status {} {}",_engine,_engine.getHandshakeStatus());
|
||||
switch(_engine.getHandshakeStatus())
|
||||
{
|
||||
case FINISHED:
|
||||
throw new IllegalStateException();
|
||||
|
||||
case NOT_HANDSHAKING:
|
||||
|
||||
// If closing, don't process application data
|
||||
if (_closing)
|
||||
{
|
||||
if (outBuf!=null && outBuf.hasContent())
|
||||
{
|
||||
LOG.debug("Write while closing");
|
||||
outBuf.clear();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Try wrapping some application data
|
||||
if (outBuf!=null && outBuf.hasContent())
|
||||
{
|
||||
int c=wrap(outBuf);
|
||||
progress=c>0||_result.bytesProduced()>0||_result.bytesConsumed()>0;
|
||||
|
||||
if (c>0)
|
||||
sent+=c;
|
||||
else if (c<0 && sent==0)
|
||||
sent=-1;
|
||||
}
|
||||
|
||||
// Try unwrapping some application data
|
||||
if (inBBuf.remaining()>0 && _inNIOBuffer!=null && _inNIOBuffer.hasContent())
|
||||
{
|
||||
int space=inBBuf.remaining();
|
||||
progress|=unwrap(inBBuf);
|
||||
received+=space-inBBuf.remaining();
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case NEED_TASK:
|
||||
{
|
||||
// A task needs to be run, so run it!
|
||||
Runnable task;
|
||||
while ((task=_engine.getDelegatedTask())!=null)
|
||||
{
|
||||
progress=true;
|
||||
task.run();
|
||||
}
|
||||
|
||||
// Detect SUN JVM Bug!!!
|
||||
if(initialStatus==HandshakeStatus.NOT_HANDSHAKING &&
|
||||
_engine.getHandshakeStatus()==HandshakeStatus.NEED_UNWRAP && sent==0)
|
||||
{
|
||||
// This should be NEED_WRAP
|
||||
// The fix simply detects the signature of the bug and then close the connection (fail-fast) so that ff3 will delegate to using SSL instead of TLS.
|
||||
// This is a jvm bug on java1.6 where the SSLEngine expects more data from the initial handshake when the client(ff3-tls) already had given it.
|
||||
// See http://jira.codehaus.org/browse/JETTY-567 for more details
|
||||
if (_debug) LOG.warn("{} JETTY-567",_session);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case NEED_WRAP:
|
||||
{
|
||||
checkRenegotiate();
|
||||
|
||||
// The SSL needs to send some handshake data to the other side
|
||||
int c=0;
|
||||
if (outBuf!=null && outBuf.hasContent())
|
||||
c=wrap(outBuf);
|
||||
else
|
||||
c=wrap(__EMPTY_BUFFER);
|
||||
|
||||
progress=_result.bytesProduced()>0||_result.bytesConsumed()>0;
|
||||
if (c>0)
|
||||
sent+=c;
|
||||
else if (c<0 && sent==0)
|
||||
sent=-1;
|
||||
break;
|
||||
}
|
||||
|
||||
case NEED_UNWRAP:
|
||||
{
|
||||
checkRenegotiate();
|
||||
|
||||
// Need more data to be unwrapped so try another call to unwrap
|
||||
progress|=unwrap(inBBuf);
|
||||
if (_closing && inBBuf.hasRemaining())
|
||||
inBBuf.clear();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (_debug) LOG.debug("{} progress {}",_session,progress);
|
||||
}
|
||||
|
||||
if (_debug) LOG.debug("{} received {} sent {}",_session,received,sent);
|
||||
|
||||
freeInBuffer();
|
||||
return (received<0||sent<0)?-1:(received+sent);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public void close() throws IOException
|
||||
{
|
||||
// For safety we always force a close calling super
|
||||
try
|
||||
{
|
||||
if (!_closing)
|
||||
{
|
||||
_closing=true;
|
||||
LOG.debug("{} close",_session);
|
||||
_engine.closeOutbound();
|
||||
process(null,null);
|
||||
}
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
// We could not write the SSL close message because the
|
||||
// socket was already closed, nothing more we can do.
|
||||
LOG.ignore(e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
super.close();
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Fill the buffer with unencrypted bytes.
|
||||
* Called by a Http Parser when more data is
|
||||
* needed to continue parsing a request or a response.
|
||||
*/
|
||||
@Override
|
||||
public int fill(Buffer buffer) throws IOException
|
||||
{
|
||||
_debug=LOG.isDebugEnabled();
|
||||
LOG.debug("{} fill",_session);
|
||||
// This end point only works on NIO buffer type (director
|
||||
// or indirect), so extract the NIO buffer that is wrapped
|
||||
// by the passed jetty Buffer.
|
||||
ByteBuffer bbuf=((NIOBuffer)buffer).getByteBuffer();
|
||||
|
||||
|
||||
// remember the original size of the unencrypted buffer
|
||||
int size=buffer.length();
|
||||
|
||||
|
||||
synchronized (bbuf)
|
||||
{
|
||||
bbuf.position(buffer.putIndex());
|
||||
try
|
||||
{
|
||||
// Call the SSLEngine unwrap method to process data in
|
||||
// the inBuffer. If there is no data in the inBuffer, then
|
||||
// super.fill is called to read encrypted bytes.
|
||||
unwrap(bbuf);
|
||||
process(bbuf,null);
|
||||
}
|
||||
finally
|
||||
{
|
||||
// reset the Buffers
|
||||
buffer.setPutIndex(bbuf.position());
|
||||
bbuf.position(0);
|
||||
}
|
||||
}
|
||||
// return the number of unencrypted bytes filled.
|
||||
int filled=buffer.length()-size;
|
||||
if (filled==0 && (isInputShutdown() || !isOpen()))
|
||||
return -1;
|
||||
|
||||
return filled;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public int flush(Buffer buffer) throws IOException
|
||||
{
|
||||
_debug=LOG.isDebugEnabled();
|
||||
LOG.debug("{} flush1",_session);
|
||||
return process(null,buffer);
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/*
|
||||
*/
|
||||
@Override
|
||||
public int flush(Buffer header, Buffer buffer, Buffer trailer) throws IOException
|
||||
{
|
||||
_debug=LOG.isDebugEnabled();
|
||||
LOG.debug("{} flush3",_session);
|
||||
|
||||
int len=0;
|
||||
int flushed=0;
|
||||
if (header!=null && header.hasContent())
|
||||
{
|
||||
len=header.length();
|
||||
flushed=flush(header);
|
||||
}
|
||||
if (flushed==len && buffer!=null && buffer.hasContent())
|
||||
{
|
||||
int f=flush(buffer);
|
||||
if (f>=0)
|
||||
flushed+=f;
|
||||
else if (flushed==0)
|
||||
flushed=-1;
|
||||
}
|
||||
|
||||
return flushed;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public void flush() throws IOException
|
||||
{
|
||||
LOG.debug("{} flush",_session);
|
||||
if (!isOpen())
|
||||
throw new EofException();
|
||||
|
||||
if (isBufferingOutput())
|
||||
{
|
||||
int flushed=super.flush(_outNIOBuffer);
|
||||
if (_debug)
|
||||
LOG.debug("{} flushed={} left={}",_session,flushed,_outNIOBuffer.length());
|
||||
}
|
||||
else if (_engine.isOutboundDone() && super.isOpen())
|
||||
{
|
||||
if (_debug)
|
||||
LOG.debug("{} flush shutdownOutput",_session);
|
||||
try
|
||||
{
|
||||
super.shutdownOutput();
|
||||
}
|
||||
catch(IOException e)
|
||||
{
|
||||
LOG.ignore(e);
|
||||
}
|
||||
}
|
||||
|
||||
freeOutBuffer();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private void checkRenegotiate() throws IOException
|
||||
{
|
||||
if (_handshook && !_allowRenegotiate && _channel!=null && _channel.isOpen())
|
||||
{
|
||||
LOG.warn("SSL renegotiate denied: {}",_channel);
|
||||
super.close();
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @return true if progress is made
|
||||
*/
|
||||
private boolean unwrap(ByteBuffer buffer) throws IOException
|
||||
{
|
||||
needInBuffer();
|
||||
ByteBuffer in_buffer=_inNIOBuffer.getByteBuffer();
|
||||
|
||||
_inNIOBuffer.compact();
|
||||
|
||||
int total_filled=0;
|
||||
boolean remoteClosed = false;
|
||||
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("{} unwrap space={} open={}",_session,_inNIOBuffer.space(),super.isOpen());
|
||||
|
||||
// loop filling as much encrypted data as we can into the buffer
|
||||
while (_inNIOBuffer.space()>0 && super.isOpen())
|
||||
{
|
||||
int filled=super.fill(_inNIOBuffer);
|
||||
if (_debug) LOG.debug("{} filled {}",_session,filled);
|
||||
if (filled < 0)
|
||||
remoteClosed = true;
|
||||
// break the loop if no progress is made (we have read everything there is to read)
|
||||
if (filled<=0)
|
||||
break;
|
||||
total_filled+=filled;
|
||||
}
|
||||
|
||||
// If we have no progress and no data
|
||||
if (total_filled==0 && _inNIOBuffer.length()==0)
|
||||
{
|
||||
// Do we need to close?
|
||||
if (isOpen() && remoteClosed)
|
||||
{
|
||||
try
|
||||
{
|
||||
_engine.closeInbound();
|
||||
}
|
||||
catch (SSLException x)
|
||||
{
|
||||
// It may happen, for example, in case of truncation
|
||||
// attacks, we close so that we do not spin forever
|
||||
super.close();
|
||||
}
|
||||
}
|
||||
|
||||
if (!isOpen())
|
||||
throw new EofException();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// We have some in data, so try to unwrap it.
|
||||
try
|
||||
{
|
||||
// inBuffer is the NIO buffer inside the _inNIOBuffer,
|
||||
// so update its position and limit from the inNIOBuffer.
|
||||
in_buffer.position(_inNIOBuffer.getIndex());
|
||||
in_buffer.limit(_inNIOBuffer.putIndex());
|
||||
|
||||
// Do the unwrap
|
||||
_result=_engine.unwrap(in_buffer,buffer);
|
||||
if (!_handshook && _result.getHandshakeStatus()==SSLEngineResult.HandshakeStatus.FINISHED)
|
||||
_handshook=true;
|
||||
if (_debug) LOG.debug("{} unwrap {}",_session,_result);
|
||||
|
||||
// skip the bytes consumed
|
||||
_inNIOBuffer.skip(_result.bytesConsumed());
|
||||
}
|
||||
catch(SSLException e)
|
||||
{
|
||||
LOG.debug(getRemoteAddr() + ":" + getRemotePort() + " ",e);
|
||||
super.close();
|
||||
throw e;
|
||||
}
|
||||
finally
|
||||
{
|
||||
// reset the buffer so it can be managed by the _inNIOBuffer again.
|
||||
in_buffer.position(0);
|
||||
in_buffer.limit(in_buffer.capacity());
|
||||
}
|
||||
|
||||
// handle the unwrap results
|
||||
switch(_result.getStatus())
|
||||
{
|
||||
case BUFFER_OVERFLOW:
|
||||
LOG.debug("{} unwrap overflow",_session);
|
||||
return false;
|
||||
|
||||
case BUFFER_UNDERFLOW:
|
||||
// Not enough data,
|
||||
// If we are closed, we will never get more, so EOF
|
||||
// else return and we will be tried again
|
||||
// later when more data arriving causes another dispatch.
|
||||
if (LOG.isDebugEnabled()) LOG.debug("{} unwrap {}",_session,_result);
|
||||
if(!isOpen())
|
||||
{
|
||||
_inNIOBuffer.clear();
|
||||
if (_outNIOBuffer!=null)
|
||||
_outNIOBuffer.clear();
|
||||
throw new EofException();
|
||||
}
|
||||
return (total_filled > 0);
|
||||
|
||||
case CLOSED:
|
||||
_closing=true;
|
||||
// return true is some bytes somewhere were moved about.
|
||||
return total_filled>0 ||_result.bytesConsumed()>0 || _result.bytesProduced()>0;
|
||||
|
||||
case OK:
|
||||
// return true is some bytes somewhere were moved about.
|
||||
return total_filled>0 ||_result.bytesConsumed()>0 || _result.bytesProduced()>0;
|
||||
|
||||
default:
|
||||
LOG.warn("{} unwrap default: {}",_session,_result);
|
||||
throw new IOException(_result.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private ByteBuffer extractOutputBuffer(Buffer buffer)
|
||||
{
|
||||
if (buffer.buffer() instanceof NIOBuffer)
|
||||
return ((NIOBuffer)buffer.buffer()).getByteBuffer();
|
||||
|
||||
return ByteBuffer.wrap(buffer.array());
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private int wrap(final Buffer buffer) throws IOException
|
||||
{
|
||||
ByteBuffer bbuf=extractOutputBuffer(buffer);
|
||||
synchronized(bbuf)
|
||||
{
|
||||
int consumed=0;
|
||||
needOutBuffer();
|
||||
_outNIOBuffer.compact();
|
||||
ByteBuffer out_buffer=_outNIOBuffer.getByteBuffer();
|
||||
synchronized(out_buffer)
|
||||
{
|
||||
try
|
||||
{
|
||||
bbuf.position(buffer.getIndex());
|
||||
bbuf.limit(buffer.putIndex());
|
||||
out_buffer.position(_outNIOBuffer.putIndex());
|
||||
out_buffer.limit(out_buffer.capacity());
|
||||
_result=_engine.wrap(bbuf,out_buffer);
|
||||
if (_debug)
|
||||
LOG.debug("{} wrap {}",_session,_result);
|
||||
if (!_handshook && _result.getHandshakeStatus()==SSLEngineResult.HandshakeStatus.FINISHED)
|
||||
_handshook=true;
|
||||
_outNIOBuffer.setPutIndex(out_buffer.position());
|
||||
consumed=_result.bytesConsumed();
|
||||
}
|
||||
catch(SSLException e)
|
||||
{
|
||||
LOG.warn(getRemoteAddr()+":"+getRemotePort()+" ",e);
|
||||
if (getChannel().isOpen())
|
||||
getChannel().close();
|
||||
throw e;
|
||||
}
|
||||
finally
|
||||
{
|
||||
out_buffer.position(0);
|
||||
bbuf.position(0);
|
||||
bbuf.limit(bbuf.capacity());
|
||||
|
||||
if (consumed>0)
|
||||
{
|
||||
int len=consumed<buffer.length()?consumed:buffer.length();
|
||||
buffer.skip(len);
|
||||
consumed-=len;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
switch(_result.getStatus())
|
||||
{
|
||||
case BUFFER_UNDERFLOW:
|
||||
throw new IllegalStateException();
|
||||
|
||||
case BUFFER_OVERFLOW:
|
||||
LOG.debug("{} wrap {}",_session,_result);
|
||||
flush();
|
||||
return 0;
|
||||
|
||||
case OK:
|
||||
return _result.bytesConsumed();
|
||||
case CLOSED:
|
||||
_closing=true;
|
||||
return _result.bytesConsumed()>0?_result.bytesConsumed():-1;
|
||||
|
||||
default:
|
||||
LOG.warn("{} wrap default {}",_session,_result);
|
||||
throw new IOException(_result.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public boolean isBufferingInput()
|
||||
{
|
||||
final Buffer in = _inNIOBuffer;
|
||||
return in!=null && in.hasContent();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public boolean isBufferingOutput()
|
||||
{
|
||||
final NIOBuffer out = _outNIOBuffer;
|
||||
return out!=null && out.hasContent();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public boolean isBufferred()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public SSLEngine getSSLEngine()
|
||||
{
|
||||
return _engine;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
final NIOBuffer i=_inNIOBuffer;
|
||||
final NIOBuffer o=_outNIOBuffer;
|
||||
return "SSL"+super.toString()+","+(_engine==null?"-":_engine.getHandshakeStatus())+", in/out="+
|
||||
(i==null?0:i.length())+"/"+(o==null?0:o.length())+
|
||||
" bi/o="+isBufferingInput()+"/"+isBufferingOutput()+
|
||||
" "+_result;
|
||||
}
|
||||
}
|
|
@ -1,62 +1,143 @@
|
|||
package org.eclipse.jetty.io;
|
||||
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.util.concurrent.Exchanger;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import org.eclipse.jetty.io.bio.SocketEndPoint;
|
||||
import org.eclipse.jetty.io.nio.IndirectNIOBuffer;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class EndPointTest
|
||||
public abstract class EndPointTest<T extends EndPoint>
|
||||
{
|
||||
public static class EndPointPair<T>
|
||||
{
|
||||
public T client;
|
||||
public T server;
|
||||
}
|
||||
|
||||
protected abstract EndPointPair<T> newConnection() throws Exception;
|
||||
|
||||
|
||||
@Test
|
||||
public void testSocketEndPoints() throws Exception
|
||||
public void testClientServerExchange() throws Exception
|
||||
{
|
||||
final ServerSocket server = new ServerSocket();
|
||||
server.bind(null);
|
||||
EndPointPair<T> c = newConnection();
|
||||
Buffer buffer = new IndirectNIOBuffer(4096);
|
||||
|
||||
final Exchanger<Socket> accepted = new Exchanger<Socket>();
|
||||
new Thread(){
|
||||
public void run()
|
||||
{
|
||||
try
|
||||
{
|
||||
accepted.exchange(server.accept());
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}.start();
|
||||
c.client.flush(new ByteArrayBuffer("request"));
|
||||
int len = c.server.fill(buffer);
|
||||
assertEquals(7,len);
|
||||
assertEquals("request",buffer.toString());
|
||||
|
||||
assertTrue(c.client.isOpen());
|
||||
assertFalse(c.client.isInputShutdown());
|
||||
assertFalse(c.client.isOutputShutdown());
|
||||
assertTrue(c.server.isOpen());
|
||||
assertFalse(c.server.isInputShutdown());
|
||||
assertFalse(c.server.isOutputShutdown());
|
||||
|
||||
Socket s0 = new Socket(server.getInetAddress(),server.getLocalPort());
|
||||
Socket s1 = accepted.exchange(null,5,TimeUnit.SECONDS);
|
||||
c.server.flush(new ByteArrayBuffer("response"));
|
||||
c.server.shutdownOutput();
|
||||
|
||||
SocketEndPoint in = new SocketEndPoint(s0);
|
||||
SocketEndPoint out = new SocketEndPoint(s1);
|
||||
assertTrue(c.client.isOpen());
|
||||
assertFalse(c.client.isInputShutdown());
|
||||
assertFalse(c.client.isOutputShutdown());
|
||||
assertTrue(c.server.isOpen());
|
||||
assertFalse(c.server.isInputShutdown());
|
||||
assertTrue(c.server.isOutputShutdown());
|
||||
|
||||
buffer.clear();
|
||||
len = c.client.fill(buffer);
|
||||
assertEquals(8,len);
|
||||
assertEquals("response",buffer.toString());
|
||||
|
||||
assertTrue(c.client.isOpen());
|
||||
assertFalse(c.client.isInputShutdown());
|
||||
assertFalse(c.client.isOutputShutdown());
|
||||
assertTrue(c.server.isOpen());
|
||||
assertFalse(c.server.isInputShutdown());
|
||||
assertTrue(c.server.isOutputShutdown());
|
||||
|
||||
buffer.clear();
|
||||
len = c.client.fill(buffer);
|
||||
assertEquals(-1,len);
|
||||
|
||||
assertTrue(c.client.isOpen());
|
||||
assertTrue(c.client.isInputShutdown());
|
||||
assertFalse(c.client.isOutputShutdown());
|
||||
assertTrue(c.server.isOpen());
|
||||
assertFalse(c.server.isInputShutdown());
|
||||
assertTrue(c.server.isOutputShutdown());
|
||||
|
||||
c.client.shutdownOutput();
|
||||
|
||||
assertFalse(c.client.isOpen());
|
||||
assertTrue(c.client.isInputShutdown());
|
||||
assertTrue(c.client.isOutputShutdown());
|
||||
assertTrue(c.server.isOpen());
|
||||
assertFalse(c.server.isInputShutdown());
|
||||
assertTrue(c.server.isOutputShutdown());
|
||||
|
||||
buffer.clear();
|
||||
len = c.server.fill(buffer);
|
||||
assertEquals(-1,len);
|
||||
|
||||
assertFalse(c.client.isOpen());
|
||||
assertTrue(c.client.isInputShutdown());
|
||||
assertTrue(c.client.isOutputShutdown());
|
||||
assertFalse(c.server.isOpen());
|
||||
assertTrue(c.server.isInputShutdown());
|
||||
assertTrue(c.server.isOutputShutdown());
|
||||
|
||||
check(in,out);
|
||||
}
|
||||
|
||||
|
||||
private void check(EndPoint in, EndPoint out) throws Exception
|
||||
|
||||
|
||||
@Test
|
||||
public void testClientClose() throws Exception
|
||||
{
|
||||
String data="Now is the time for all good men to come to the aid of the party";
|
||||
Buffer send = new ByteArrayBuffer(data);
|
||||
Buffer receive = new IndirectNIOBuffer(4096);
|
||||
EndPointPair<T> c = newConnection();
|
||||
Buffer buffer = new IndirectNIOBuffer(4096);
|
||||
|
||||
int lo=out.flush(send);
|
||||
int li=in.fill(receive);
|
||||
c.client.flush(new ByteArrayBuffer("request"));
|
||||
int len = c.server.fill(buffer);
|
||||
assertEquals(7,len);
|
||||
assertEquals("request",buffer.toString());
|
||||
|
||||
assertTrue(c.client.isOpen());
|
||||
assertFalse(c.client.isInputShutdown());
|
||||
assertFalse(c.client.isOutputShutdown());
|
||||
assertTrue(c.server.isOpen());
|
||||
assertFalse(c.server.isInputShutdown());
|
||||
assertFalse(c.server.isOutputShutdown());
|
||||
|
||||
Assert.assertEquals(data.length(),lo);
|
||||
Assert.assertEquals(data.length(),li);
|
||||
Assert.assertEquals(data,receive.toString());
|
||||
c.client.close();
|
||||
|
||||
assertFalse(c.client.isOpen());
|
||||
assertTrue(c.client.isInputShutdown());
|
||||
assertTrue(c.client.isOutputShutdown());
|
||||
assertTrue(c.server.isOpen());
|
||||
assertFalse(c.server.isInputShutdown());
|
||||
assertFalse(c.server.isOutputShutdown());
|
||||
|
||||
in.close();
|
||||
out.close();
|
||||
}
|
||||
len = c.server.fill(buffer);
|
||||
assertEquals(-1,len);
|
||||
|
||||
assertFalse(c.client.isOpen());
|
||||
assertTrue(c.client.isInputShutdown());
|
||||
assertTrue(c.client.isOutputShutdown());
|
||||
assertTrue(c.server.isOpen());
|
||||
assertTrue(c.server.isInputShutdown());
|
||||
assertFalse(c.server.isOutputShutdown());
|
||||
|
||||
c.server.shutdownOutput();
|
||||
|
||||
assertFalse(c.client.isOpen());
|
||||
assertTrue(c.client.isInputShutdown());
|
||||
assertTrue(c.client.isOutputShutdown());
|
||||
assertFalse(c.server.isOpen());
|
||||
assertTrue(c.server.isInputShutdown());
|
||||
assertTrue(c.server.isOutputShutdown());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue