Merge remote-tracking branch 'origin/master' into jetty-8
This commit is contained in:
commit
0ba6fc7408
|
@ -73,7 +73,7 @@ public class LikeJettyXml
|
|||
SslSelectChannelConnector ssl_connector = new SslSelectChannelConnector();
|
||||
ssl_connector.setPort(8443);
|
||||
SslContextFactory cf = ssl_connector.getSslContextFactory();
|
||||
cf.setKeyStore(jetty_home + "/etc/keystore");
|
||||
cf.setKeyStorePath(jetty_home + "/etc/keystore");
|
||||
cf.setKeyStorePassword("OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4");
|
||||
cf.setKeyManagerPassword("OBF:1u2u1wml1z7s1z7a1wnl1u2g");
|
||||
cf.setTrustStore(jetty_home + "/etc/keystore");
|
||||
|
|
|
@ -47,7 +47,7 @@ public class ManyConnectors
|
|||
System.setProperty("jetty.home",jetty_home);
|
||||
ssl_connector.setPort(8443);
|
||||
SslContextFactory cf = ssl_connector.getSslContextFactory();
|
||||
cf.setKeyStore(jetty_home + "/etc/keystore");
|
||||
cf.setKeyStorePath(jetty_home + "/etc/keystore");
|
||||
cf.setKeyStorePassword("OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4");
|
||||
cf.setKeyManagerPassword("OBF:1u2u1wml1z7s1z7a1wnl1u2g");
|
||||
|
||||
|
|
|
@ -698,14 +698,14 @@ public class HttpClient extends HttpBuffers implements Attributes, Dumpable
|
|||
@Deprecated
|
||||
public String getKeyStoreLocation()
|
||||
{
|
||||
return _sslContextFactory.getKeyStore();
|
||||
return _sslContextFactory.getKeyStorePath();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Deprecated
|
||||
public void setKeyStoreLocation(String keyStoreLocation)
|
||||
{
|
||||
_sslContextFactory.setKeyStore(keyStoreLocation);
|
||||
_sslContextFactory.setKeyStorePath(keyStoreLocation);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
|
|
|
@ -37,6 +37,7 @@ import org.eclipse.jetty.io.Buffers;
|
|||
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.View;
|
||||
import org.eclipse.jetty.io.nio.SslSelectChannelEndPoint;
|
||||
import org.eclipse.jetty.util.component.AggregateLifeCycle;
|
||||
|
@ -279,7 +280,7 @@ public class HttpConnection extends AbstractConnection implements Dumpable
|
|||
io += filled;
|
||||
|
||||
if (_parser.isIdle() && (_endp.isInputShutdown() || !_endp.isOpen()))
|
||||
throw new EOFException();
|
||||
throw new EofException();
|
||||
}
|
||||
|
||||
if (io > 0)
|
||||
|
|
|
@ -228,6 +228,10 @@ class SelectConnector extends AbstractLifeCycle implements HttpClient.Connector
|
|||
@Override
|
||||
protected void connectionFailed(SocketChannel channel, Throwable ex, Object attachment)
|
||||
{
|
||||
Timeout.Task connectTimeout = _connectingChannels.remove(channel);
|
||||
if (connectTimeout != null)
|
||||
connectTimeout.cancel();
|
||||
|
||||
if (attachment instanceof HttpDestination)
|
||||
((HttpDestination)attachment).onConnectionFailed(ex);
|
||||
else
|
||||
|
|
|
@ -47,7 +47,7 @@ public class ProxyTunnellingTest
|
|||
SslSelectChannelConnector connector = new SslSelectChannelConnector();
|
||||
String keyStorePath = MavenTestingUtils.getTestResourceFile("keystore").getAbsolutePath();
|
||||
SslContextFactory cf = connector.getSslContextFactory();
|
||||
cf.setKeyStore(keyStorePath);
|
||||
cf.setKeyStorePath(keyStorePath);
|
||||
cf.setKeyStorePassword("storepwd");
|
||||
cf.setKeyManagerPassword("keypwd");
|
||||
startServer(connector, handler);
|
||||
|
|
|
@ -58,7 +58,7 @@ public class SslCertSecuredExchangeTest extends ContentExchangeTest
|
|||
cf.setValidateCerts(true);
|
||||
cf.setCrlPath(_crlpath);
|
||||
cf.setNeedClientAuth(true);
|
||||
cf.setKeyStore(_keypath);
|
||||
cf.setKeyStorePath(_keypath);
|
||||
cf.setKeyStorePassword(_password);
|
||||
cf.setKeyManagerPassword(_password);
|
||||
cf.setTrustStore(_trustpath);
|
||||
|
@ -159,7 +159,7 @@ public class SslCertSecuredExchangeTest extends ContentExchangeTest
|
|||
cf.setCrlPath(_crlpath);
|
||||
|
||||
cf.setCertAlias("client");
|
||||
cf.setKeyStore(_clientpath);
|
||||
cf.setKeyStorePath(_clientpath);
|
||||
cf.setKeyStorePassword(_password);
|
||||
cf.setKeyManagerPassword(_password);
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@ public class SslContentExchangeTest
|
|||
SslSelectChannelConnector connector = new SslSelectChannelConnector();
|
||||
File keystore = MavenTestingUtils.getTestResourceFile("keystore");
|
||||
SslContextFactory cf = connector.getSslContextFactory();
|
||||
cf.setKeyStore(keystore.getAbsolutePath());
|
||||
cf.setKeyStorePath(keystore.getAbsolutePath());
|
||||
cf.setKeyStorePassword("storepwd");
|
||||
cf.setKeyManagerPassword("keypwd");
|
||||
cf.setSessionCachingEnabled(true);
|
||||
|
|
|
@ -63,7 +63,7 @@ extends ContentExchangeTest
|
|||
SslSelectChannelConnector connector = new SslSelectChannelConnector();
|
||||
File keystore = MavenTestingUtils.getTestResourceFile("keystore");
|
||||
SslContextFactory cf = connector.getSslContextFactory();
|
||||
cf.setKeyStore(keystore.getAbsolutePath());
|
||||
cf.setKeyStorePath(keystore.getAbsolutePath());
|
||||
cf.setKeyStorePassword("storepwd");
|
||||
cf.setKeyManagerPassword("keypwd");
|
||||
server.addConnector(connector);
|
||||
|
|
|
@ -165,7 +165,7 @@ public class SslSecurityListenerTest
|
|||
|
||||
connector.setPort(0);
|
||||
SslContextFactory cf = connector.getSslContextFactory();
|
||||
cf.setKeyStore(keystore);
|
||||
cf.setKeyStorePath(keystore);
|
||||
cf.setKeyStorePassword("storepwd");
|
||||
cf.setKeyManagerPassword("keypwd");
|
||||
|
||||
|
|
|
@ -52,7 +52,7 @@ public abstract class SslValidationTestBase extends ContentExchangeTest
|
|||
srvFactory.setCrlPath(_crlpath);
|
||||
srvFactory.setNeedClientAuth(true);
|
||||
|
||||
srvFactory.setKeyStore(_keypath);
|
||||
srvFactory.setKeyStorePath(_keypath);
|
||||
srvFactory.setKeyStorePassword(_password);
|
||||
srvFactory.setKeyManagerPassword(_password);
|
||||
|
||||
|
@ -88,7 +88,7 @@ public abstract class SslValidationTestBase extends ContentExchangeTest
|
|||
cf.setValidateCerts(true);
|
||||
cf.setCrlPath(_crlpath);
|
||||
|
||||
cf.setKeyStore(_clientpath);
|
||||
cf.setKeyStorePath(_clientpath);
|
||||
cf.setKeyStorePassword(_password);
|
||||
cf.setKeyManagerPassword(_password);
|
||||
|
||||
|
|
|
@ -42,7 +42,7 @@ public abstract class AbstractSslServerAndClientCreator implements ServerAndClie
|
|||
|
||||
connector.setPort(0);
|
||||
SslContextFactory cf = connector.getSslContextFactory();
|
||||
cf.setKeyStore(keystore);
|
||||
cf.setKeyStorePath(keystore);
|
||||
cf.setKeyStorePassword("storepwd");
|
||||
cf.setKeyManagerPassword("keypwd");
|
||||
connector.setAllowRenegotiate(true);
|
||||
|
|
|
@ -306,7 +306,7 @@ public class HttpParser implements Parser
|
|||
throw ex;
|
||||
|
||||
if (!isComplete() && !isIdle())
|
||||
throw new EOFException();
|
||||
throw new EofException();
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
|
|
@ -177,6 +177,8 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
|
||||
/** SSL context */
|
||||
private SSLContext _context;
|
||||
|
||||
private boolean _trustAll;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
|
@ -185,6 +187,17 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
*/
|
||||
public SslContextFactory()
|
||||
{
|
||||
_trustAll=true;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Construct an instance of SslContextFactory
|
||||
* Default constructor for use in XmlConfiguration files
|
||||
*/
|
||||
public SslContextFactory(boolean trustAll)
|
||||
{
|
||||
_trustAll=trustAll;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -207,29 +220,36 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
{
|
||||
if (_context == null)
|
||||
{
|
||||
if (_keyStoreInputStream == null && _keyStorePath == null &&
|
||||
_trustStoreInputStream == null && _trustStorePath == null )
|
||||
if (_keyStore==null && _keyStoreInputStream == null && _keyStorePath == null &&
|
||||
_trustStore==null && _trustStoreInputStream == null && _trustStorePath == null )
|
||||
{
|
||||
LOG.debug("No keystore or trust store configured. ACCEPTING UNTRUSTED CERTIFICATES!!!!!");
|
||||
// Create a trust manager that does not validate certificate chains
|
||||
TrustManager trustAllCerts = new X509TrustManager()
|
||||
TrustManager[] trust_managers=null;
|
||||
|
||||
if (_trustAll)
|
||||
{
|
||||
public java.security.cert.X509Certificate[] getAcceptedIssuers()
|
||||
LOG.info("No keystore or trust store configured. ACCEPTING UNTRUSTED CERTIFICATES!!!!!");
|
||||
// Create a trust manager that does not validate certificate chains
|
||||
TrustManager trustAllCerts = new X509TrustManager()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
public java.security.cert.X509Certificate[] getAcceptedIssuers()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType)
|
||||
{
|
||||
}
|
||||
|
||||
public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType)
|
||||
{
|
||||
}
|
||||
};
|
||||
public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType)
|
||||
{
|
||||
}
|
||||
|
||||
public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType)
|
||||
{
|
||||
}
|
||||
};
|
||||
trust_managers = new TrustManager[] { trustAllCerts };
|
||||
}
|
||||
|
||||
SecureRandom secureRandom = (_secureRandomAlgorithm == null)?null:SecureRandom.getInstance(_secureRandomAlgorithm);
|
||||
_context = SSLContext.getInstance(_sslProtocol);
|
||||
_context.init(null, new TrustManager[]{trustAllCerts}, null);
|
||||
_context.init(null, trust_managers, secureRandom);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -402,16 +422,36 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
/**
|
||||
* @return The file or URL of the SSL Key store.
|
||||
*/
|
||||
public String getKeyStore()
|
||||
public String getKeyStorePath()
|
||||
{
|
||||
return _keyStorePath;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Deprecated
|
||||
public String getKeyStore()
|
||||
{
|
||||
return _keyStorePath;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param keyStorePath
|
||||
* The file or URL of the SSL Key store.
|
||||
*/
|
||||
public void setKeyStorePath(String keyStorePath)
|
||||
{
|
||||
checkNotStarted();
|
||||
|
||||
_keyStorePath = keyStorePath;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param keyStorePath
|
||||
* @deprecated Use {@link #setKeyStorePath(String)}
|
||||
*/
|
||||
@Deprecated
|
||||
public void setKeyStore(String keyStorePath)
|
||||
{
|
||||
checkNotStarted();
|
||||
|
@ -479,7 +519,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
/** Set the keyStoreInputStream.
|
||||
* @param keyStoreInputStream the InputStream to the KeyStore
|
||||
*
|
||||
* @deprecated
|
||||
* @deprecated Use {@link #setKeyStore(KeyStore)}
|
||||
*/
|
||||
@Deprecated
|
||||
public void setKeyStoreInputStream(InputStream keyStoreInputStream)
|
||||
|
@ -842,7 +882,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
{
|
||||
return (_keyManagerFactoryAlgorithm);
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param algorithm
|
||||
|
@ -864,10 +904,29 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
return (_trustManagerFactoryAlgorithm);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @return True if all certificates should be trusted if there is no KeyStore or TrustStore
|
||||
*/
|
||||
public boolean isTrustAll()
|
||||
{
|
||||
return _trustAll;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param trustAll True if all certificates should be trusted if there is no KeyStore or TrustStore
|
||||
*/
|
||||
public void setTrustAll(boolean trustAll)
|
||||
{
|
||||
_trustAll = trustAll;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param algorithm
|
||||
* The algorithm name (default "SunX509") used by the {@link TrustManagerFactory}
|
||||
* Use the string "TrustAll" to install a trust manager that trusts all.
|
||||
*/
|
||||
public void setTrustManagerFactoryAlgorithm(String algorithm)
|
||||
{
|
||||
|
@ -1039,7 +1098,7 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
|
||||
/* ------------------------------------------------------------ */
|
||||
protected TrustManager[] getTrustManagers(KeyStore trustStore, Collection<? extends CRL> crls) throws Exception
|
||||
{
|
||||
{
|
||||
TrustManager[] managers = null;
|
||||
if (trustStore != null)
|
||||
{
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
package org.eclipse.jetty.http;
|
||||
|
||||
import static junit.framework.Assert.assertTrue;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.security.KeyStore;
|
||||
|
||||
import org.eclipse.jetty.http.ssl.SslContextFactory;
|
||||
import org.junit.Test;
|
||||
|
||||
|
||||
public class SslContextFactoryTest
|
||||
{
|
||||
@Test
|
||||
public void testNoTsFileKs() throws Exception
|
||||
{
|
||||
String keystorePath = System.getProperty("basedir",".") + "/src/test/resources/keystore";
|
||||
SslContextFactory cf = new SslContextFactory(keystorePath);
|
||||
cf.setKeyStorePassword("storepwd");
|
||||
cf.setKeyManagerPassword("keypwd");
|
||||
|
||||
cf.start();
|
||||
|
||||
assertTrue(cf.getSslContext()!=null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoTsStreamKs() throws Exception
|
||||
{
|
||||
String keystorePath = System.getProperty("basedir",".") + "/src/test/resources/keystore";
|
||||
|
||||
SslContextFactory cf = new SslContextFactory();
|
||||
|
||||
cf.setKeyStoreInputStream(new FileInputStream(keystorePath));
|
||||
cf.setKeyStorePassword("storepwd");
|
||||
cf.setKeyManagerPassword("keypwd");
|
||||
|
||||
cf.start();
|
||||
|
||||
assertTrue(cf.getSslContext()!=null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoTsSetKs() throws Exception
|
||||
{
|
||||
String keystorePath = System.getProperty("basedir",".") + "/src/test/resources/keystore";
|
||||
|
||||
KeyStore ks = KeyStore.getInstance("JKS");
|
||||
ks.load(new FileInputStream(keystorePath),"storepwd".toCharArray());
|
||||
|
||||
SslContextFactory cf = new SslContextFactory();
|
||||
cf.setKeyStore(ks);
|
||||
cf.setKeyManagerPassword("keypwd");
|
||||
|
||||
cf.start();
|
||||
|
||||
assertTrue(cf.getSslContext()!=null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoTsNoKs() throws Exception
|
||||
{
|
||||
SslContextFactory cf = new SslContextFactory();
|
||||
cf.start();
|
||||
assertTrue(cf.getSslContext()!=null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTrustAll() throws Exception
|
||||
{
|
||||
SslContextFactory cf = new SslContextFactory();
|
||||
cf.start();
|
||||
assertTrue(cf.getSslContext()!=null);
|
||||
}
|
||||
}
|
Binary file not shown.
|
@ -16,6 +16,7 @@ package org.eclipse.jetty.io.nio;
|
|||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.ByteChannel;
|
||||
import java.nio.channels.GatheringByteChannel;
|
||||
|
@ -129,10 +130,17 @@ public class ChannelEndPoint implements EndPoint
|
|||
Socket socket= ((SocketChannel)_channel).socket();
|
||||
if (!socket.isClosed())
|
||||
{
|
||||
if (socket.isInputShutdown())
|
||||
socket.close();
|
||||
else if (!socket.isOutputShutdown())
|
||||
socket.shutdownOutput();
|
||||
try
|
||||
{
|
||||
if (socket.isInputShutdown())
|
||||
socket.close();
|
||||
else if (!socket.isOutputShutdown())
|
||||
socket.shutdownOutput();
|
||||
}
|
||||
catch(SocketException e)
|
||||
{
|
||||
LOG.ignore(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -561,7 +561,7 @@ public class SslSelectChannelEndPoint extends SelectChannelEndPoint
|
|||
}
|
||||
catch(SSLException e)
|
||||
{
|
||||
LOG.warn(getRemoteAddr() + ":" + getRemotePort() + " ",e);
|
||||
LOG.debug(getRemoteAddr() + ":" + getRemotePort() + " ",e);
|
||||
super.close();
|
||||
throw e;
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@ import org.eclipse.jetty.http.HttpStatus;
|
|||
import org.eclipse.jetty.io.AsyncEndPoint;
|
||||
import org.eclipse.jetty.io.Connection;
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
import org.eclipse.jetty.io.nio.ChannelEndPoint;
|
||||
import org.eclipse.jetty.io.nio.SelectChannelEndPoint;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
@ -16,7 +15,7 @@ public class AsyncHttpConnection extends HttpConnection
|
|||
{
|
||||
private final static int NO_PROGRESS_INFO = Integer.getInteger("org.mortbay.jetty.NO_PROGRESS_INFO",100);
|
||||
private final static int NO_PROGRESS_CLOSE = Integer.getInteger("org.mortbay.jetty.NO_PROGRESS_CLOSE",200);
|
||||
|
||||
|
||||
private static final Logger LOG = Log.getLogger(AsyncHttpConnection.class);
|
||||
private int _total_no_progress;
|
||||
|
||||
|
@ -28,26 +27,26 @@ public class AsyncHttpConnection extends HttpConnection
|
|||
public Connection handle() throws IOException
|
||||
{
|
||||
Connection connection = this;
|
||||
boolean some_progress=false;
|
||||
boolean progress=true;
|
||||
|
||||
boolean some_progress=false;
|
||||
boolean progress=true;
|
||||
|
||||
// Loop while more in buffer
|
||||
try
|
||||
{
|
||||
setCurrentConnection(this);
|
||||
|
||||
boolean more_in_buffer =false;
|
||||
|
||||
|
||||
while (_endp.isOpen() && (more_in_buffer || progress) && connection==this)
|
||||
{
|
||||
progress=false;
|
||||
try
|
||||
{
|
||||
|
||||
|
||||
// Handle resumed request
|
||||
if (_request._async.isAsync() && !_request._async.isComplete())
|
||||
handleRequest();
|
||||
|
||||
|
||||
// else Parse more input
|
||||
else if (!_parser.isComplete() && _parser.parseAvailable()>0)
|
||||
progress=true;
|
||||
|
@ -55,11 +54,11 @@ public class AsyncHttpConnection extends HttpConnection
|
|||
// Generate more output
|
||||
if (_generator.isCommitted() && !_generator.isComplete() && _generator.flushBuffer()>0)
|
||||
progress=true;
|
||||
|
||||
|
||||
// Flush output from buffering endpoint
|
||||
if (_endp.isBufferingOutput())
|
||||
_endp.flush();
|
||||
|
||||
|
||||
// Special case close handling.
|
||||
// If we were dispatched and have made no progress, but io is shutdown, then close
|
||||
if (!progress && !some_progress && (_endp.isInputShutdown()||_endp.isOutputShutdown()))
|
||||
|
@ -87,7 +86,7 @@ public class AsyncHttpConnection extends HttpConnection
|
|||
_endp.close();
|
||||
reset(true);
|
||||
}
|
||||
|
||||
|
||||
// else Is this request/response round complete?
|
||||
else if (_parser.isComplete() && _generator.isComplete() && !_endp.isBufferingOutput())
|
||||
{
|
||||
|
@ -102,9 +101,9 @@ public class AsyncHttpConnection extends HttpConnection
|
|||
connection=switched;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Reset the parser/generator
|
||||
// keep the buffers as we will cycle
|
||||
// keep the buffers as we will cycle
|
||||
progress=true;
|
||||
reset(false);
|
||||
more_in_buffer = _parser.isMoreInBuffer() || _endp.isBufferingInput();
|
||||
|
@ -118,7 +117,7 @@ public class AsyncHttpConnection extends HttpConnection
|
|||
}
|
||||
else
|
||||
more_in_buffer = _parser.isMoreInBuffer() || _endp.isBufferingInput();
|
||||
|
||||
|
||||
some_progress|=progress|((SelectChannelEndPoint)_endp).isProgressing();
|
||||
}
|
||||
}
|
||||
|
@ -132,19 +131,23 @@ public class AsyncHttpConnection extends HttpConnection
|
|||
// Check if we are write blocked
|
||||
if (_generator.isCommitted() && !_generator.isComplete() && _endp.isOpen() && !_endp.isOutputShutdown())
|
||||
((AsyncEndPoint)_endp).scheduleWrite(); // TODO. This should not be required
|
||||
|
||||
if (!some_progress)
|
||||
{
|
||||
_total_no_progress++;
|
||||
|
||||
if (NO_PROGRESS_INFO>0 && _total_no_progress%NO_PROGRESS_INFO==0 && (NO_PROGRESS_CLOSE<=0 || _total_no_progress< NO_PROGRESS_CLOSE))
|
||||
if (some_progress)
|
||||
{
|
||||
_total_no_progress=0;
|
||||
}
|
||||
else
|
||||
{
|
||||
int totalNoProgress=++_total_no_progress;
|
||||
|
||||
if (NO_PROGRESS_INFO>0 && totalNoProgress==NO_PROGRESS_INFO && (NO_PROGRESS_CLOSE<=0 || totalNoProgress<NO_PROGRESS_CLOSE))
|
||||
{
|
||||
LOG.info("EndPoint making no progress: "+_total_no_progress+" "+_endp);
|
||||
LOG.info("EndPoint making no progress: {} {}", totalNoProgress, _endp);
|
||||
}
|
||||
|
||||
if (NO_PROGRESS_CLOSE>0 && _total_no_progress==NO_PROGRESS_CLOSE)
|
||||
|
||||
if (NO_PROGRESS_CLOSE>0 && totalNoProgress==NO_PROGRESS_CLOSE)
|
||||
{
|
||||
LOG.warn("Closing EndPoint making no progress: "+_total_no_progress+" "+_endp);
|
||||
LOG.warn("Closing EndPoint making no progress: {} {}", totalNoProgress, _endp);
|
||||
if (_endp instanceof SelectChannelEndPoint)
|
||||
{
|
||||
System.err.println(((SelectChannelEndPoint)_endp).getSelectManager().dump());
|
||||
|
|
|
@ -245,9 +245,9 @@ public class SelectChannelConnector extends AbstractNIOConnector
|
|||
_manager.setMaxIdleTime(getMaxIdleTime());
|
||||
_manager.setLowResourcesConnections(getLowResourcesConnections());
|
||||
_manager.setLowResourcesMaxIdleTime(getLowResourcesMaxIdleTime());
|
||||
_manager.start();
|
||||
|
||||
super.doStart();
|
||||
_manager.start();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
|
|
@ -262,7 +262,7 @@ public class SslSelectChannelConnector extends SelectChannelConnector implements
|
|||
@Deprecated
|
||||
public void setKeystore(String keystore)
|
||||
{
|
||||
_sslContextFactory.setKeyStore(keystore);
|
||||
_sslContextFactory.setKeyStorePath(keystore);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -273,7 +273,7 @@ public class SslSelectChannelConnector extends SelectChannelConnector implements
|
|||
@Deprecated
|
||||
public String getKeystore()
|
||||
{
|
||||
return _sslContextFactory.getKeyStore();
|
||||
return _sslContextFactory.getKeyStorePath();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
|
|
@ -176,7 +176,7 @@ public class SslSocketConnector extends SocketConnector implements SslConnector
|
|||
@Deprecated
|
||||
public String getKeystore()
|
||||
{
|
||||
return _sslContextFactory.getKeyStore();
|
||||
return _sslContextFactory.getKeyStorePath();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -427,7 +427,7 @@ public class SslSocketConnector extends SocketConnector implements SslConnector
|
|||
@Deprecated
|
||||
public void setKeystore(String keystore)
|
||||
{
|
||||
_sslContextFactory.setKeyStore(keystore);
|
||||
_sslContextFactory.setKeyStorePath(keystore);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
|
|
@ -92,12 +92,12 @@ public class RequestTest
|
|||
{
|
||||
//catch the error and check the param map is not null
|
||||
map = request.getParameterMap();
|
||||
System.err.println(map);
|
||||
assertFalse(map == null);
|
||||
assertTrue(map.isEmpty());
|
||||
|
||||
Enumeration names = request.getParameterNames();
|
||||
assertFalse(names.hasMoreElements());
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -111,7 +111,32 @@ public class RequestTest
|
|||
"Content-Type: text/html;charset=utf8\n"+
|
||||
"\n";
|
||||
|
||||
String response = _connector.getResponses(request);
|
||||
String responses=_connector.getResponses(request);
|
||||
assertTrue(responses.startsWith("HTTP/1.1 200"));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBadUtf8ParamExtraction() throws Exception
|
||||
{
|
||||
_handler._checker = new RequestTester()
|
||||
{
|
||||
public boolean check(HttpServletRequest request,HttpServletResponse response)
|
||||
{
|
||||
String value=request.getParameter("param");
|
||||
return value.startsWith("aaa") && value.endsWith("bb");
|
||||
}
|
||||
};
|
||||
|
||||
//Send a request with query string with illegal hex code to cause
|
||||
//an exception parsing the params
|
||||
String request="GET /?param=aaa%E7bbb HTTP/1.1\r\n"+
|
||||
"Host: whatever\r\n"+
|
||||
"Content-Type: text/html;charset=utf8\n"+
|
||||
"\n";
|
||||
|
||||
String responses=_connector.getResponses(request);
|
||||
assertTrue(responses.startsWith("HTTP/1.1 200"));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ public class ConnectHandlerSSLTest extends AbstractConnectHandlerTest
|
|||
|
||||
String keyStorePath = MavenTestingUtils.getTestResourceFile("keystore").getAbsolutePath();
|
||||
SslContextFactory cf = connector.getSslContextFactory();
|
||||
cf.setKeyStore(keyStorePath);
|
||||
cf.setKeyStorePath(keyStorePath);
|
||||
cf.setKeyStorePassword("storepwd");
|
||||
cf.setKeyManagerPassword("keypwd");
|
||||
|
||||
|
|
|
@ -112,7 +112,7 @@ public class SSLEngineTest
|
|||
|
||||
connector.setPort(0);
|
||||
SslContextFactory cf = connector.getSslContextFactory();
|
||||
cf.setKeyStore(keystore);
|
||||
cf.setKeyStorePath(keystore);
|
||||
cf.setKeyStorePassword("storepwd");
|
||||
cf.setKeyManagerPassword("keypwd");
|
||||
connector.setRequestBufferSize(512);
|
||||
|
|
|
@ -45,7 +45,7 @@ public class SSLSelectChannelConnectorLoadTest
|
|||
|
||||
String keystorePath = System.getProperty("basedir", ".") + "/src/test/resources/keystore";
|
||||
SslContextFactory cf = connector.getSslContextFactory();
|
||||
cf.setKeyStore(keystorePath);
|
||||
cf.setKeyStorePath(keystorePath);
|
||||
cf.setKeyStorePassword("storepwd");
|
||||
cf.setKeyManagerPassword("keypwd");
|
||||
cf.setTrustStore(keystorePath);
|
||||
|
|
|
@ -95,7 +95,7 @@ public class SslRenegotiateTest
|
|||
String keystore = MavenTestingUtils.getTestResourceFile("keystore").getAbsolutePath();
|
||||
connector.setPort(0);
|
||||
SslContextFactory cf = connector.getSslContextFactory();
|
||||
cf.setKeyStore(keystore);
|
||||
cf.setKeyStorePath(keystore);
|
||||
cf.setKeyStorePassword("storepwd");
|
||||
cf.setKeyManagerPassword("keypwd");
|
||||
cf.setAllowRenegotiate(reneg);
|
||||
|
|
|
@ -48,7 +48,7 @@ public class SslSelectChannelServerTest extends HttpServerTestBase
|
|||
SslSelectChannelConnector connector = new SslSelectChannelConnector();
|
||||
String keystorePath = System.getProperty("basedir",".") + "/src/test/resources/keystore";
|
||||
SslContextFactory cf = connector.getSslContextFactory();
|
||||
cf.setKeyStore(keystorePath);
|
||||
cf.setKeyStorePath(keystorePath);
|
||||
cf.setKeyStorePassword("storepwd");
|
||||
cf.setKeyManagerPassword("keypwd");
|
||||
cf.setTrustStore(keystorePath);
|
||||
|
|
|
@ -42,7 +42,7 @@ public class SslSelectChannelTimeoutTest extends ConnectorTimeoutTest
|
|||
connector.setMaxIdleTime(MAX_IDLE_TIME); //250 msec max idle
|
||||
String keystorePath = System.getProperty("basedir",".") + "/src/test/resources/keystore";
|
||||
SslContextFactory cf = connector.getSslContextFactory();
|
||||
cf.setKeyStore(keystorePath);
|
||||
cf.setKeyStorePath(keystorePath);
|
||||
cf.setKeyStorePassword("storepwd");
|
||||
cf.setKeyManagerPassword("keypwd");
|
||||
cf.setTrustStore(keystorePath);
|
||||
|
|
|
@ -51,7 +51,7 @@ public class SslSocketServerTest extends HttpServerTestBase
|
|||
SslSocketConnector connector = new SslSocketConnector();
|
||||
String keystorePath = System.getProperty("basedir",".") + "/src/test/resources/keystore";
|
||||
SslContextFactory cf = connector.getSslContextFactory();
|
||||
cf.setKeyStore(keystorePath);
|
||||
cf.setKeyStorePath(keystorePath);
|
||||
cf.setKeyStorePassword("storepwd");
|
||||
cf.setKeyManagerPassword("keypwd");
|
||||
cf.setTrustStore(keystorePath);
|
||||
|
|
|
@ -44,7 +44,7 @@ public class SslSocketTimeoutTest extends ConnectorTimeoutTest
|
|||
connector.setMaxIdleTime(MAX_IDLE_TIME); //250 msec max idle
|
||||
String keystorePath = System.getProperty("basedir",".") + "/src/test/resources/keystore";
|
||||
SslContextFactory cf = connector.getSslContextFactory();
|
||||
cf.setKeyStore(keystorePath);
|
||||
cf.setKeyStorePath(keystorePath);
|
||||
cf.setKeyStorePassword("storepwd");
|
||||
cf.setKeyManagerPassword("keypwd");
|
||||
cf.setTrustStore(keystorePath);
|
||||
|
|
|
@ -84,7 +84,7 @@ public class SslTruncationAttackTest
|
|||
|
||||
String keystorePath = System.getProperty("basedir", ".") + "/src/test/resources/keystore";
|
||||
SslContextFactory sslContextFactory = connector.getSslContextFactory();
|
||||
sslContextFactory.setKeyStore(keystorePath);
|
||||
sslContextFactory.setKeyStorePath(keystorePath);
|
||||
sslContextFactory.setKeyStorePassword("storepwd");
|
||||
sslContextFactory.setKeyManagerPassword("keypwd");
|
||||
sslContextFactory.setTrustStore(keystorePath);
|
||||
|
|
|
@ -58,7 +58,7 @@ public class SslUploadTest
|
|||
|
||||
String keystorePath = System.getProperty("basedir",".") + "/src/test/resources/keystore";
|
||||
SslContextFactory cf = connector.getSslContextFactory();
|
||||
cf.setKeyStore(keystorePath);
|
||||
cf.setKeyStorePath(keystorePath);
|
||||
cf.setKeyStorePassword("storepwd");
|
||||
cf.setKeyManagerPassword("keypwd");
|
||||
cf.setTrustStore(keystorePath);
|
||||
|
|
|
@ -32,7 +32,7 @@ import org.eclipse.jetty.util.log.Logger;
|
|||
|
||||
/**
|
||||
* <p>Implementation of the
|
||||
* <a href="http://dev.w3.org/2006/waf/access-control/">cross-origin resource sharing</a>.</p>
|
||||
* <a href="http://www.w3.org/TR/cors/">cross-origin resource sharing</a>.</p>
|
||||
* <p>A typical example is to use this filter to allow cross-domain
|
||||
* <a href="http://cometd.org">cometd</a> communication using the standard
|
||||
* long polling transport instead of the JSONP transport (that is less
|
||||
|
@ -74,38 +74,39 @@ import org.eclipse.jetty.util.log.Logger;
|
|||
*/
|
||||
public class CrossOriginFilter implements Filter
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(CrossOriginFilter.class);
|
||||
private static final Logger logger = Log.getLogger(CrossOriginFilter.class);
|
||||
|
||||
// Request headers
|
||||
private static final String ORIGIN_HEADER = "Origin";
|
||||
private static final String ACCESS_CONTROL_REQUEST_METHOD_HEADER = "Access-Control-Request-Method";
|
||||
private static final String ACCESS_CONTROL_REQUEST_HEADERS_HEADER = "Access-Control-Request-Headers";
|
||||
public static final String ACCESS_CONTROL_REQUEST_METHOD_HEADER = "Access-Control-Request-Method";
|
||||
public static final String ACCESS_CONTROL_REQUEST_HEADERS_HEADER = "Access-Control-Request-Headers";
|
||||
// Response headers
|
||||
private static final String ACCESS_CONTROL_ALLOW_ORIGIN_HEADER = "Access-Control-Allow-Origin";
|
||||
private static final String ACCESS_CONTROL_ALLOW_METHODS_HEADER = "Access-Control-Allow-Methods";
|
||||
private static final String ACCESS_CONTROL_ALLOW_HEADERS_HEADER = "Access-Control-Allow-Headers";
|
||||
private static final String ACCESS_CONTROL_MAX_AGE_HEADER = "Access-Control-Max-Age";
|
||||
private static final String ACCESS_CONTROL_ALLOW_CREDENTIALS_HEADER = "Access-Control-Allow-Credentials";
|
||||
public static final String ACCESS_CONTROL_ALLOW_ORIGIN_HEADER = "Access-Control-Allow-Origin";
|
||||
public static final String ACCESS_CONTROL_ALLOW_METHODS_HEADER = "Access-Control-Allow-Methods";
|
||||
public static final String ACCESS_CONTROL_ALLOW_HEADERS_HEADER = "Access-Control-Allow-Headers";
|
||||
public static final String ACCESS_CONTROL_MAX_AGE_HEADER = "Access-Control-Max-Age";
|
||||
public static final String ACCESS_CONTROL_ALLOW_CREDENTIALS_HEADER = "Access-Control-Allow-Credentials";
|
||||
// Implementation constants
|
||||
private static final String ALLOWED_ORIGINS_PARAM = "allowedOrigins";
|
||||
private static final String ALLOWED_METHODS_PARAM = "allowedMethods";
|
||||
private static final String ALLOWED_HEADERS_PARAM = "allowedHeaders";
|
||||
private static final String PREFLIGHT_MAX_AGE_PARAM = "preflightMaxAge";
|
||||
private static final String ALLOWED_CREDENTIALS_PARAM = "allowCredentials";
|
||||
public static final String ALLOWED_ORIGINS_PARAM = "allowedOrigins";
|
||||
public static final String ALLOWED_METHODS_PARAM = "allowedMethods";
|
||||
public static final String ALLOWED_HEADERS_PARAM = "allowedHeaders";
|
||||
public static final String PREFLIGHT_MAX_AGE_PARAM = "preflightMaxAge";
|
||||
public static final String ALLOW_CREDENTIALS_PARAM = "allowCredentials";
|
||||
private static final String ANY_ORIGIN = "*";
|
||||
private static final List<String> SIMPLE_HTTP_METHODS = Arrays.asList("GET", "POST", "HEAD");
|
||||
|
||||
private boolean anyOriginAllowed = false;
|
||||
private boolean anyOriginAllowed;
|
||||
private List<String> allowedOrigins = new ArrayList<String>();
|
||||
private List<String> allowedMethods = new ArrayList<String>();
|
||||
private List<String> allowedHeaders = new ArrayList<String>();
|
||||
private int preflightMaxAge = 0;
|
||||
private boolean allowCredentials = true;
|
||||
private boolean allowCredentials;
|
||||
|
||||
public void init(FilterConfig config) throws ServletException
|
||||
{
|
||||
String allowedOriginsConfig = config.getInitParameter(ALLOWED_ORIGINS_PARAM);
|
||||
if (allowedOriginsConfig == null) allowedOriginsConfig = "*";
|
||||
if (allowedOriginsConfig == null)
|
||||
allowedOriginsConfig = "*";
|
||||
String[] allowedOrigins = allowedOriginsConfig.split(",");
|
||||
for (String allowedOrigin : allowedOrigins)
|
||||
{
|
||||
|
@ -126,34 +127,38 @@ public class CrossOriginFilter implements Filter
|
|||
}
|
||||
|
||||
String allowedMethodsConfig = config.getInitParameter(ALLOWED_METHODS_PARAM);
|
||||
if (allowedMethodsConfig == null) allowedMethodsConfig = "GET,POST";
|
||||
if (allowedMethodsConfig == null)
|
||||
allowedMethodsConfig = "GET,POST,HEAD";
|
||||
allowedMethods.addAll(Arrays.asList(allowedMethodsConfig.split(",")));
|
||||
|
||||
String allowedHeadersConfig = config.getInitParameter(ALLOWED_HEADERS_PARAM);
|
||||
if (allowedHeadersConfig == null) allowedHeadersConfig = "X-Requested-With,Content-Type,Accept,Origin";
|
||||
if (allowedHeadersConfig == null)
|
||||
allowedHeadersConfig = "X-Requested-With,Content-Type,Accept,Origin";
|
||||
allowedHeaders.addAll(Arrays.asList(allowedHeadersConfig.split(",")));
|
||||
|
||||
String preflightMaxAgeConfig = config.getInitParameter(PREFLIGHT_MAX_AGE_PARAM);
|
||||
if (preflightMaxAgeConfig == null) preflightMaxAgeConfig = "1800"; // Default is 30 minutes
|
||||
if (preflightMaxAgeConfig == null)
|
||||
preflightMaxAgeConfig = "1800"; // Default is 30 minutes
|
||||
try
|
||||
{
|
||||
preflightMaxAge = Integer.parseInt(preflightMaxAgeConfig);
|
||||
}
|
||||
catch (NumberFormatException x)
|
||||
{
|
||||
LOG.info("Cross-origin filter, could not parse '{}' parameter as integer: {}", PREFLIGHT_MAX_AGE_PARAM, preflightMaxAgeConfig);
|
||||
logger.info("Cross-origin filter, could not parse '{}' parameter as integer: {}", PREFLIGHT_MAX_AGE_PARAM, preflightMaxAgeConfig);
|
||||
}
|
||||
|
||||
String allowedCredentialsConfig = config.getInitParameter(ALLOWED_CREDENTIALS_PARAM);
|
||||
if (allowedCredentialsConfig == null) allowedCredentialsConfig = "false";
|
||||
String allowedCredentialsConfig = config.getInitParameter(ALLOW_CREDENTIALS_PARAM);
|
||||
if (allowedCredentialsConfig == null)
|
||||
allowedCredentialsConfig = "true";
|
||||
allowCredentials = Boolean.parseBoolean(allowedCredentialsConfig);
|
||||
|
||||
LOG.debug("Cross-origin filter configuration: " +
|
||||
ALLOWED_ORIGINS_PARAM + " = " + allowedOriginsConfig + ", " +
|
||||
ALLOWED_METHODS_PARAM + " = " + allowedMethodsConfig + ", " +
|
||||
ALLOWED_HEADERS_PARAM + " = " + allowedHeadersConfig + ", " +
|
||||
PREFLIGHT_MAX_AGE_PARAM + " = " + preflightMaxAgeConfig + ", " +
|
||||
ALLOWED_CREDENTIALS_PARAM + " = " + allowedCredentialsConfig);
|
||||
logger.debug("Cross-origin filter configuration: " +
|
||||
ALLOWED_ORIGINS_PARAM + " = " + allowedOriginsConfig + ", " +
|
||||
ALLOWED_METHODS_PARAM + " = " + allowedMethodsConfig + ", " +
|
||||
ALLOWED_HEADERS_PARAM + " = " + allowedHeadersConfig + ", " +
|
||||
PREFLIGHT_MAX_AGE_PARAM + " = " + preflightMaxAgeConfig + ", " +
|
||||
ALLOW_CREDENTIALS_PARAM + " = " + allowedCredentialsConfig);
|
||||
}
|
||||
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException
|
||||
|
@ -171,18 +176,23 @@ public class CrossOriginFilter implements Filter
|
|||
{
|
||||
if (isSimpleRequest(request))
|
||||
{
|
||||
LOG.debug("Cross-origin request to {} is a simple cross-origin request", request.getRequestURI());
|
||||
logger.debug("Cross-origin request to {} is a simple cross-origin request", request.getRequestURI());
|
||||
handleSimpleResponse(request, response, origin);
|
||||
}
|
||||
else if (isPreflightRequest(request))
|
||||
{
|
||||
logger.debug("Cross-origin request to {} is a preflight cross-origin request", request.getRequestURI());
|
||||
handlePreflightResponse(request, response, origin);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG.debug("Cross-origin request to {} is a preflight cross-origin request", request.getRequestURI());
|
||||
handlePreflightResponse(request, response, origin);
|
||||
logger.debug("Cross-origin request to {} is a non-simple cross-origin request", request.getRequestURI());
|
||||
handleSimpleResponse(request, response, origin);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG.debug("Cross-origin request to " + request.getRequestURI() + " with origin " + origin + " does not match allowed origins " + allowedOrigins);
|
||||
logger.debug("Cross-origin request to " + request.getRequestURI() + " with origin " + origin + " does not match allowed origins " + allowedOrigins);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -201,14 +211,33 @@ public class CrossOriginFilter implements Filter
|
|||
return true;
|
||||
}
|
||||
|
||||
private boolean originMatches(String origin)
|
||||
private boolean originMatches(String originList)
|
||||
{
|
||||
if (anyOriginAllowed) return true;
|
||||
for (String allowedOrigin : allowedOrigins)
|
||||
if (anyOriginAllowed)
|
||||
return true;
|
||||
|
||||
if (originList.trim().length() == 0)
|
||||
return false;
|
||||
|
||||
String[] origins = originList.split(" ");
|
||||
for (String origin : origins)
|
||||
{
|
||||
if (allowedOrigin.equals(origin)) return true;
|
||||
if (origin.trim().length() == 0)
|
||||
continue;
|
||||
|
||||
boolean allowed = false;
|
||||
for (String allowedOrigin : allowedOrigins)
|
||||
{
|
||||
if (allowedOrigin.equals(origin))
|
||||
{
|
||||
allowed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!allowed)
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean isSimpleRequest(HttpServletRequest request)
|
||||
|
@ -216,8 +245,8 @@ public class CrossOriginFilter implements Filter
|
|||
String method = request.getMethod();
|
||||
if (SIMPLE_HTTP_METHODS.contains(method))
|
||||
{
|
||||
// TODO: implement better section 6.1
|
||||
// Section 6.1 says that for a request to be simple, custom request headers must be simple.
|
||||
// TODO: implement better detection of simple headers
|
||||
// The specification says that for a request to be simple, custom request headers must be simple.
|
||||
// Here for simplicity I just check if there is a Access-Control-Request-Method header,
|
||||
// which is required for preflight requests
|
||||
return request.getHeader(ACCESS_CONTROL_REQUEST_METHOD_HEADER) == null;
|
||||
|
@ -225,50 +254,55 @@ public class CrossOriginFilter implements Filter
|
|||
return false;
|
||||
}
|
||||
|
||||
private boolean isPreflightRequest(HttpServletRequest request)
|
||||
{
|
||||
String method = request.getMethod();
|
||||
if (!"OPTIONS".equalsIgnoreCase(method))
|
||||
return false;
|
||||
if (request.getHeader(ACCESS_CONTROL_REQUEST_METHOD_HEADER) == null)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
private void handleSimpleResponse(HttpServletRequest request, HttpServletResponse response, String origin)
|
||||
{
|
||||
response.setHeader(ACCESS_CONTROL_ALLOW_ORIGIN_HEADER, origin);
|
||||
if (allowCredentials) response.setHeader(ACCESS_CONTROL_ALLOW_CREDENTIALS_HEADER, "true");
|
||||
if (allowCredentials)
|
||||
response.setHeader(ACCESS_CONTROL_ALLOW_CREDENTIALS_HEADER, "true");
|
||||
}
|
||||
|
||||
private void handlePreflightResponse(HttpServletRequest request, HttpServletResponse response, String origin)
|
||||
{
|
||||
// Implementation of section 5.2
|
||||
|
||||
// 5.2.3 and 5.2.5
|
||||
boolean methodAllowed = isMethodAllowed(request);
|
||||
if (!methodAllowed) return;
|
||||
// 5.2.4 and 5.2.6
|
||||
if (!methodAllowed)
|
||||
return;
|
||||
boolean headersAllowed = areHeadersAllowed(request);
|
||||
if (!headersAllowed) return;
|
||||
// 5.2.7
|
||||
if (!headersAllowed)
|
||||
return;
|
||||
response.setHeader(ACCESS_CONTROL_ALLOW_ORIGIN_HEADER, origin);
|
||||
if (allowCredentials) response.setHeader(ACCESS_CONTROL_ALLOW_CREDENTIALS_HEADER, "true");
|
||||
// 5.2.8
|
||||
if (preflightMaxAge > 0) response.setHeader(ACCESS_CONTROL_MAX_AGE_HEADER, String.valueOf(preflightMaxAge));
|
||||
// 5.2.9
|
||||
if (allowCredentials)
|
||||
response.setHeader(ACCESS_CONTROL_ALLOW_CREDENTIALS_HEADER, "true");
|
||||
if (preflightMaxAge > 0)
|
||||
response.setHeader(ACCESS_CONTROL_MAX_AGE_HEADER, String.valueOf(preflightMaxAge));
|
||||
response.setHeader(ACCESS_CONTROL_ALLOW_METHODS_HEADER, commify(allowedMethods));
|
||||
// 5.2.10
|
||||
response.setHeader(ACCESS_CONTROL_ALLOW_HEADERS_HEADER, commify(allowedHeaders));
|
||||
}
|
||||
|
||||
private boolean isMethodAllowed(HttpServletRequest request)
|
||||
{
|
||||
String accessControlRequestMethod = request.getHeader(ACCESS_CONTROL_REQUEST_METHOD_HEADER);
|
||||
LOG.debug("{} is {}", ACCESS_CONTROL_REQUEST_METHOD_HEADER, accessControlRequestMethod);
|
||||
logger.debug("{} is {}", ACCESS_CONTROL_REQUEST_METHOD_HEADER, accessControlRequestMethod);
|
||||
boolean result = false;
|
||||
if (accessControlRequestMethod != null)
|
||||
{
|
||||
result = allowedMethods.contains(accessControlRequestMethod);
|
||||
}
|
||||
LOG.debug("Method {} is" + (result ? "" : " not") + " among allowed methods {}", accessControlRequestMethod, allowedMethods);
|
||||
logger.debug("Method {} is" + (result ? "" : " not") + " among allowed methods {}", accessControlRequestMethod, allowedMethods);
|
||||
return result;
|
||||
}
|
||||
|
||||
private boolean areHeadersAllowed(HttpServletRequest request)
|
||||
{
|
||||
String accessControlRequestHeaders = request.getHeader(ACCESS_CONTROL_REQUEST_HEADERS_HEADER);
|
||||
LOG.debug("{} is {}", ACCESS_CONTROL_REQUEST_HEADERS_HEADER, accessControlRequestHeaders);
|
||||
logger.debug("{} is {}", ACCESS_CONTROL_REQUEST_HEADERS_HEADER, accessControlRequestHeaders);
|
||||
boolean result = true;
|
||||
if (accessControlRequestHeaders != null)
|
||||
{
|
||||
|
@ -291,7 +325,7 @@ public class CrossOriginFilter implements Filter
|
|||
}
|
||||
}
|
||||
}
|
||||
LOG.debug("Headers [{}] are" + (result ? "" : " not") + " among allowed headers {}", accessControlRequestHeaders, allowedHeaders);
|
||||
logger.debug("Headers [{}] are" + (result ? "" : " not") + " among allowed headers {}", accessControlRequestHeaders, allowedHeaders);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,343 @@
|
|||
package org.eclipse.jetty.servlets;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.servlet.FilterHolder;
|
||||
import org.eclipse.jetty.servlet.FilterMapping;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.eclipse.jetty.testing.ServletTester;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
public class CrossOriginFilterTest
|
||||
{
|
||||
private ServletTester tester;
|
||||
|
||||
@Before
|
||||
public void init() throws Exception
|
||||
{
|
||||
tester = new ServletTester();
|
||||
tester.start();
|
||||
}
|
||||
|
||||
@After
|
||||
public void destroy() throws Exception
|
||||
{
|
||||
if (tester != null)
|
||||
tester.stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRequestWithNoOriginArrivesToApplication() throws Exception
|
||||
{
|
||||
tester.getContext().addFilter(CrossOriginFilter.class, "/*", FilterMapping.DEFAULT);
|
||||
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
tester.getContext().addServlet(new ServletHolder(new ResourceServlet(latch)), "/*");
|
||||
|
||||
String request = "" +
|
||||
"GET / HTTP/1.1\r\n" +
|
||||
"Host: localhost\r\n" +
|
||||
"\r\n";
|
||||
String response = tester.getResponses(request);
|
||||
Assert.assertTrue(response.contains("HTTP/1.1 200"));
|
||||
Assert.assertTrue(latch.await(1, TimeUnit.SECONDS));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleRequestWithNonMatchingOrigin() throws Exception
|
||||
{
|
||||
FilterHolder filterHolder = new FilterHolder(new CrossOriginFilter());
|
||||
String origin = "http://localhost";
|
||||
filterHolder.setInitParameter(CrossOriginFilter.ALLOWED_ORIGINS_PARAM, origin);
|
||||
tester.getContext().addFilter(filterHolder, "/*", FilterMapping.DEFAULT);
|
||||
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
tester.getContext().addServlet(new ServletHolder(new ResourceServlet(latch)), "/*");
|
||||
|
||||
String otherOrigin = origin.replace("localhost", "127.0.0.1");
|
||||
String request = "" +
|
||||
"GET / HTTP/1.1\r\n" +
|
||||
"Host: localhost\r\n" +
|
||||
"Origin: " + otherOrigin + "\r\n" +
|
||||
"\r\n";
|
||||
String response = tester.getResponses(request);
|
||||
Assert.assertTrue(response.contains("HTTP/1.1 200"));
|
||||
Assert.assertFalse(response.contains(CrossOriginFilter.ACCESS_CONTROL_ALLOW_ORIGIN_HEADER));
|
||||
Assert.assertFalse(response.contains(CrossOriginFilter.ACCESS_CONTROL_ALLOW_CREDENTIALS_HEADER));
|
||||
Assert.assertTrue(latch.await(1, TimeUnit.SECONDS));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleRequestWithMatchingOrigin() throws Exception
|
||||
{
|
||||
FilterHolder filterHolder = new FilterHolder(new CrossOriginFilter());
|
||||
String origin = "http://localhost";
|
||||
filterHolder.setInitParameter(CrossOriginFilter.ALLOWED_ORIGINS_PARAM, origin);
|
||||
tester.getContext().addFilter(filterHolder, "/*", FilterMapping.DEFAULT);
|
||||
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
tester.getContext().addServlet(new ServletHolder(new ResourceServlet(latch)), "/*");
|
||||
|
||||
String request = "" +
|
||||
"GET / HTTP/1.1\r\n" +
|
||||
"Host: localhost\r\n" +
|
||||
"Origin: " + origin + "\r\n" +
|
||||
"\r\n";
|
||||
String response = tester.getResponses(request);
|
||||
Assert.assertTrue(response.contains("HTTP/1.1 200"));
|
||||
Assert.assertTrue(response.contains(CrossOriginFilter.ACCESS_CONTROL_ALLOW_ORIGIN_HEADER));
|
||||
Assert.assertTrue(response.contains(CrossOriginFilter.ACCESS_CONTROL_ALLOW_CREDENTIALS_HEADER));
|
||||
Assert.assertTrue(latch.await(1, TimeUnit.SECONDS));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleRequestWithMatchingMultipleOrigins() throws Exception
|
||||
{
|
||||
FilterHolder filterHolder = new FilterHolder(new CrossOriginFilter());
|
||||
String origin = "http://localhost";
|
||||
String otherOrigin = origin.replace("localhost", "127.0.0.1");
|
||||
filterHolder.setInitParameter(CrossOriginFilter.ALLOWED_ORIGINS_PARAM, origin + "," + otherOrigin);
|
||||
tester.getContext().addFilter(filterHolder, "/*", FilterMapping.DEFAULT);
|
||||
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
tester.getContext().addServlet(new ServletHolder(new ResourceServlet(latch)), "/*");
|
||||
|
||||
String request = "" +
|
||||
"GET / HTTP/1.1\r\n" +
|
||||
"Host: localhost\r\n" +
|
||||
// Use 2 spaces as separator to test that the implementation does not fail
|
||||
"Origin: " + otherOrigin + " " + " " + origin + "\r\n" +
|
||||
"\r\n";
|
||||
String response = tester.getResponses(request);
|
||||
Assert.assertTrue(response.contains("HTTP/1.1 200"));
|
||||
Assert.assertTrue(response.contains(CrossOriginFilter.ACCESS_CONTROL_ALLOW_ORIGIN_HEADER));
|
||||
Assert.assertTrue(response.contains(CrossOriginFilter.ACCESS_CONTROL_ALLOW_CREDENTIALS_HEADER));
|
||||
Assert.assertTrue(latch.await(1, TimeUnit.SECONDS));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleRequestWithoutCredentials() throws Exception
|
||||
{
|
||||
FilterHolder filterHolder = new FilterHolder(new CrossOriginFilter());
|
||||
filterHolder.setInitParameter(CrossOriginFilter.ALLOW_CREDENTIALS_PARAM, "false");
|
||||
tester.getContext().addFilter(filterHolder, "/*", FilterMapping.DEFAULT);
|
||||
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
tester.getContext().addServlet(new ServletHolder(new ResourceServlet(latch)), "/*");
|
||||
|
||||
String request = "" +
|
||||
"GET / HTTP/1.1\r\n" +
|
||||
"Host: localhost\r\n" +
|
||||
"Origin: http://localhost\r\n" +
|
||||
"\r\n";
|
||||
String response = tester.getResponses(request);
|
||||
Assert.assertTrue(response.contains("HTTP/1.1 200"));
|
||||
Assert.assertTrue(response.contains(CrossOriginFilter.ACCESS_CONTROL_ALLOW_ORIGIN_HEADER));
|
||||
Assert.assertFalse(response.contains(CrossOriginFilter.ACCESS_CONTROL_ALLOW_CREDENTIALS_HEADER));
|
||||
Assert.assertTrue(latch.await(1, TimeUnit.SECONDS));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNonSimpleRequestWithoutPreflight() throws Exception
|
||||
{
|
||||
// We cannot know if an actual request has performed the preflight before:
|
||||
// we'll trust browsers to do it right, so responses to actual requests
|
||||
// will contain the CORS response headers.
|
||||
|
||||
FilterHolder filterHolder = new FilterHolder(new CrossOriginFilter());
|
||||
tester.getContext().addFilter(filterHolder, "/*", FilterMapping.DEFAULT);
|
||||
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
tester.getContext().addServlet(new ServletHolder(new ResourceServlet(latch)), "/*");
|
||||
|
||||
String request = "" +
|
||||
"PUT / HTTP/1.1\r\n" +
|
||||
"Host: localhost\r\n" +
|
||||
"Origin: http://localhost\r\n" +
|
||||
"\r\n";
|
||||
String response = tester.getResponses(request);
|
||||
Assert.assertTrue(response.contains("HTTP/1.1 200"));
|
||||
Assert.assertTrue(response.contains(CrossOriginFilter.ACCESS_CONTROL_ALLOW_ORIGIN_HEADER));
|
||||
Assert.assertTrue(response.contains(CrossOriginFilter.ACCESS_CONTROL_ALLOW_CREDENTIALS_HEADER));
|
||||
Assert.assertTrue(latch.await(1, TimeUnit.SECONDS));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOptionsRequestButNotPreflight() throws Exception
|
||||
{
|
||||
// We cannot know if an actual request has performed the preflight before:
|
||||
// we'll trust browsers to do it right, so responses to actual requests
|
||||
// will contain the CORS response headers.
|
||||
|
||||
FilterHolder filterHolder = new FilterHolder(new CrossOriginFilter());
|
||||
tester.getContext().addFilter(filterHolder, "/*", FilterMapping.DEFAULT);
|
||||
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
tester.getContext().addServlet(new ServletHolder(new ResourceServlet(latch)), "/*");
|
||||
|
||||
String request = "" +
|
||||
"OPTIONS / HTTP/1.1\r\n" +
|
||||
"Host: localhost\r\n" +
|
||||
"Origin: http://localhost\r\n" +
|
||||
"\r\n";
|
||||
String response = tester.getResponses(request);
|
||||
Assert.assertTrue(response.contains("HTTP/1.1 200"));
|
||||
Assert.assertTrue(response.contains(CrossOriginFilter.ACCESS_CONTROL_ALLOW_ORIGIN_HEADER));
|
||||
Assert.assertTrue(response.contains(CrossOriginFilter.ACCESS_CONTROL_ALLOW_CREDENTIALS_HEADER));
|
||||
Assert.assertTrue(latch.await(1, TimeUnit.SECONDS));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPUTRequestWithPreflight() throws Exception
|
||||
{
|
||||
FilterHolder filterHolder = new FilterHolder(new CrossOriginFilter());
|
||||
filterHolder.setInitParameter(CrossOriginFilter.ALLOWED_METHODS_PARAM, "PUT");
|
||||
tester.getContext().addFilter(filterHolder, "/*", FilterMapping.DEFAULT);
|
||||
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
tester.getContext().addServlet(new ServletHolder(new ResourceServlet(latch)), "/*");
|
||||
|
||||
// Preflight request
|
||||
String request = "" +
|
||||
"OPTIONS / HTTP/1.1\r\n" +
|
||||
"Host: localhost\r\n" +
|
||||
CrossOriginFilter.ACCESS_CONTROL_REQUEST_METHOD_HEADER + ": PUT\r\n" +
|
||||
"Origin: http://localhost\r\n" +
|
||||
"\r\n";
|
||||
String response = tester.getResponses(request);
|
||||
Assert.assertTrue(response.contains("HTTP/1.1 200"));
|
||||
Assert.assertTrue(response.contains(CrossOriginFilter.ACCESS_CONTROL_ALLOW_ORIGIN_HEADER));
|
||||
Assert.assertTrue(response.contains(CrossOriginFilter.ACCESS_CONTROL_ALLOW_CREDENTIALS_HEADER));
|
||||
Assert.assertTrue(response.contains(CrossOriginFilter.ACCESS_CONTROL_MAX_AGE_HEADER));
|
||||
Assert.assertTrue(response.contains(CrossOriginFilter.ACCESS_CONTROL_ALLOW_METHODS_HEADER));
|
||||
Assert.assertTrue(response.contains(CrossOriginFilter.ACCESS_CONTROL_ALLOW_HEADERS_HEADER));
|
||||
Assert.assertTrue(latch.await(1, TimeUnit.SECONDS));
|
||||
|
||||
// Preflight request was ok, now make the actual request
|
||||
request = "" +
|
||||
"PUT / HTTP/1.1\r\n" +
|
||||
"Host: localhost\r\n" +
|
||||
"Origin: http://localhost\r\n" +
|
||||
"\r\n";
|
||||
response = tester.getResponses(request);
|
||||
Assert.assertTrue(response.contains("HTTP/1.1 200"));
|
||||
Assert.assertTrue(response.contains(CrossOriginFilter.ACCESS_CONTROL_ALLOW_ORIGIN_HEADER));
|
||||
Assert.assertTrue(response.contains(CrossOriginFilter.ACCESS_CONTROL_ALLOW_CREDENTIALS_HEADER));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDELETERequestWithPreflightAndAllowedCustomHeaders() throws Exception
|
||||
{
|
||||
FilterHolder filterHolder = new FilterHolder(new CrossOriginFilter());
|
||||
filterHolder.setInitParameter(CrossOriginFilter.ALLOWED_METHODS_PARAM, "GET,HEAD,POST,PUT,DELETE");
|
||||
filterHolder.setInitParameter(CrossOriginFilter.ALLOWED_HEADERS_PARAM, "X-Requested-With,Content-Type,Accept,Origin,X-Custom");
|
||||
tester.getContext().addFilter(filterHolder, "/*", FilterMapping.DEFAULT);
|
||||
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
tester.getContext().addServlet(new ServletHolder(new ResourceServlet(latch)), "/*");
|
||||
|
||||
// Preflight request
|
||||
String request = "" +
|
||||
"OPTIONS / HTTP/1.1\r\n" +
|
||||
"Host: localhost\r\n" +
|
||||
CrossOriginFilter.ACCESS_CONTROL_REQUEST_METHOD_HEADER + ": DELETE\r\n" +
|
||||
CrossOriginFilter.ACCESS_CONTROL_REQUEST_HEADERS_HEADER + ": origin,x-custom,x-requested-with\r\n" +
|
||||
"Origin: http://localhost\r\n" +
|
||||
"\r\n";
|
||||
String response = tester.getResponses(request);
|
||||
Assert.assertTrue(response.contains("HTTP/1.1 200"));
|
||||
Assert.assertTrue(response.contains(CrossOriginFilter.ACCESS_CONTROL_ALLOW_ORIGIN_HEADER));
|
||||
Assert.assertTrue(response.contains(CrossOriginFilter.ACCESS_CONTROL_ALLOW_CREDENTIALS_HEADER));
|
||||
Assert.assertTrue(response.contains(CrossOriginFilter.ACCESS_CONTROL_MAX_AGE_HEADER));
|
||||
Assert.assertTrue(response.contains(CrossOriginFilter.ACCESS_CONTROL_ALLOW_METHODS_HEADER));
|
||||
Assert.assertTrue(response.contains(CrossOriginFilter.ACCESS_CONTROL_ALLOW_HEADERS_HEADER));
|
||||
Assert.assertTrue(latch.await(1, TimeUnit.SECONDS));
|
||||
|
||||
// Preflight request was ok, now make the actual request
|
||||
request = "" +
|
||||
"DELETE / HTTP/1.1\r\n" +
|
||||
"Host: localhost\r\n" +
|
||||
"X-Custom: value\r\n" +
|
||||
"X-Requested-With: local\r\n" +
|
||||
"Origin: http://localhost\r\n" +
|
||||
"\r\n";
|
||||
response = tester.getResponses(request);
|
||||
Assert.assertTrue(response.contains("HTTP/1.1 200"));
|
||||
Assert.assertTrue(response.contains(CrossOriginFilter.ACCESS_CONTROL_ALLOW_ORIGIN_HEADER));
|
||||
Assert.assertTrue(response.contains(CrossOriginFilter.ACCESS_CONTROL_ALLOW_CREDENTIALS_HEADER));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDELETERequestWithPreflightAndNotAllowedCustomHeaders() throws Exception
|
||||
{
|
||||
FilterHolder filterHolder = new FilterHolder(new CrossOriginFilter());
|
||||
filterHolder.setInitParameter(CrossOriginFilter.ALLOWED_METHODS_PARAM, "GET,HEAD,POST,PUT,DELETE");
|
||||
tester.getContext().addFilter(filterHolder, "/*", FilterMapping.DEFAULT);
|
||||
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
tester.getContext().addServlet(new ServletHolder(new ResourceServlet(latch)), "/*");
|
||||
|
||||
// Preflight request
|
||||
String request = "" +
|
||||
"OPTIONS / HTTP/1.1\r\n" +
|
||||
"Host: localhost\r\n" +
|
||||
CrossOriginFilter.ACCESS_CONTROL_REQUEST_METHOD_HEADER + ": DELETE\r\n" +
|
||||
CrossOriginFilter.ACCESS_CONTROL_REQUEST_HEADERS_HEADER + ": origin,x-custom,x-requested-with\r\n" +
|
||||
"Origin: http://localhost\r\n" +
|
||||
"\r\n";
|
||||
String response = tester.getResponses(request);
|
||||
Assert.assertTrue(response.contains("HTTP/1.1 200"));
|
||||
Assert.assertFalse(response.contains(CrossOriginFilter.ACCESS_CONTROL_ALLOW_ORIGIN_HEADER));
|
||||
Assert.assertFalse(response.contains(CrossOriginFilter.ACCESS_CONTROL_ALLOW_CREDENTIALS_HEADER));
|
||||
Assert.assertTrue(latch.await(1, TimeUnit.SECONDS));
|
||||
// The preflight request failed because header X-Custom is not allowed, actual request not issued
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCrossOriginFilterDisabledForWebSocketUpgrade() throws Exception
|
||||
{
|
||||
FilterHolder filterHolder = new FilterHolder(new CrossOriginFilter());
|
||||
tester.getContext().addFilter(filterHolder, "/*", FilterMapping.DEFAULT);
|
||||
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
tester.getContext().addServlet(new ServletHolder(new ResourceServlet(latch)), "/*");
|
||||
|
||||
String request = "" +
|
||||
"GET / HTTP/1.1\r\n" +
|
||||
"Host: localhost\r\n" +
|
||||
"Connection: Upgrade\r\n" +
|
||||
"Upgrade: WebSocket\r\n" +
|
||||
"Origin: http://localhost\r\n" +
|
||||
"\r\n";
|
||||
String response = tester.getResponses(request);
|
||||
Assert.assertTrue(response.contains("HTTP/1.1 200"));
|
||||
Assert.assertFalse(response.contains(CrossOriginFilter.ACCESS_CONTROL_ALLOW_ORIGIN_HEADER));
|
||||
Assert.assertFalse(response.contains(CrossOriginFilter.ACCESS_CONTROL_ALLOW_CREDENTIALS_HEADER));
|
||||
Assert.assertTrue(latch.await(1, TimeUnit.SECONDS));
|
||||
}
|
||||
|
||||
public static class ResourceServlet extends HttpServlet
|
||||
{
|
||||
private final CountDownLatch latch;
|
||||
|
||||
public ResourceServlet(CountDownLatch latch)
|
||||
{
|
||||
this.latch = latch;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
|
||||
{
|
||||
latch.countDown();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -20,6 +20,9 @@ import java.io.UnsupportedEncodingException;
|
|||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jetty.util.Utf8Appendable.NotUtf8Exception;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Handles coding of MIME "x-www-form-urlencoded".
|
||||
|
@ -42,7 +45,7 @@ import java.util.Map;
|
|||
*/
|
||||
public class UrlEncoded extends MultiMap
|
||||
{
|
||||
// private static final Logger LOG = Log.getLogger(UrlEncoded.class);
|
||||
private static final Logger LOG = Log.getLogger(UrlEncoded.class);
|
||||
|
||||
public static final String ENCODING = System.getProperty("org.eclipse.jetty.util.UrlEncoding.charset",StringUtil.__UTF8);
|
||||
|
||||
|
@ -267,50 +270,59 @@ public class UrlEncoded extends MultiMap
|
|||
{
|
||||
String key = null;
|
||||
String value = null;
|
||||
|
||||
|
||||
// TODO cache of parameter names ???
|
||||
int end=offset+length;
|
||||
for (int i=offset;i<end;i++)
|
||||
{
|
||||
byte b=raw[i];
|
||||
switch ((char)(0xff&b))
|
||||
try
|
||||
{
|
||||
case '&':
|
||||
value = buffer.length()==0?"":buffer.toString();
|
||||
buffer.reset();
|
||||
if (key != null)
|
||||
{
|
||||
map.add(key,value);
|
||||
}
|
||||
else if (value!=null&&value.length()>0)
|
||||
{
|
||||
map.add(value,"");
|
||||
}
|
||||
key = null;
|
||||
value=null;
|
||||
break;
|
||||
|
||||
case '=':
|
||||
if (key!=null)
|
||||
{
|
||||
switch ((char)(0xff&b))
|
||||
{
|
||||
case '&':
|
||||
value = buffer.length()==0?"":buffer.toString();
|
||||
buffer.reset();
|
||||
if (key != null)
|
||||
{
|
||||
map.add(key,value);
|
||||
}
|
||||
else if (value!=null&&value.length()>0)
|
||||
{
|
||||
map.add(value,"");
|
||||
}
|
||||
key = null;
|
||||
value=null;
|
||||
break;
|
||||
|
||||
case '=':
|
||||
if (key!=null)
|
||||
{
|
||||
buffer.append(b);
|
||||
break;
|
||||
}
|
||||
key = buffer.toString();
|
||||
buffer.reset();
|
||||
break;
|
||||
|
||||
case '+':
|
||||
buffer.append((byte)' ');
|
||||
break;
|
||||
|
||||
case '%':
|
||||
if (i+2<end)
|
||||
buffer.append((byte)((TypeUtil.convertHexDigit(raw[++i])<<4) + TypeUtil.convertHexDigit(raw[++i])));
|
||||
break;
|
||||
|
||||
default:
|
||||
buffer.append(b);
|
||||
break;
|
||||
}
|
||||
key = buffer.toString();
|
||||
buffer.reset();
|
||||
break;
|
||||
|
||||
case '+':
|
||||
buffer.append((byte)' ');
|
||||
break;
|
||||
|
||||
case '%':
|
||||
if (i+2<end)
|
||||
buffer.append((byte)((TypeUtil.convertHexDigit(raw[++i])<<4) + TypeUtil.convertHexDigit(raw[++i])));
|
||||
break;
|
||||
default:
|
||||
buffer.append(b);
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch(NotUtf8Exception e)
|
||||
{
|
||||
LOG.warn(e.toString());
|
||||
LOG.debug(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -159,6 +159,7 @@ public abstract class Utf8Appendable
|
|||
}
|
||||
else if (_state == UTF8_REJECT)
|
||||
{
|
||||
_codep=0;
|
||||
_state = UTF8_ACCEPT;
|
||||
_appendable.append(REPLACEMENT);
|
||||
throw new NotUtf8Exception();
|
||||
|
|
|
@ -80,12 +80,11 @@ public class Log
|
|||
__log.debug("Logging to {} via {}", __log, log_class.getName());
|
||||
}
|
||||
}
|
||||
catch(NoClassDefFoundError e)
|
||||
{
|
||||
initStandardLogging(e);
|
||||
}
|
||||
catch(Exception e)
|
||||
catch(Throwable e)
|
||||
{
|
||||
if (e instanceof ThreadDeath)
|
||||
throw (ThreadDeath)e;
|
||||
|
||||
initStandardLogging(e);
|
||||
}
|
||||
|
||||
|
|
|
@ -141,27 +141,44 @@ public class StdErrLog implements Logger
|
|||
}
|
||||
else
|
||||
{
|
||||
if ("ALL".equalsIgnoreCase(levelStr.trim()))
|
||||
int level = getLevelId(levelStr);
|
||||
if (level != (-1))
|
||||
{
|
||||
return LEVEL_ALL;
|
||||
}
|
||||
else if ("DEBUG".equalsIgnoreCase(levelStr.trim()))
|
||||
{
|
||||
return LEVEL_DEBUG;
|
||||
}
|
||||
else if ("INFO".equalsIgnoreCase(levelStr.trim()))
|
||||
{
|
||||
return LEVEL_INFO;
|
||||
}
|
||||
else if ("WARN".equalsIgnoreCase(levelStr.trim()))
|
||||
{
|
||||
return LEVEL_WARN;
|
||||
return level;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Default Logging Level
|
||||
return LEVEL_INFO;
|
||||
return getLevelId(props.getProperty("log.LEVEL", "INFO"));
|
||||
}
|
||||
|
||||
protected static int getLevelId(String levelName)
|
||||
{
|
||||
if (levelName == null)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
String levelStr = levelName.trim();
|
||||
if ("ALL".equalsIgnoreCase(levelStr))
|
||||
{
|
||||
return LEVEL_ALL;
|
||||
}
|
||||
else if ("DEBUG".equalsIgnoreCase(levelStr))
|
||||
{
|
||||
return LEVEL_DEBUG;
|
||||
}
|
||||
else if ("INFO".equalsIgnoreCase(levelStr))
|
||||
{
|
||||
return LEVEL_INFO;
|
||||
}
|
||||
else if ("WARN".equalsIgnoreCase(levelStr))
|
||||
{
|
||||
return LEVEL_WARN;
|
||||
}
|
||||
|
||||
System.err.println("Unknown StdErrLog level [" + levelStr + "], expecting only [ALL, DEBUG, INFO, WARN] as values.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -541,7 +558,7 @@ public class StdErrLog implements Logger
|
|||
StdErrLog sel = new StdErrLog(fullname);
|
||||
// Preserve configuration for new loggers configuration
|
||||
sel.setPrintLongNames(_printLongNames);
|
||||
sel.setLevel(_level);
|
||||
// Let Level come from configured Properties instead - sel.setLevel(_level);
|
||||
sel.setSource(_source);
|
||||
logger = __loggers.putIfAbsent(fullname,sel);
|
||||
if (logger == null)
|
||||
|
|
|
@ -78,6 +78,19 @@ public class StdErrLogTest
|
|||
Assert.assertEquals("Default Logging Level",StdErrLog.LEVEL_INFO,StdErrLog.getLoggingLevel(props,StdErrLogTest.class.getName()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetLoggingLevel_Root()
|
||||
{
|
||||
Properties props = new Properties();
|
||||
props.setProperty("log.LEVEL","DEBUG");
|
||||
|
||||
// Default Levels
|
||||
Assert.assertEquals("Default Logging Level",StdErrLog.LEVEL_DEBUG,StdErrLog.getLoggingLevel(props,null));
|
||||
Assert.assertEquals("Default Logging Level",StdErrLog.LEVEL_DEBUG,StdErrLog.getLoggingLevel(props,""));
|
||||
Assert.assertEquals("Default Logging Level",StdErrLog.LEVEL_DEBUG,StdErrLog.getLoggingLevel(props,"org.eclipse.jetty"));
|
||||
Assert.assertEquals("Default Logging Level",StdErrLog.LEVEL_DEBUG,StdErrLog.getLoggingLevel(props,StdErrLogTest.class.getName()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetLoggingLevel_FQCN()
|
||||
{
|
||||
|
@ -117,20 +130,21 @@ public class StdErrLogTest
|
|||
public void testGetLoggingLevel_MixedLevels()
|
||||
{
|
||||
Properties props = new Properties();
|
||||
props.setProperty("org.eclipse.jetty.util.LEVEL","DEBUG");
|
||||
props.setProperty("log.LEVEL","DEBUG");
|
||||
props.setProperty("org.eclipse.jetty.util.LEVEL","WARN");
|
||||
props.setProperty("org.eclipse.jetty.util.ConcurrentHashMap.LEVEL","ALL");
|
||||
|
||||
// Default Levels
|
||||
Assert.assertEquals(StdErrLog.LEVEL_INFO,StdErrLog.getLoggingLevel(props,null));
|
||||
Assert.assertEquals(StdErrLog.LEVEL_INFO,StdErrLog.getLoggingLevel(props,""));
|
||||
Assert.assertEquals(StdErrLog.LEVEL_INFO,StdErrLog.getLoggingLevel(props,"org.eclipse.jetty"));
|
||||
Assert.assertEquals(StdErrLog.LEVEL_INFO,StdErrLog.getLoggingLevel(props,"org.eclipse.jetty.server.ServerObject"));
|
||||
Assert.assertEquals(StdErrLog.LEVEL_DEBUG,StdErrLog.getLoggingLevel(props,null));
|
||||
Assert.assertEquals(StdErrLog.LEVEL_DEBUG,StdErrLog.getLoggingLevel(props,""));
|
||||
Assert.assertEquals(StdErrLog.LEVEL_DEBUG,StdErrLog.getLoggingLevel(props,"org.eclipse.jetty"));
|
||||
Assert.assertEquals(StdErrLog.LEVEL_DEBUG,StdErrLog.getLoggingLevel(props,"org.eclipse.jetty.server.ServerObject"));
|
||||
|
||||
// Configured Level
|
||||
Assert.assertEquals(StdErrLog.LEVEL_DEBUG,StdErrLog.getLoggingLevel(props,StdErrLogTest.class.getName()));
|
||||
Assert.assertEquals(StdErrLog.LEVEL_DEBUG,StdErrLog.getLoggingLevel(props,"org.eclipse.jetty.util.MagicUtil"));
|
||||
Assert.assertEquals(StdErrLog.LEVEL_DEBUG,StdErrLog.getLoggingLevel(props,"org.eclipse.jetty.util"));
|
||||
Assert.assertEquals(StdErrLog.LEVEL_DEBUG,StdErrLog.getLoggingLevel(props,"org.eclipse.jetty.util.resource.FileResource"));
|
||||
Assert.assertEquals(StdErrLog.LEVEL_WARN,StdErrLog.getLoggingLevel(props,StdErrLogTest.class.getName()));
|
||||
Assert.assertEquals(StdErrLog.LEVEL_WARN,StdErrLog.getLoggingLevel(props,"org.eclipse.jetty.util.MagicUtil"));
|
||||
Assert.assertEquals(StdErrLog.LEVEL_WARN,StdErrLog.getLoggingLevel(props,"org.eclipse.jetty.util"));
|
||||
Assert.assertEquals(StdErrLog.LEVEL_WARN,StdErrLog.getLoggingLevel(props,"org.eclipse.jetty.util.resource.FileResource"));
|
||||
Assert.assertEquals(StdErrLog.LEVEL_ALL,StdErrLog.getLoggingLevel(props,"org.eclipse.jetty.util.ConcurrentHashMap"));
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue